rn_ui_dropdown
Version:
`rn_ui_dropdown` is a customizable dropdown component for React Native that allows you to easily add a dropdown menu with options, selection handling, and dynamic rendering. It provides both single-select and multi-select modes
300 lines (299 loc) • 13.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = require("react");
const react_native_1 = require("react-native");
const RnUiDropdown = ({ options, selectedOption, bindingProp, displayProp, multiSelect, onSearchTextChange, onSelectionChange, containerStyle, selectedOptionStyle, selectedOptionTextStyle, optionsStyle, optionsTextStyle, searchBoxStyle, searchTextStyle, placeholderText, searchPlaceholderText, }) => {
const [modalVisible, setModalVisible] = (0, react_1.useState)(false);
const [selectedValue, setSelectedValue] = (0, react_1.useState)(selectedOption || []);
const [filteredDataList, setFilteredDataList] = (0, react_1.useState)([]);
const [layout, setLayout] = (0, react_1.useState)('vertical');
const [containerWidth, setContainerWidth] = (0, react_1.useState)(100);
const [heightAccordScreenLayout, setHeightAccordScreenLayout] = (0, react_1.useState)(100);
const limitText = (text, length) => {
if (text.length > length)
return text.substring(0, length) + '...';
return text;
};
const alreadySelected = (id) => {
return (selectedValue.filter(selectedId => selectedId == id).length > 0);
};
(0, react_1.useEffect)(() => {
if (multiSelect != true)
console.log('single select mode');
else
console.log('multi select mode on');
console.log(Array.isArray(selectedValue));
const { width, height } = react_native_1.Dimensions.get('screen');
if (width < height)
setLayout(prevState => 'vertical');
else
setLayout(prevState => 'horizontal');
setHeightAccordScreenLayout(prevState => react_native_1.Dimensions.get('screen').height);
}, []);
(0, react_1.useEffect)(() => {
if (multiSelect == true)
onSelectionChange(selectedValue || []);
else
onSelectionChange(selectedValue);
}, [selectedValue]);
(0, react_1.useEffect)(() => {
setSelectedValue(selectedOption);
if (multiSelect == true)
onSelectionChange(selectedOption || []);
else
onSelectionChange(selectedOption);
}, [selectedOption]);
(0, react_1.useEffect)(() => {
setFilteredDataList(options);
}, [options]);
(0, react_1.useEffect)(() => {
console.log('containerWidth >>', containerWidth);
}, [containerWidth]);
(0, react_1.useEffect)(() => {
console.log('heightAccordScreenLayout >>', heightAccordScreenLayout);
}, [heightAccordScreenLayout]);
return (<react_native_1.SafeAreaView>
<react_native_1.View style={{ ...styles.container, ...containerStyle }} onLayout={event => {
const { width, height } = react_native_1.Dimensions.get('screen');
if (width < height)
setLayout(prevState => 'vertical');
else
setLayout(prevState => 'horizontal');
setContainerWidth(event.nativeEvent.layout.width);
setHeightAccordScreenLayout(prevState => react_native_1.Dimensions.get('screen').height);
}}>
<react_native_1.View style={{
...styles.selectedItemContainer,
// backgroundColor: 'green',
width: containerWidth -
(multiSelect != true && selectedOption != null ? 96 : 48),
...selectedOptionStyle,
}}>
{multiSelect == true &&
selectedValue &&
selectedValue.length == 0 && (<react_native_1.Text style={{
...styles.placeholder,
...selectedOptionTextStyle,
}} numberOfLines={1}>
{options?.filter(option => option[bindingProp] == selectedValue)?.[0]?.[displayProp] ??
placeholderText ??
'Select'}
</react_native_1.Text>)}
{multiSelect == true &&
selectedValue &&
selectedValue.length > 0 &&
selectedValue.map((val, ind) => {
return (<react_native_1.View key={'selectedVal' + ind} style={{
display: 'flex',
flexDirection: 'row',
marginVertical: 6,
marginHorizontal: 4,
paddingLeft: 6,
backgroundColor: 'rgb(187, 222, 243)',
borderRadius: 4,
gap: 2,
maxWidth: containerWidth - 58,
}}>
<react_native_1.Text style={{
paddingVertical: 6,
maxWidth: containerWidth - 82,
letterSpacing: 1,
fontSize: 16,
fontWeight: 'semibold',
}} numberOfLines={1}>
{options.filter(option => option[bindingProp] == val)[0][displayProp]}
</react_native_1.Text>
<react_native_1.Pressable android_ripple={{ color: 'rgba(220, 220, 220, 1)' }} onPress={() => {
setSelectedValue(selectedValue.filter(id => id != val));
}}>
<react_native_1.Image style={{
width: 22,
height: 22,
// backgroundColor: 'yellow',
marginVertical: 'auto',
}} source={require('./close.png')}/>
</react_native_1.Pressable>
</react_native_1.View>);
})}
{multiSelect != true && (<react_native_1.Text style={{
...(selectedValue
? styles.selectedItemText
: styles.placeholder),
...selectedOptionTextStyle,
}} numberOfLines={1}>
{options?.filter(option => option[bindingProp] == selectedValue)?.[0]?.[displayProp] ??
placeholderText ??
'Select'}
</react_native_1.Text>)}
</react_native_1.View>
{selectedValue != null && multiSelect != true && (<react_native_1.Pressable android_ripple={{ color: 'rgba(220, 220, 220, 1)' }} style={{
minWidth: 48,
minHeight: 48,
height: '100%',
}} onPress={() => setSelectedValue(null)}>
<react_native_1.Image style={{ width: 24, height: 24, margin: 'auto' }} source={require('./close.png')}/>
</react_native_1.Pressable>)}
<react_native_1.Pressable android_ripple={{ color: 'rgba(220, 220, 220, 1)' }} style={{
width: 48,
minHeight: 48,
height: '100%',
}} onPress={() => {
setFilteredDataList(options);
setModalVisible(true);
}}>
<react_native_1.Image style={{ width: 24, height: 24, margin: 'auto' }} source={require('./caret.webp')}/>
</react_native_1.Pressable>
</react_native_1.View>
<react_native_1.Modal animationType={'fade'} transparent={true} visible={modalVisible} onRequestClose={() => {
setModalVisible(!modalVisible);
}}>
<react_native_1.Pressable style={styles.centeredView} onPress={() => setModalVisible(false)}>
<react_native_1.View style={{
...styles.modalView,
maxWidth: containerWidth - (layout == 'horizontal' ? 72 : 48),
maxHeight: heightAccordScreenLayout - (layout == 'horizontal' ? 100 : 180),
}}>
<react_native_1.View style={{
display: 'flex',
flexDirection: 'row',
borderColor: 'lightgray',
borderBottomWidth: 1,
...searchBoxStyle,
}}>
<react_native_1.TextInput style={{
flexGrow: 1,
padding: 12,
fontSize: 16,
borderTopLeftRadius: 4,
width: '80%',
...searchTextStyle,
}} placeholder={searchPlaceholderText ?? 'Search'} onChangeText={val => {
if (onSearchTextChange != null) {
onSearchTextChange(val);
}
else if (val == null || val == '') {
setFilteredDataList(options);
}
else {
let filteredData = options.filter((data) => data[displayProp]
.toLowerCase()
.indexOf(val.toLowerCase()) != -1);
setFilteredDataList(filteredData);
}
}}/>
<react_native_1.Pressable android_ripple={{ color: 'rgba(220, 220, 220, 1)' }} onPress={() => setModalVisible(false)}>
<react_native_1.Image style={{
width: 24,
height: 24,
margin: 'auto',
marginHorizontal: 4,
}} source={require('./close.png')}/>
</react_native_1.Pressable>
</react_native_1.View>
{multiSelect != true && (<react_native_1.FlatList style={{ minHeight: 100, maxHeight: 400 }} data={filteredDataList} keyExtractor={(item, index) => item[bindingProp].toString() + '-' + index} renderItem={({ item, index }) => (<react_native_1.Pressable android_ripple={{ color: 'lightgray' }} key={'singleSelectOption' + index} style={{ padding: 12, ...optionsStyle }} onPress={() => {
setSelectedValue(item[bindingProp]);
setModalVisible(false);
}}>
<react_native_1.Text style={{
fontSize: 16,
letterSpacing: 1,
...optionsTextStyle,
}} numberOfLines={1}>
{item[displayProp]}
</react_native_1.Text>
</react_native_1.Pressable>)}/>)}
{multiSelect == true && (<react_native_1.FlatList style={{ minHeight: 100, maxHeight: 500 }} data={filteredDataList} keyExtractor={(item, index) => item[bindingProp].toString() + '-' + index} renderItem={({ item, index }) => (<react_native_1.Pressable android_ripple={{ color: 'lightgray' }} style={{
padding: 12,
display: 'flex',
flexDirection: 'row',
gap: 16,
alignItems: 'center',
...optionsStyle,
}} onPress={() => {
if (alreadySelected(item[bindingProp])) {
setSelectedValue((values) => {
let newValues = values.filter(value => value != item[bindingProp]);
return newValues;
});
}
else {
setSelectedValue((values) => {
let newValues = [...values, item[bindingProp]];
newValues.sort((a, b) => a - b);
return newValues;
});
}
}}>
<react_native_1.View style={{}}>
<react_native_1.Image source={selectedValue?.filter(optionId => optionId == item[bindingProp]).length > 0
? require('./checkbox.png')
: ''} resizeMode={'center'} resizeMethod={'scale'} style={{
width: 18,
height: 18,
borderRadius: 2,
backgroundColor: selectedValue?.filter(optionId => optionId == item[bindingProp]).length > 0
? 'rgb(4, 154, 236)'
: 'lightgray',
borderWidth: 1,
borderColor: selectedValue?.filter(optionId => optionId == item[bindingProp]).length > 0
? 'rgb(4, 154, 236)'
: 'lightgray',
}}/>
</react_native_1.View>
<react_native_1.Text style={{
fontSize: 16,
letterSpacing: 1,
...optionsTextStyle,
}} numberOfLines={1}>
{item[displayProp]}
</react_native_1.Text>
</react_native_1.Pressable>)}/>)}
</react_native_1.View>
</react_native_1.Pressable>
</react_native_1.Modal>
</react_native_1.SafeAreaView>);
};
const styles = react_native_1.StyleSheet.create({
container: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-start',
width: '100%',
borderColor: 'gray',
borderWidth: 1,
},
selectedItemContainer: {
// flexGrow: 1,
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
gap: 4,
},
selectedItemText: {
width: '100%',
padding: 12,
letterSpacing: 1,
fontSize: 16,
fontWeight: 'semibold',
},
placeholder: {
padding: 12,
letterSpacing: 1,
fontSize: 16,
fontWeight: 'semibold',
color: 'gray',
},
centeredView: {
backgroundColor: 'rgba(120, 120, 120, 0.4)',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
modalView: {
position: 'relative',
backgroundColor: 'white',
boxShadow: '0.4 0.4 1 gray',
borderRadius: 4,
},
});
exports.default = RnUiDropdown;