UNPKG

@crave/farmblocks-input-select

Version:
293 lines (254 loc) • 9.46 kB
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import * as React from "react"; import ReactAutocomplete from "react-autocomplete"; import PropTypes from "prop-types"; import { compose } from "recompose"; import memoize from "memoize-one"; import groupBy from "lodash.groupby"; import xor from "lodash.xor"; import formInput, { formInputProps } from "@crave/farmblocks-hoc-input"; import { DropdownMenuWrapper, DropdownItemWrapper } from "@crave/farmblocks-dropdown"; import Tag from "@crave/farmblocks-tags"; import withImage, { refName } from "./components/withImage"; import Item from "./components/Item"; import EmptyCard from "./components/EmptyCard"; import DropdownWrapper from "./styledComponents/DropdownWrapper"; import InputWithTags from "./components/InputWithTags"; const EnhancedInput = compose(formInput, withImage)(InputWithTags); EnhancedInput.displayName = "EnhancedInput"; const getValues = ({ multi, value }) => { if (!multi) return value; if (Array.isArray(value)) return value; if (value === undefined) return []; return [value]; }; class Select extends React.Component { constructor(_props) { super(_props); _defineProperty(this, "componentDidUpdate", prevProps => { const { value } = this.props; if ((value || value === 0) && value !== prevProps.value && value !== this.state.selectedValue || prevProps.items !== this.props.items) { this.setState({ selectedValue: value, selectedLabel: this.getSelectedLabel(this.props) }); } }); _defineProperty(this, "onMenuVisibilityChange", isMenuOpen => { var _this$props$onMenuVis, _this$props; if (!this.props.disableSearch && isMenuOpen && this.input) { this.input.select(); } this.setState({ isMenuOpen }); (_this$props$onMenuVis = (_this$props = this.props).onMenuVisibilityChange) === null || _this$props$onMenuVis === void 0 ? void 0 : _this$props$onMenuVis.call(_this$props, isMenuOpen); }); _defineProperty(this, "onFilter", event => { if (!this.state.isSearching && !this.props.multi) { this.props.onChange(""); } this.setState({ selectedLabel: event.target.value, isSearching: true }); }); _defineProperty(this, "onSelect", (selectedLabel, item) => { const { onChange } = this.props; this.setState({ selectedLabel, isSearching: false }); if (this.props.multi) { onChange(xor(this.state.selectedValue, [item.value])); return; } onChange(item.value); }); _defineProperty(this, "onRemoveTag", value => this.onSelect("", { value })); _defineProperty(this, "onKeyDown", autoCompleteOnKeyDown => event => { const { value } = this.props; if (this.props.multi && event.key === "Backspace" && !this.state.selectedLabel) { var _value$slice; const lastTagValue = Array.isArray(value) && ((_value$slice = value.slice(-1)) === null || _value$slice === void 0 ? void 0 : _value$slice[0]); if (lastTagValue) this.onRemoveTag(lastTagValue); } autoCompleteOnKeyDown === null || autoCompleteOnKeyDown === void 0 ? void 0 : autoCompleteOnKeyDown(event); }); _defineProperty(this, "getSelectedLabel", props => { const item = (props.value || props.value === 0) && props.items.find(x => x.value === props.value); if (item) { return item.label; } }); _defineProperty(this, "normalizeItems", memoize(items => groupBy(items, "value"))); _defineProperty(this, "renderTags", () => { var _getValues; const items = this.normalizeItems(this.props.items); return (_getValues = getValues(this.props)) === null || _getValues === void 0 ? void 0 : _getValues.map(value => { var _items$value; const item = (_items$value = items[value]) === null || _items$value === void 0 ? void 0 : _items$value[0]; if (!item) return null; return /*#__PURE__*/React.createElement(Tag, { className: "tag", key: item.value, value: item.value, text: item.label, onRemove: this.onRemoveTag, disabled: this.props.disabled }); }); }); _defineProperty(this, "renderInput", autoCompleteProps => { var _getValues2; const { ref, ...rest } = autoCompleteProps; const { renderItem, disableSearch, items, zIndex, maxHeight, multi, placeholder, className = "", onMenuVisibilityChange, ...inputProps } = this.props; inputProps.validationMessages = this.state.isMenuOpen ? [] : this.props.validationMessages; const selectedItem = items.find(item => item.label === autoCompleteProps.value); const image = selectedItem && selectedItem.image; return /*#__PURE__*/React.createElement(EnhancedInput, _extends({ className: `select__search ${className}`, readOnly: disableSearch, placeholder: (_getValues2 = getValues(this.props)) !== null && _getValues2 !== void 0 && _getValues2.length ? "" : placeholder }, inputProps, rest, { innerRef: ref, refName: refName, image: image, onKeyDown: this.onKeyDown(rest.onKeyDown), mb: 0 }), multi && this.renderTags()); }); _defineProperty(this, "renderMenu", items => { const { noResultsMessage, maxHeight } = this.props; if (!(items !== null && items !== void 0 && items.length)) { return /*#__PURE__*/React.createElement(EmptyCard, { className: "emptyCard", noResultsMessage: noResultsMessage }); } return /*#__PURE__*/React.createElement(DropdownMenuWrapper, { className: "dropdownMenu", maxHeight: maxHeight }, /*#__PURE__*/React.createElement("ul", null, items)); }); _defineProperty(this, "renderItem", (item, highlighted) => { const { selectedValue } = this.state; const selected = Array.isArray(selectedValue) ? selectedValue.includes(item.value) : selectedValue === item.value; return /*#__PURE__*/React.createElement(DropdownItemWrapper, { className: "itemWrapper", key: item.value, highlighted: highlighted, selected: selected }, this.props.renderItem ? this.props.renderItem(item, selected) : /*#__PURE__*/React.createElement(Item, { className: "item", label: item.label, id: this.props.id && `${this.props.id}-item-${item.value}`, image: item.image, selected: selected, checkbox: this.props.multi })); }); _defineProperty(this, "shouldItemRender", item => { const { selectedLabel } = this.state; if (this.state.isSearching) { return item.label.toLowerCase().indexOf(selectedLabel && selectedLabel.toLowerCase()) > -1; } // If user is not searching, we render the full list of items return true; }); this.state = { selectedValue: getValues(_props), selectedLabel: this.getSelectedLabel(_props), isSearching: false, isMenuOpen: false }; } render() { const { width, zIndex, items, className } = this.props; return /*#__PURE__*/React.createElement(DropdownWrapper, { className: className, width: width, zIndex: zIndex }, /*#__PURE__*/React.createElement(ReactAutocomplete, { items: items, shouldItemRender: this.shouldItemRender, getItemValue: item => item.label, value: this.state.selectedLabel, onChange: this.onFilter, onSelect: this.onSelect, renderInput: this.renderInput, renderMenu: this.renderMenu, renderItem: this.renderItem, autoHighlight: false, onMenuVisibilityChange: this.onMenuVisibilityChange, wrapperStyle: {}, ref: ref => { this.input = ref; } })); } } Select.defaultProps = { onChange: () => false, width: "200px", items: [] }; Select.propTypes = { ...formInputProps, items: PropTypes.arrayOf(PropTypes.shape({ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), label: PropTypes.string, image: PropTypes.string })), value: (props, ...rest) => { const valueTypes = PropTypes.oneOfType([PropTypes.string, PropTypes.number]); return (props.multi ? PropTypes.arrayOf(valueTypes) : valueTypes)(props, ...rest); }, width: PropTypes.string, onChange: PropTypes.func, renderItem: PropTypes.func, noResultsMessage: PropTypes.string, disableSearch: PropTypes.bool, zIndex: PropTypes.number, maxHeight: PropTypes.string, multi: PropTypes.bool, className: PropTypes.string, onMenuVisibilityChange: PropTypes.func }; export default Select;