UNPKG

@eccenca/gui-elements

Version:

Collection of low-level GUI elements like Buttons, Icons or Alerts. Also includes core styles for those elements.

150 lines (134 loc) 4.63 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import _ from 'lodash'; import Highlighter from 'react-highlight-words'; import cx from 'classnames'; import SelectBox from '../SelectBox/SelectBox'; const Highlight = props => { const { textToHighlight, searchWord } = props; if (!_.isString(textToHighlight) || _.isEmpty(textToHighlight)) { return false; } if (!_.isString(searchWord) || _.isEmpty(searchWord)) { return <span>{textToHighlight}</span>; } return ( <Highlighter textToHighlight={textToHighlight} searchWords={[searchWord]} autoEscape={true} /> ); }; class AutoCompleteBox extends Component { static propTypes = { /** * pass Textfield user input to parent component (e.g. to update options) */ handleValueChange: PropTypes.func, // query which returns options /** * Insert a custom className to element */ className: PropTypes.string, /** * Allow to manipulate inserted user input string before using it */ inputRestriction: PropTypes.func, /** * Define if the label is shown in option's dropdown */ showLabel: PropTypes.bool, /** * Define if the value is shown in option's dropdown */ showValue: PropTypes.bool, /** * Define if the description is shown in option's dropdown */ showDescription: PropTypes.bool, // rest will be validated by `SelectBox` }; static defaultProps = { showLabel: true, showValue: true, showDescription: true, }; /** * @param props */ constructor(props) { super(props); this.displayName = 'AutoCompleteBox'; this.handleInputChange = this.handleInputChange.bind(this); this.currentInputValue = ''; } optionRender = option => { const { showLabel, showValue, showDescription } = this.props; const { label, value, description } = option; const escapedInput = this.currentInputValue.replace(/[?*|$]/g, '\\$0'); // only show value entry if it is not same as label and is allowed to show const optionValue = (value !== label) && showValue && ( <code key="autoCompleteValue" className="Select-option__value"> <Highlight textToHighlight={value} searchWord={escapedInput} /> </code> ); const optionDescription = description && showDescription && ( <span key="autoCompleteDescription" className="Select-option__description" > <Highlight textToHighlight={description} searchWord={escapedInput} /> </span> ); const optionLabel = label && showLabel && ( <strong key="autoCompleteLabel" className="Select-option__label"> <Highlight textToHighlight={label} searchWord={escapedInput} /> </strong> ); return [ optionLabel, optionValue, optionDescription, ]; }; // will only be triggered when the user type something in textfield handleInputChange(inputValue) { if (_.isFunction(this.props.inputRestriction)) { inputValue = this.props.inputRestriction(inputValue); } const inputValueCleaned = inputValue.replace(/\$/g, ''); // check if value really changed if (!_.isEqual(inputValueCleaned, this.currentInputValue)) { this.currentInputValue = _.clone(inputValueCleaned); // directly pass the current value to parent component (e.g. to update external options) if (_.isFunction(this.props.handleValueChange)) { this.props.handleValueChange(inputValueCleaned); } } return inputValueCleaned; } render() { const { showLabel, showValue, showDescription, ...props } = this.props; return ( <SelectBox {...props} className={cx(this.props.className, 'Select--AutoComplete')} onInputChange={this.handleInputChange} searchable optionRenderer={this.optionRender} /> ); } } export default AutoCompleteBox;