content: import React, { Component } from 'react';
  import {
    StyleSheet,
    Dimensions,
    Platform,
    View,
    TextInput,
    TouchableOpacity,
    Animated
  } from 'react-native';
  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 = Platform.OS === 'ios' ? -80 : -60;
  
  export default class Search extends Component {
    static propTypes = {
      data: PropTypes.array,
      placeholder: PropTypes.string,
      handleChangeText: PropTypes.func,
      handleSearch: PropTypes.func,
      handleResults: PropTypes.func,
      onSubmitEditing: PropTypes.func,
      onFocus: PropTypes.func,
      onBlur: PropTypes.func,
      onHide: 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,
      hideBack: 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 = {
      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,
      hideBack: 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 = {
        input: '',
        dimensions: Dimensions.get("window"),
        show: props.showOnLoad,
        top: new Animated.Value(
          props.showOnLoad ? 0 : INITIAL_TOP + props.heightAdjust
        )
      };
    }
  
    getValue = () => {
      return this.state.input;
    };
  
    setValue = (input) => {
      return this.setState({input})
    };
  
    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) });
      }
    };
  
    hide = () => {
      const { onHide, animate, animationDuration } = this.props;
      if (onHide) {
        onHide(this.state.input);
      }
      if (animate) {
        Animated.timing(this.state.top, {
          toValue: INITIAL_TOP,
          duration: animationDuration,
          useNativeDriver: true,
        }).start();
        const timerId = setTimeout(() => {
          this._doHide();
          clearTimeout(timerId);
        }, animationDuration);
      } else {
        this.setState({ top: new Animated.Value(INITIAL_TOP) });
        this._doHide();
      }
    };
  
    _doHide = () => {
      const { clearOnHide } = this.props;
      this.setState({ show: false });
      if (clearOnHide) {
        this.setState({ input: '' });
      }
    };
  
    _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('');
    };
  
    _onChangeText = input => {
      const { handleChangeText, handleSearch, handleResults } = this.props;
      this.setState({ input });
      if (handleChangeText) {
        handleChangeText(input);
      }
      if (handleSearch) {
        handleSearch(input);
      } else {
        debounce(() => {
          // use internal search logic (depth first)!
          if (handleResults) {
            const results = this._internalSearch(input);
            handleResults(results);
          }
        }, 500)();
      }
    };
  
    _internalSearch = input => {
      const { data, allDataOnEmptySearch } = this.props;
      if (input === '') {
        return allDataOnEmptySearch ? data : [];
      }
      return filter(data, item => {
        return this._depthFirstSearch(item, input);
      });
    };
  
    _depthFirstSearch = (collection, input) => {
      // let's get recursive boi
      let type = typeof collection;
      // base case(s)
      if (type === 'string' || type === 'number' || type === 'boolean') {
        return includes(
          collection.toString().toLowerCase(),
          input.toString().toLowerCase()
        );
      }
      return some(collection, item => this._depthFirstSearch(item, input));
    };
  
    _dimHandler = dims => this.setState({dimensions: dims.window});
  
    componentWillMount() {
      Dimensions.addEventListener("change", this._dimHandler);
    }
  
    componentWillUnmount() {
      Dimensions.removeEventListener("change", this._dimHandler);
    }
  
    render = () => {
      const {
        placeholder,
        heightAdjust,
        backgroundColor,
        iconColor,
        textColor,
        selectionColor,
        placeholderTextColor,
        onBack,
        hideBack,
        hideX,
        iOSPadding,
        iOSPaddingBackgroundColor,
        iOSHideShadow,
        onSubmitEditing,
        onFocus,
        focusOnLayout,
        autoCorrect,
        autoCapitalize,
        keyboardAppearance,
        fontFamily,
        backButton,
        backButtonAccessibilityLabel,
        closeButton,
        closeButtonAccessibilityLabel,
        backCloseSize,
        fontSize,
        editable
      } = this.props;
      return (
        <Animated.View
          style={[
            styles.container,
            {
              transform: [
                {
                  translateY: this.state.top
                }
              ],
              shadowOpacity: iOSHideShadow ? 0 : 0.7
            }
          ]}>
          {this.state.show && (
            <View style={[{ backgroundColor }, {width:this.state.dimensions.width}]}>
              {Platform.OS === 'ios' &&
                iOSPadding && <View style={{ height: 20, backgroundColor: iOSPaddingBackgroundColor }} />}
              <View
                style={[
                  styles.nav,
                  { height: (Platform.OS === 'ios' ? 52 : 62) + heightAdjust }
                ]}>
                {!hideBack && (
                  <TouchableOpacity
                    accessible={true}
                    accessibilityComponentType="button"
                    accessibilityLabel={backButtonAccessibilityLabel}
                    onPress={onBack || this.hide}>
                    {backButton ? (
                      <View
                        style={{ width: backCloseSize, height: backCloseSize }}>
                        {backButton}
                      </View>
                    ) : (
                      <Icon
                        name="arrow-back"
                        size={backCloseSize}
                        style={{
                          color: iconColor,
                          padding: heightAdjust / 2 + 10
                        }}
                      />
                    )}
                  </TouchableOpacity>
                )}
                <TextInput
                  ref={ref => (this.textInput = ref)}
                  onLayout={() => focusOnLayout && this.textInput.focus()}
                  style={[
                    styles.input,
                    {
                      width:this.state.dimensions.width-120,
                      fontSize: fontSize,
                      color: textColor,
                      fontFamily: fontFamily,
                      marginLeft: hideBack ? 30 : 0,
                      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>
      );
    };
  }
  
  const styles = StyleSheet.create({
    container: {
      flex: 1,
      zIndex: 10,
      position: 'absolute',
      elevation: 2,
      shadowRadius: 5
    },
    nav: {
      ...Platform.select({
        android: {
          borderBottomColor: 'lightgray',
          borderBottomWidth: StyleSheet.hairlineWidth
        }
      }),
      flex: 1,
      flexBasis: 1,
      flexDirection: 'row',
      justifyContent: 'space-around',
      alignItems: 'center'
    },
    input: {
      ...Platform.select({
        ios: { height: 30 },
        android: { height: 50 }
      }),
      width: Dimensions.get('window').width - 120
    }
  });
  