UNPKG

@devrue/rn-select

Version:

Custom typescript only select component for react native

258 lines (257 loc) 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = Select; var _react = _interopRequireWildcard(require("react")); var _SearchBox = _interopRequireDefault(require("./SearchBox")); var _reactNative = require("react-native"); var _useStyles = _interopRequireDefault(require("../hooks/useStyles")); var _SelectRow = _interopRequireDefault(require("./SelectRow")); var _BottomSpacer = _interopRequireDefault(require("./BottomSpacer")); var _Divider = _interopRequireDefault(require("./Divider")); var _Anchor = _interopRequireDefault(require("./Anchor")); var _pickBy = _interopRequireDefault(require("lodash/pickBy")); var _ListContainer = _interopRequireDefault(require("./ListContainer")); var _EmptyList = _interopRequireDefault(require("./EmptyList")); var _common = require("./common"); var _lodash = require("lodash"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } 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); } function extractStyleProps(obj, startPattern, endPattern) { return (0, _pickBy.default)(obj, (_, key) => key.startsWith(startPattern) && key.endsWith(endPattern)); } function Select({ options, value, onChangeInput, onCreateItem, placeholder, searchPlaceholder, searchPlaceholderTextColor, listTitle, showSelectionCount = true, reverse, selectionEffectColor, optionsScrollIndicator = true, emptyOptionsPlaceholder = 'No Options', emptySearchMsg, clearable = true, disabled, searchable = true, createable, avoidBottom, renderAnchor, renderSearch, renderOption, optionDivider, statsTextStyle, optionCheckColors, emptyTextStyle, ...rest }) { const [showlist, setShowlist] = (0, _react.useState)(false); const [search, setSearch] = (0, _react.useState)(''); const [anchorPosition, setAnchorPosition] = (0, _react.useState)({}); const [createdOptions, setCreatedOptions] = (0, _react.useState)([]); const [bottomSpacerHeight, setBottomSpacerHeight] = (0, _react.useState)(50); const styles = (0, _useStyles.default)(({ tokens: { size } }) => ({ row: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', columnGap: 8 }, optionsFlatlist: { flex: 1, paddingHorizontal: size.sm }, optionsFlatlistContent: { flexGrow: 1 }, statsRow: { paddingHorizontal: size.sm }, optionListContainer: _reactNative.Platform.select({ web: { minWidth: _common.MIN_WIDTH, ...((anchorPosition.width ?? 0) >= _common.MIN_WIDTH && { width: anchorPosition.width }) }, default: {} }) }), [anchorPosition]); const [selectedMap, selectedOptions] = (0, _react.useMemo)(() => { const optionsMap = new Map([...options, ...createdOptions]); const foundOptions = []; if (value) { if (Array.isArray(value)) { const foundValues = value.map(item => { return [item, optionsMap.get(item)]; }).filter(item => item[1]); foundOptions.push(...foundValues); } else { const item = optionsMap.get(value); if (item) foundOptions.push([value, item]); } } return [new Map(foundOptions), foundOptions]; }, [createdOptions, options, value]); const list = (0, _react.useMemo)(() => (0, _lodash.uniqBy)([...options, ...createdOptions], ([key]) => key).filter(([_, val]) => val.toLowerCase().includes(search.toLowerCase())), [createdOptions, options, search]); const handleSearch = (0, _react.useCallback)(text => { setSearch(text); onChangeInput === null || onChangeInput === void 0 || onChangeInput(text); }, [onChangeInput]); const handleDismiss = (0, _react.useCallback)(() => { handleSearch(''); setShowlist(false); }, [handleSearch]); const handleRowPress = (0, _react.useCallback)(key => { if ('multi' in rest) { if (selectedMap.has(key)) { var _rest$onChangeValue; selectedMap.delete(key); (_rest$onChangeValue = rest.onChangeValue) === null || _rest$onChangeValue === void 0 || _rest$onChangeValue.call(rest, [...selectedMap.keys()]); } else { var _rest$onChangeValue2; (_rest$onChangeValue2 = rest.onChangeValue) === null || _rest$onChangeValue2 === void 0 || _rest$onChangeValue2.call(rest, [...selectedMap.keys(), key]); } } else { var _rest$onChangeValue3, _rest$onChangeValue4; if (selectedMap.has(key)) (_rest$onChangeValue3 = rest.onChangeValue) === null || _rest$onChangeValue3 === void 0 || _rest$onChangeValue3.call(rest, '');else (_rest$onChangeValue4 = rest.onChangeValue) === null || _rest$onChangeValue4 === void 0 || _rest$onChangeValue4.call(rest, key); handleDismiss(); } }, [handleDismiss, rest, selectedMap]); const handleRemove = (0, _react.useCallback)(key => { var _rest$onChangeValue5; selectedMap.delete(key); if ('multi' in rest) (_rest$onChangeValue5 = rest.onChangeValue) === null || _rest$onChangeValue5 === void 0 || _rest$onChangeValue5.call(rest, [...selectedMap.keys()]); }, [rest, selectedMap]); const handleClear = (0, _react.useCallback)(() => { var _rest$onChangeValue6, _rest$onChangeValue7; if ('multi' in rest) (_rest$onChangeValue6 = rest.onChangeValue) === null || _rest$onChangeValue6 === void 0 || _rest$onChangeValue6.call(rest, []);else (_rest$onChangeValue7 = rest.onChangeValue) === null || _rest$onChangeValue7 === void 0 || _rest$onChangeValue7.call(rest, ''); }, [rest]); const handleLaunch = (0, _react.useCallback)(() => setShowlist(!showlist), [showlist]); const handleLayout = (0, _react.useCallback)(rect => { const { top, left, width } = rect; setAnchorPosition({ x: left ?? 0, y: top ?? 0, width }); }, []); const handleCreateItem = (0, _react.useCallback)(createValue => { onCreateItem === null || onCreateItem === void 0 || onCreateItem(createValue); setCreatedOptions(c => [...c, [createValue, createValue]]); handleRowPress(createValue); }, [handleRowPress, onCreateItem]); const anchorStyleProps = extractStyleProps(rest, 'select', 'Style'); const searchStyleProps = extractStyleProps(rest, 'search', 'Style'); const optionStyleProps = extractStyleProps(rest, 'option', 'Style'); const noOptions = options.length === 0 ? emptyOptionsPlaceholder : undefined; const multi = (0, _react.useMemo)(() => 'multi' in rest ? true : false, [rest]); const renderItem = (0, _react.useCallback)(({ item: [key, val] }) => /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, !renderOption && /*#__PURE__*/_react.default.createElement(_SelectRow.default, _extends({ value: val, onPress: () => handleRowPress(key), multi: multi, checked: selectedMap.has(key), reverse: reverse, selectionEffectColor: selectionEffectColor, optionCheckColors: optionCheckColors, role: "option", "aria-selected": selectedMap.has(key) }, optionStyleProps)), renderOption === null || renderOption === void 0 ? void 0 : renderOption({ optionKey: key, optionValue: val, isChecked: selectedMap.has(key), onPress: () => handleRowPress(key) })), [handleRowPress, multi, optionCheckColors, optionStyleProps, renderOption, reverse, selectedMap, selectionEffectColor]); const customAnchor = (0, _react.useMemo)(() => renderAnchor === null || renderAnchor === void 0 ? void 0 : renderAnchor({ launch: handleLaunch, remove: handleRemove, clear: handleClear, setRect: handleLayout }), [handleClear, handleLaunch, handleLayout, handleRemove, renderAnchor]); return /*#__PURE__*/_react.default.createElement(_reactNative.View, { role: "list" }, !renderAnchor && /*#__PURE__*/_react.default.createElement(_Anchor.default, _extends({ placeholder: placeholder, selected: selectedOptions ?? [], multi: multi, onPress: disabled ? null : handleLaunch, onRemove: handleRemove, onClear: handleClear, onLayout: handleLayout, disabled: disabled, clearable: clearable }, anchorStyleProps)), customAnchor, /*#__PURE__*/_react.default.createElement(_ListContainer.default, _extends({ visible: showlist, onRequestClose: handleDismiss, hardwareAccelerated: true, style: [styles.optionListContainer, optionStyleProps.optionListContainerStyle] }, _reactNative.Platform.select({ web: { animationType: 'fade', transparent: true, position: anchorPosition }, default: { animationType: 'slide' } }), { avoidBottom: avoidBottom, onOptionsOffet: setBottomSpacerHeight }), searchable && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, !renderSearch && /*#__PURE__*/_react.default.createElement(_SearchBox.default, _extends({ autoFocus: true, onBackPress: handleDismiss, placeholder: searchPlaceholder, value: search, onChangeText: handleSearch, role: "searchbox", placeholderTextColor: searchPlaceholderTextColor }, searchStyleProps)), renderSearch === null || renderSearch === void 0 ? void 0 : renderSearch({ search, dismiss: handleDismiss, onChangeSearch: handleSearch })), /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: [styles.statsRow, styles.row] }, listTitle && /*#__PURE__*/_react.default.createElement(_reactNative.Text, { style: statsTextStyle }, listTitle), /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: [styles.row] }), showSelectionCount && multi && /*#__PURE__*/_react.default.createElement(_reactNative.Text, { style: statsTextStyle }, "Selections: ", selectedMap.size)), /*#__PURE__*/_react.default.createElement(_reactNative.FlatList, { data: list, keyExtractor: ([key]) => key, renderItem: renderItem, showsVerticalScrollIndicator: optionsScrollIndicator, ItemSeparatorComponent: optionDivider ?? _Divider.default, keyboardShouldPersistTaps: "handled", ListFooterComponent: /*#__PURE__*/_react.default.createElement(_BottomSpacer.default, { height: bottomSpacerHeight }), ListEmptyComponent: /*#__PURE__*/_react.default.createElement(_EmptyList.default, { textStyle: emptyTextStyle, msg: noOptions ?? emptySearchMsg, createOption: typeof createable === 'function' ? createable(() => handleCreateItem(search)) : createable ? search : undefined, onCreate: handleCreateItem }), style: [styles.optionsFlatlist, optionStyleProps.optionListStyle], contentContainerStyle: styles.optionsFlatlistContent }))); } //# sourceMappingURL=Select.js.map