UNPKG

wix-style-react

Version:
161 lines (133 loc) 3.77 kB
import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import InputWithOptions from '../InputWithOptions'; import SearchIcon from 'wix-ui-icons-common/Search'; import WixComponent from '../BaseComponents/WixComponent'; import { StringUtils } from '../utils/StringUtils'; import styles from './Search.scss'; /** * Search component with suggestions based on input value listed in dropdown */ export default class Search extends WixComponent { static displayName = 'Search'; static propTypes = { ...InputWithOptions.propTypes, placeholder: PropTypes.string, expandable: PropTypes.bool, }; static defaultProps = { ...InputWithOptions.defaultProps, placeholder: 'Search', expandable: false, }; constructor(props) { super(props); const initialValue = (!this._isControlled && props.defaultValue) || ''; this.state = { inputValue: initialValue, collapsed: props.expandable && initialValue === '' && !props.autoFocus, }; } get _isControlled() { return 'value' in this.props && 'onChange' in this.props; } get _filteredOptions() { const { options, value } = this.props; const searchText = this._isControlled ? value : this.state.inputValue; return options.filter(option => searchText && searchText.length ? StringUtils.includesCaseInsensitive(option.value, searchText.trim()) : true, ); } _onChange = e => { if (this._isControlled) { this.props.onChange(e); } else { this.setState({ inputValue: e.target.value, }); } }; _onClear = () => { const { onClear } = this.props; if (!this.state.collapsed && this.props.expandable) { this.setState({ collapsed: true, }); } onClear && onClear(); }; _currentValue = () => { let value; if (this._isControlled) { value = this.props.value; } else { value = this.state.inputValue; } return value; }; _onBlur = () => { const { onBlur } = this.props; if (!this.state.collapsed && this.props.expandable) { const value = this._currentValue(); if (value === '') { this.setState({ collapsed: true, }); } } onBlur && onBlur(); }; _onWrapperClick = () => { if (this.props.expandable && this.state.collapsed) { this.searchInput.input.focus(); this.setState({ collapsed: false }); } }; _onWrapperMouseDown = e => { // We need to capture mouse down and prevent it's event if the input // is already open if (this.props.expandable && !this.state.collapsed) { const value = this._currentValue(); if (value === '') { e.preventDefault(); } } }; render() { const wrapperClasses = classNames({ [styles.expandableStyles]: this.props.expandable, [styles.collapsed]: this.state.collapsed && this.props.expandable, [styles.expanded]: !this.state.collapsed && this.props.expandable, }); return ( <div className={wrapperClasses} onClick={this._onWrapperClick} onMouseDown={this._onWrapperMouseDown} > <InputWithOptions {...this.props} ref={r => (this.searchInput = r)} roundInput prefix={ <div className={styles.leftIcon}> <SearchIcon /> </div> } menuArrow={false} clearButton closeOnSelect showOptionsIfEmptyInput={false} options={this._filteredOptions} onClear={this._onClear} onChange={this._onChange} onBlur={this._onBlur} highlight /> </div> ); } }