import React, { useState, useRef, useEffect } from 'react'; import { TextInput, Surface, Divider, HelperText, Searchbar, Provider as PaperProvider, useTheme, } from 'react-native-paper'; import { View, Dimensions, Platform, FlatList, ActivityIndicator, } from 'react-native'; import Modal from 'react-native-modal'; import Lo from 'lodash'; import Item from '../Components/Item'; import { defaultDropdownProps, ITEMLAYOUT } from '../constants'; import type { IDropdownData, IDropdownProps } from '../types'; import styles from '../styles'; import { deviceWidth, deviceHeight } from '../util'; import EmptyList from '../Components/EmptyList'; import PressableTouch from '../Components/PressableTouch'; const Dropdown: React.FC = props => { const { error, value, label, required, disabled, data, onChange, floating, enableSearch, primaryColor, elevation, borderRadius, activityIndicatorColor, searchPlaceholder, rippleColor = 'transparent', helperText, errorColor, itemTextStyle, itemContainerStyle, showLoader, animationIn = 'fadeIn', animationOut = 'fadeOut', supportedOrientations = ['portrait', 'landscape'], animationInTiming, animationOutTiming, parentDDContainerStyle, emptyListText, disableSort, enableAvatar, avatarSize, defaultSortOrder = 'asc', onBlur, paperTheme, textInputStyle, mainContainerStyle, underlineColor, disableSelectionTick, textInputPlaceholder, textInputPlaceholderColor, selectedItemTextStyle, selectedItemViewStyle, removeLabel, mode = 'flat', disabledItemTextStyle, disabledItemViewStyle, dropdownIcon = 'menu-down', dropdownIconSize = 30, itemSelectIcon, itemSelectIconSize, multiline = false, searchInputTheme, } = props; const { colors } = useTheme(); const [selected, setSelected] = useState(); const [labelv, setLabelV] = useState(''); const [isVisible, setIsVisible] = useState(false); const [iconColor, setIconColor] = useState('grey'); const [options, setOptions] = useState([]); const [hasError, setError] = useState(false); const [contMeasure, setConMeasure] = useState({ vx: 0, vy: 0, vWidth: 0, vHeight: 0, }); const [dimension, setDimension] = useState({ dw: deviceWidth, dh: deviceHeight, }); const [searchQuery, setSearchQuery] = useState(''); const pViewRef = useRef(); const listRef = useRef(); useEffect(() => { Dimensions.addEventListener('change', () => { setIsVisible(false); const { width, height } = Dimensions.get('window'); setDimension({ dw: width, dh: height }); setIconColor('grey'); }); return () => { Dimensions.removeEventListener('change', () => {}); }; }, []); useEffect(() => { if (!Lo.isEmpty(data) && value) { const lFilter = Lo.filter(data, { value: value })[0]; if (!Lo.isEmpty(lFilter)) setLabelV(lFilter.label); } }, [value, data]); useEffect(() => { if (disabled) { setIconColor('lightgrey'); } }, [disabled]); useEffect(() => { if (isVisible && listRef) { listRef.current.flashScrollIndicators(); } }, [isVisible]); useEffect(() => { if (!disableSort) setOptions(Lo.orderBy(data, ['label'], [defaultSortOrder])); else setOptions(data); }, [data, disableSort, defaultSortOrder]); useEffect(() => { if (isVisible && selected) { const selectedIndex = Lo.findIndex(options, { value: selected }); if (selectedIndex >= 0 && listRef) { setTimeout(() => { listRef.current.scrollToIndex({ animated: false, index: selectedIndex, viewPosition: Platform.OS === 'android' ? 0 : 0.5, }); }, 100); } } }, [selected, options, isVisible]); useEffect(() => { if (required && error) { setError(true); setIconColor(errorColor); } else { setError(false); setIconColor('grey'); } }, [required, error, errorColor]); const onTextInputFocus = () => { if (hasError) { setIconColor('red'); } else { setIconColor(primaryColor); } pViewRef.current.measureInWindow( (vx: number, vy: number, vWidth: number, vHeight: number) => { const ddTop = vy + vHeight; const bottomMetric = dimension.dh - vy; if (bottomMetric < 300) { setConMeasure({ vx, vy: ddTop - 217, vWidth, vHeight }); } else { setConMeasure({ vx, vy: ddTop, vWidth, vHeight }); } } ); setIsVisible(true); }; const androidOnLayout = () => { if (Platform.OS === 'android') { pViewRef.current.measureInWindow( (vx: number, vy: number, vWidth: number, vHeight: number) => { const ddTop = vy + vHeight; const bottomMetric = dimension.dh - vy; if (bottomMetric < 300) { setConMeasure({ vx, vy: ddTop - 217, vWidth, vHeight }); } else { setConMeasure({ vx, vy: ddTop, vWidth, vHeight }); } } ); } }; const onModalBlur = () => { setIsVisible(false); if (hasError) { setIconColor('red'); } else { setIconColor('grey'); } if (onBlur && typeof onBlur === 'function') onBlur(); }; const handleOptionSelect = (v: string | number) => { const lFilter = Lo.filter(data, { value: v })[0]; if (!Lo.isEmpty(lFilter)) setLabelV(lFilter.label); setSelected(v); if (onChange && typeof onChange === 'function') { onChange(v); setIsVisible(false); } if (hasError) { setIconColor('red'); } else { setIconColor('grey'); } setSearchQuery(''); if (!disableSort) setOptions(Lo.orderBy(data, ['label'], [defaultSortOrder])); else setOptions(data); }; const onChangeSearch = (query: string) => { setSearchQuery(query); if (!Lo.isEmpty(data) && query) { const lFilter = data.filter(opt => opt.label .toString() .toLowerCase() .trim() .includes(query.toString().toLowerCase()) ); if (lFilter.length === 0) { setOptions([]); } else { setOptions(lFilter); } } else if (!Lo.isEmpty(data) && !query && !disableSort) { setOptions(Lo.sortBy(data, 'label')); } else setOptions(data); }; const getEmptyComponent = () => { if (typeof emptyListText === 'string') return ; else return <>{emptyListText}; }; const labelAction = () => { if (removeLabel) { return ''; } else { return required ? `${label}*` : label; } }; return ( } mode={mode} /> {required && hasError ? ( {helperText ? helperText : `${label} is required`} ) : null} {showLoader ? ( ) : null} ) : null } stickyHeaderIndices={enableSearch ? [0] : undefined} renderItem={({ item }) => ( )} keyExtractor={() => Math.random().toString()} ItemSeparatorComponent={() => ( )} getItemLayout={(_d, index) => ({ length: ITEMLAYOUT, offset: ITEMLAYOUT * index, index, })} ListEmptyComponent={getEmptyComponent()} /> ); }; Dropdown.defaultProps = defaultDropdownProps; export default Dropdown;