wix-style-react
Version:
wix-style-react
200 lines • 8.89 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import InputWithOptions from '../InputWithOptions';
import { Search as SearchIcon } from '@wix/wix-ui-icons-common';
import Input from '../Input';
import Box from '../Box';
import Loader from '../Loader';
import Text from '../Text';
import { dataHooks } from './constants';
/** AddressInput */
class AddressInput extends React.PureComponent {
constructor(props) {
super(props);
this.innerRef = React.createRef();
this._onChange = event => {
const { onChange } = this.props;
this.setState({
inputValue: event.target.value,
});
if (onChange) {
onChange(event);
}
};
this._onSelect = option => {
const { onSelect } = this.props;
this.setState({
inputValue: option.label,
});
onSelect && onSelect(option);
};
this._onClear = () => {
const { onClear } = this.props;
this.setState({
inputValue: '',
}, () => {
onClear && onClear();
});
};
this._getInputValue = () => {
const { value: controlledValue } = this.props;
const { inputValue } = this.state;
const value = controlledValue !== undefined ? controlledValue : inputValue;
return value;
};
this._getIsLoading = () => {
const { status } = this.props;
return status === 'loading';
};
this._getStatus = () => {
const { status } = this.props;
const { isDropdownOpen } = this.state;
const isLoading = this._getIsLoading();
/** If addresses are loading and dropdown is open,
* displays loader in dropdown instead of in input.
*/
if (isLoading && isDropdownOpen) {
return undefined;
}
return status;
};
this._setDropdownOpen = () => this.setState({ isDropdownOpen: true });
this._setDropdownClosed = () => this.setState({ isDropdownOpen: false });
this._renderLoadingOption = () => {
return {
id: '',
disabled: true,
value: () => (React.createElement(Box, { flex: 1, align: "center", padding: "3px" },
React.createElement(Loader, { size: "tiny", dataHook: dataHooks.loader }))),
};
};
this._renderNoResultsOption = () => {
const { noResultsText } = this.props;
const isString = typeof noResultsText === 'string';
const value = isString ? (React.createElement(Text, { light: true, secondary: true, dataHook: dataHooks.noResultsText }, noResultsText)) : (noResultsText);
return {
id: '',
disabled: true,
overrideOptionStyle: !isString,
value,
};
};
this._renderOptions = () => {
const { options, noResultsText } = this.props;
const value = this._getInputValue();
const isLoading = this._getIsLoading();
const noResultsFound = !options || options.length === 0;
if (isLoading) {
return [this._renderLoadingOption()];
}
/** show `noResultsText` option
* if the input is not empty and there are no results */
if (value && noResultsFound && noResultsText) {
return [this._renderNoResultsOption()];
}
return options;
};
this.state = {
inputValue: props.initialValue || '',
isDropdownOpen: false,
};
}
render() {
const { dataHook, className, size, clearButton, placeholder, disabled, onFocus, onBlur, autoSelect, statusMessage, border, onManuallyInput, popoverProps, } = this.props;
const value = this._getInputValue();
const status = this._getStatus();
return (React.createElement(InputWithOptions, { dataHook: dataHook, className: className, clearButton: clearButton, onChange: this._onChange, size: size, options: this._renderOptions(), onSelect: this._onSelect, onManuallyInput: onManuallyInput, popoverProps: popoverProps, value: value, disabled: disabled, border: border,
/** <Input /> always shows clear button when `onClear` prop is passed,
so we only pass handler when clearButton is `true` */
onClear: clearButton ? this._onClear : undefined, onFocus: onFocus, onBlur: onBlur, autoSelect: autoSelect, status: status, statusMessage: statusMessage, menuArrow: false, highlight: true, prefix: React.createElement(Input.IconAffix, null,
React.createElement(SearchIcon, null)), placeholder: placeholder, onOptionsShow: this._setDropdownOpen, onOptionsHide: this._setDropdownClosed,
// disable browser autofill (including in chrome)
autocomplete: "off,chrome-off", ref: this.innerRef }));
}
/**
* Sets focus on the input element
* @param {FocusOptions} options
*/
focus() {
this.innerRef.current && this.innerRef.current.focus();
}
}
AddressInput.displayName = 'AddressInput';
AddressInput.propTypes = {
/** Applies a data-hook HTML attribute that can be used in the tests */
dataHook: PropTypes.string,
/** Specifies a CSS class name to be appended to the component’s root element */
className: PropTypes.string,
/** Displays a clear button (X) on a non-empty input */
clearButton: PropTypes.bool,
/** Sets the initial input value */
initialValue: PropTypes.string,
/** Sets a value to display (controlled mode). */
value: PropTypes.string,
/** Specifies whether input is disabled */
disabled: PropTypes.bool,
/** Fetch predictions debounce in milliseconds */
debounceDuration: PropTypes.number,
/** Defines a callback function which is called whenever a user selects a different option in the list */
onSelect: PropTypes.func,
/** Defines a callback function which is called every time input value is changed */
onChange: PropTypes.func,
/** Specify an array of options to render. When the option is an {optionProps}, the <AddressInput.Option/> component will be rendered on behalf of the user. */
options: PropTypes.array,
/** Defines a handler for getting notified upon a clear event. When passed, it displays a clear button in the input. */
onClear: PropTypes.func,
/** Defines a standard input onFocus callback */
onFocus: PropTypes.func,
/** Defines a standard input onBlur callback */
onBlur: PropTypes.func,
/** Specifies whether input is auto selected on focus */
autoSelect: PropTypes.bool,
/** Defines a callback function which is called when user performs a submit action.
* Submit-Action triggers are: "Enter", "Tab" */
onManuallyInput: PropTypes.func,
/** Specify the status of a field. Mostly used for “loading” indication upon async request calls. */
status: PropTypes.oneOf(['loading', 'error', 'warning']),
/** Defines the message to display on status icon hover. If not given or empty there will be no tooltip. */
statusMessage: PropTypes.node,
/** Control the border style of an input */
border: PropTypes.oneOf(['standard', 'round', 'bottomLine', 'none']),
/** Controls the size of the input. Default value: `medium` */
size: PropTypes.oneOf(['small', 'medium', 'large']),
/** Sets a placeholder message to display */
placeholder: PropTypes.string,
/** Sets the message to show in a dropdown when no results are found */
noResultsText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
/** Allows to pass common popover props */
popoverProps: PropTypes.shape({
appendTo: PropTypes.oneOf(['window', 'scrollParent', 'parent', 'viewport']),
maxWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
minWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
flip: PropTypes.bool,
fixed: PropTypes.bool,
placement: PropTypes.oneOf([
'auto-start',
'auto',
'auto-end',
'top-start',
'top',
'top-end',
'right-start',
'right',
'right-end',
'bottom-end',
'bottom',
'bottom-start',
'left-end',
'left',
'left-start',
]),
dynamicWidth: PropTypes.bool,
}),
};
AddressInput.defaultProps = {
clearButton: true,
debounceDuration: 200,
border: 'round',
};
export default AddressInput;
//# sourceMappingURL=AddressInput.js.map