UNPKG

rn-searchbox

Version:
301 lines (279 loc) 8.55 kB
/* * @Author: kerim selmi * @Date: 2018-06-13 22:56:02 * @Last Modified by: kerim selmi * @Last Modified time: 2018-06-15 16:49:38 */ import React, { Component } from 'react' import { Platform, View, TextInput, TouchableOpacity, Animated, ScrollView } from 'react-native' import Box from './box' import styles from './styles' import StringMatching from './stringMatching' import PropTypes from 'prop-types' import Icon from 'react-native-vector-icons/MaterialIcons' import { filter, some, includes } from 'lodash/collection' import { debounce } from 'lodash/function' const INITIAL_TOP = -60 export default class Search extends Component { static propTypes = { onClick: PropTypes.func, data: PropTypes.array.isRequired, itemsStyles: PropTypes.object, placeholder: PropTypes.string, handleChangeText: PropTypes.func, handleSearch: PropTypes.func, handleResults: PropTypes.func, onSubmitEditing: PropTypes.func, onFocus: PropTypes.func, onBlur: PropTypes.func, onBack: PropTypes.func, onX: PropTypes.func, backButton: PropTypes.object, backButtonAccessibilityLabel: PropTypes.string, closeButton: PropTypes.object, closeButtonAccessibilityLabel: PropTypes.string, backCloseSize: PropTypes.number, fontSize: PropTypes.number, heightAdjust: PropTypes.number, backgroundColor: PropTypes.string, iconColor: PropTypes.string, textColor: PropTypes.string, selectionColor: PropTypes.string, placeholderTextColor: PropTypes.string, animate: PropTypes.bool, animationDuration: PropTypes.number, showOnLoad: PropTypes.bool, hideX: PropTypes.bool, iOSPadding: PropTypes.bool, iOSPaddingBackgroundColor: PropTypes.string, iOSHideShadow: PropTypes.bool, clearOnShow: PropTypes.bool, clearOnHide: PropTypes.bool, clearOnBlur: PropTypes.bool, focusOnLayout: PropTypes.bool, autoCorrect: PropTypes.bool, autoCapitalize: PropTypes.string, keyboardAppearance: PropTypes.string, fontFamily: PropTypes.string, allDataOnEmptySearch: PropTypes.bool, editable: PropTypes.bool } static defaultProps = { onClick: () => { }, data: [], placeholder: 'Search', backButtonAccessibilityLabel: 'Navigate up', closeButtonAccessibilityLabel: 'Clear search text', heightAdjust: 0, backgroundColor: 'white', iconColor: 'gray', textColor: 'gray', selectionColor: 'lightskyblue', placeholderTextColor: 'lightgray', animate: true, animationDuration: 200, showOnLoad: false, hideX: false, iOSPadding: true, iOSPaddingBackgroundColor: 'transparent', iOSHideShadow: false, clearOnShow: false, clearOnHide: true, clearOnBlur: false, focusOnLayout: true, autoCorrect: true, autoCapitalize: 'sentences', keyboardAppearance: 'default', fontFamily: 'System', allDataOnEmptySearch: false, backCloseSize: 28, fontSize: 20, editable: true } constructor(props) { super(props) this.state = { dataToBox: props.data, input: '', show: props.showOnLoad, top: new Animated.Value( props.showOnLoad ? 0 : INITIAL_TOP + props.heightAdjust ) } } show = () => { const { animate, animationDuration, clearOnShow } = this.props if (clearOnShow) { this.setState({ input: '' }) } this.setState({ show: true }) if (animate) { Animated.timing(this.state.top, { toValue: 0, duration: animationDuration, useNativeDriver: true, }).start() } else { this.setState({ top: new Animated.Value(0) }) } } _handleX = () => { const { onX } = this.props this._clearInput() if (onX) onX() } _handleBlur = () => { const { onBlur, clearOnBlur } = this.props if (onBlur) { onBlur() } if (clearOnBlur) { this._clearInput() } } _clearInput = () => { this.setState({ input: '' }) this._onChangeText('') } /** we would filter the JSON array according to given value pass as argument. * After filtering data we would set the newly data in dataSource state. */ _onChangeText = input => { //TODO add string matching algorithm const { data } = this.props const newData = data.filter(function (item) { return StringMatching.diceSearch(input, item) }) this.setState({ input: input, dataToBox: newData }) } itemResponse(item) { this.props.onClick(item) } render = () => { const { itemsStyles, placeholder, heightAdjust, backgroundColor, iconColor, textColor, selectionColor, placeholderTextColor, onBack, hideX, iOSPadding, iOSPaddingBackgroundColor, iOSHideShadow, onSubmitEditing, onFocus, focusOnLayout, autoCorrect, autoCapitalize, keyboardAppearance, fontFamily, backButton, backButtonAccessibilityLabel, closeButton, closeButtonAccessibilityLabel, backCloseSize, fontSize, editable } = this.props return ( <View> <Animated.View style={[ styles.container, { transform: [ { translateY: this.state.top } ], shadowOpacity: iOSHideShadow ? 0 : 0.7 } ]}> {this.state.show && ( <View style={[styles.navWrapper, { backgroundColor }]}> {Platform.OS === 'ios' && iOSPadding && <View style={{ height: 20, backgroundColor: iOSPaddingBackgroundColor }} />} <View style={[ styles.nav, { height: (Platform.OS === 'ios' ? 52 : 62) + heightAdjust } ]}> <TextInput ref={ref => (this.textInput = ref)} onLayout={() => focusOnLayout && this.textInput.focus()} style={[ styles.input, { fontSize: fontSize, color: textColor, fontFamily: fontFamily, marginLeft: 10, marginTop: Platform.OS === 'ios' ? heightAdjust / 2 + 10 : 0 } ]} selectionColor={selectionColor} onChangeText={input => this._onChangeText(input)} onSubmitEditing={() => onSubmitEditing ? onSubmitEditing() : null} onFocus={() => (onFocus ? onFocus() : null)} onBlur={this._handleBlur} placeholder={placeholder} placeholderTextColor={placeholderTextColor} value={this.state.input} underlineColorAndroid="transparent" returnKeyType="search" autoCorrect={autoCorrect} autoCapitalize={autoCapitalize} keyboardAppearance={keyboardAppearance} editable={editable} /> <TouchableOpacity accessible={true} accessibilityComponentType="button" accessibilityLabel={closeButtonAccessibilityLabel} onPress={ hideX || this.state.input === '' ? null : this._handleX }> {closeButton ? ( <View style={{ width: backCloseSize, height: backCloseSize }}> {closeButton} </View> ) : ( <Icon name={'close'} size={backCloseSize} style={{ color: hideX || this.state.input == '' ? backgroundColor : iconColor, padding: heightAdjust / 2 + 10 }} /> )} </TouchableOpacity> </View> </View> )} </Animated.View> <View style={{ marginTop: 50 }}> <Box data={this.state.dataToBox} itemsStyles={itemsStyles} getItem={(item) => this.itemResponse(item)} /> </View> </View> ) } }