@devrue/rn-select
Version:
Custom typescript only select component for react native
258 lines (257 loc) • 11.8 kB
JavaScript
"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