UNPKG

wix-style-react

Version:
197 lines (181 loc) • 6.46 kB
import React from 'react'; import PropTypes from 'prop-types'; import StatusAlertSmall from 'wix-ui-icons-common/StatusAlertSmall'; import Input from '../Input'; import LabelledElement from '../LabelledElement'; import Text from '../Text'; import InputWithOptions from '../InputWithOptions'; import { classes } from './AutoCompleteWithLabel.st.css'; import dataHooks from './dataHooks'; import { optionValidator } from '../DropdownLayout/DropdownLayout'; class AutoCompleteWithLabel extends React.PureComponent { constructor(props) { super(props); this.state = { value: props.value || '', isEditing: false, }; } static displayName = 'AutoCompleteWithLabel'; static propTypes = { /** Sets a default value for those who want to use this component un-controlled. */ dataHook: PropTypes.string, /** Defines a value label to show inside of a field. */ label: PropTypes.string.isRequired, /** Specify an array of options to display in the dropdown list. */ options: PropTypes.arrayOf(optionValidator).isRequired, /** Pass a component you want to show as the suffix of the input, e.g., text string, icon. */ suffix: PropTypes.arrayOf(PropTypes.element), /** Specify the status of a field. */ status: PropTypes.oneOf(['error']), /** Defines the message to display on status icon hover. If not given or empty there will be no tooltip. */ statusMessage: PropTypes.node, /** Defines a standard input onFocus callback. */ onFocus: PropTypes.func, /** Defines a standard input onBlur callback */ onBlur: PropTypes.func, /** Defines a standard input onChange callback. */ onChange: PropTypes.func, /** Reference element data when a form is submitted. */ name: PropTypes.string, /** Specifies the type of `<input/>` element to display. Default is text string. */ type: PropTypes.string, /** Define a string that labels the current element in case where a text label is not visible on the screen. */ ariaLabel: PropTypes.string, /** Focus the element on mount (standard React input autoFocus). */ autoFocus: PropTypes.bool, /** Sets the value of native autocomplete attribute (check the [HTML spec](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete) for possible values */ autocomplete: PropTypes.string, /** Specifies whether input should be disabled or not. */ disabled: PropTypes.bool, /** Specifies a CSS class name to be appended to the component’s root element. */ className: PropTypes.string, /** Sets the maximum number of characters that can be entered into a field. */ maxLength: PropTypes.number, /** Sets a placeholder message to display. */ placeholder: PropTypes.string, /** Defines a callback function which is called whenever user selects a different option in the list. */ onSelect: PropTypes.func, /** Indicates whether to render using the native select element */ native: PropTypes.bool, /** Value of rendered child input */ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets the maximum height of the dropdownLayout in pixels. */ maxHeightPixels: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), }; static defaultProps = { ...Input.defaultProps, label: '', options: [], onSelect: () => {}, }; onSelect = option => { const { value } = option; this.setState({ value, }); this.props.onSelect(option); this.setState({ isEditing: false }); }; onChange = event => { const { value } = event.target; this.setState({ value, isEditing: true }); this.props.onChange && this.props.onChange(event); }; _isInputControlled = () => typeof this.props.value !== 'undefined'; render() { const { label, dataHook, options, status, suffix, statusMessage, onFocus, name, type, ariaLabel, autoFocus, autocomplete, disabled, className, maxLength, placeholder, native, onBlur, maxHeightPixels, } = this.props; const { value } = this._isInputControlled() ? this.props : this.state; const predicate = this.state.isEditing ? option => option.value.toLowerCase().includes(value.toLowerCase()) : () => true; const filteredOptions = options.filter(predicate); const suffixContainer = suffix ? suffix.map((item, index) => { return ( <div className={classes.suffix} key={`${dataHook}-${index}`}> {item} </div> ); }) : []; return ( <div data-hook={dataHook}> <LabelledElement label={label} dataHook={dataHooks.labelledElement} value={value} > <InputWithOptions onChange={this.onChange} onSelect={this.onSelect} dataHook={dataHooks.inputWithOptions} hideStatusSuffix onFocus={onFocus} onBlur={onBlur} size={'large'} inputElement={ <Input name={name} type={type} ariaLabel={ariaLabel} autoFocus={autoFocus} autocomplete={autocomplete} disabled={disabled} maxLength={maxLength} placeholder={placeholder} dataHook={dataHooks.inputWithLabel} value={value} className={className} suffix={suffixContainer} status={status} /> } options={filteredOptions} native={native} maxHeightPixels={maxHeightPixels} /> </LabelledElement> {status === Input.StatusError && statusMessage && ( <Text skin="error" weight="normal" size="small" className={classes.statusMessage} > <span className={classes.statusMessageIcon}> <StatusAlertSmall /> </span> <span data-hook={dataHooks.errorMessage} className={classes.errorMessageContent} > {statusMessage} </span> </Text> )} </div> ); } } export default AutoCompleteWithLabel;