UNPKG

@massds/mayflower-react

Version:

React versions of Mayflower design system UI components

305 lines 12.2 kB
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } function _inheritsLoose(t, o) { t.prototype = Object.create(o.prototype), t.prototype.constructor = t, _setPrototypeOf(t, o); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /** * InputTextFuzzy module. * @module @massds/mayflower-react/InputTextFuzzy * @requires module:@massds/mayflower-assets/scss/01-atoms/input-typeahead * @requires module:@massds/mayflower-assets/scss/01-atoms/input-fuzzy * @requires module:@massds/mayflower-assets/scss/01-atoms/helper-text */ import React from "react"; import Autosuggest from "react-autosuggest"; import PropTypes from "prop-types"; import Fuse from "fuse.js"; import parse from "autosuggest-highlight/parse"; import classNames from "classnames"; import is from "is"; import Label from "../Label"; let InputTextFuzzy = /*#__PURE__*/function (_React$Component) { function InputTextFuzzy(props) { var _this; _this = _React$Component.call(this, props) || this; _defineProperty(_this, "onSuggestionsFetchRequested", _ref => { let value = _ref.value; const suggestions = is.empty(value) ? _this.optionsToSuggestions(_this.props.options) : _this.fuse.search(value); _this.setState({ suggestions: suggestions }); }); _defineProperty(_this, "onSuggestionsClearRequested", () => { _this.setState({ suggestions: [] }); }); _defineProperty(_this, "onSuggestionSelected", (event, _ref2) => { let suggestion = _ref2.suggestion, method = _ref2.method; // invokes custom function if passed in the component if (is.fn(_this.props.onSuggestionClick)) { event.persist(); // Suggestion is an object that can contain info on score, matches, etc. _this.props.onSuggestionClick(event, { suggestion: suggestion, method: method, suggestions: _this.state.suggestions }); } }); _defineProperty(_this, "getSuggestionValue", suggestion => suggestion.item.text); _defineProperty(_this, "handleChange", (event, _ref3) => { let newValue = _ref3.newValue, method = _ref3.method; if (event && event.persist) { event.persist(); } const value = newValue; _this.setState({ value: value }, () => { if (is.fn(_this.props.onChange)) { _this.props.onChange({ event: event, method: method, value: value, suggestions: _this.state.suggestions }); } }); }); _defineProperty(_this, "handleBlur", event => { if (is.fn(_this.props.onBlur)) { if (event && event.persist()) { event.persist(); } _this.props.onBlur({ event: event, value: _this.state.value, suggestions: _this.state.suggestions }); } }); // handleChange and onSuggestionSelected both do not fire when enter is hit. // This is a workaround for that. Use handleChange for keyboard presses. _defineProperty(_this, "handleKeyPress", event => { const _this$state = _this.state, value = _this$state.value, suggestions = _this$state.suggestions; if (is.fn(_this.props.onKeyDown)) { _this.props.onKeyDown(event); } const match = suggestions.find(el => el.item.text === value); if (event.key === 'Enter') { event.persist(); event.preventDefault(); if (is.fn(_this.props.onSuggestionClick) && match) { _this.props.onSuggestionClick(event, { method: 'enter', suggestion: { item: { text: value } } }); } } }); _defineProperty(_this, "handleFocus", event => { if (is.fn(_this.props.onFocus)) { event.persist(); _this.props.onFocus(event, { event: event, value: _this.state.value, suggestions: _this.state.suggestions }); } }); _defineProperty(_this, "optionsToSuggestions", options => { const suggestions = options.map(item => ({ item: { text: item.text, value: item.value }, matches: [{ indices: [], value: item.text, key: 'text', arrayIndex: 0 }] })); return suggestions; }); _defineProperty(_this, "shouldRenderSuggestions", value => _this.props.renderDefaultSuggestion === true ? value.trim().length >= 0 : value.trim().length > 0); _defineProperty(_this, "renderItem", suggestion => { const item = suggestion.item, matches = suggestion.matches; let renderItems = []; if (is.empty(_this.state.value)) { renderItems = _this.props.keys.map(key => /*#__PURE__*/React.createElement("span", { key: key + ".suggestion_" + item.optionIndex }, item[key])); } else { matches.forEach(match => { if (_this.props.keys.indexOf(match.key) > -1) { // Add one to each range to get a proper highlight match. const ranges = match.indices.map(range => { const start = range[0], end = range[1]; return [start, Number(end) + 1]; }); const parts = parse(match.value, ranges); renderItems = parts.filter(part => part.text.length > 0).map((part, index) => { const className = part.highlight === true ? 'highlight' : null; const key = match.key + ".suggestion_" + index; return /*#__PURE__*/React.createElement("span", { className: className, key: key }, part.text); }); } }); } return /*#__PURE__*/React.createElement("span", { className: "ma__suggestion-content" }, /*#__PURE__*/React.createElement("span", { className: "ma__suggestion-content-name" }, renderItems)); }); _defineProperty(_this, "renderItemsContainer", _ref4 => { let children = _ref4.children, containerProps = _ref4.containerProps; return /*#__PURE__*/React.createElement("div", _extends({ className: "ma__input-fuzzy" }, containerProps), children); }); _this.state = { value: _this.props.selected || '', suggestions: [] }; const fuseOptions = _this.props.fuseOptions; fuseOptions.keys = _this.props.keys; _this.fuse = new Fuse(_this.props.options, fuseOptions); return _this; } _inheritsLoose(InputTextFuzzy, _React$Component); var _proto = InputTextFuzzy.prototype; _proto.render = function render() { const _this$props = this.props, inputId = _this$props.inputId, id = _this$props.id, placeholder = _this$props.placeholder, disabled = _this$props.disabled, label = _this$props.label, boxed = _this$props.boxed, autoFocusInput = _this$props.autoFocusInput; const autoProps = { suggestions: this.state.suggestions, renderSuggestionsContainer: this.renderItemsContainer, renderSuggestion: this.renderItem, onSuggestionsFetchRequested: this.onSuggestionsFetchRequested, onSuggestionsClearRequested: this.onSuggestionsClearRequested, getSuggestionValue: this.getSuggestionValue, shouldRenderSuggestions: this.shouldRenderSuggestions, onSuggestionSelected: this.onSuggestionSelected, focusInputOnSuggestionClick: false, inputProps: { type: 'search', placeholder: placeholder, onChange: this.handleChange, value: this.state.value, disabled: disabled, id: inputId, onFocus: this.handleFocus, autoFocus: autoFocusInput, onBlur: this.handleBlur, onKeyPress: this.handleKeyPress }, id: id }; const inputTextTypeAheadClasses = classNames({ 'ma__input-typeahead': true, 'ma__input-typeahead--disabled': disabled, 'ma__input-typeahead--boxed': boxed }); return /*#__PURE__*/React.createElement(React.Fragment, null, label && /*#__PURE__*/React.createElement(Label, { inputId: inputId, disabled: disabled }, label), /*#__PURE__*/React.createElement("div", { className: inputTextTypeAheadClasses }, /*#__PURE__*/React.createElement(Autosuggest, autoProps))); }; return InputTextFuzzy; }(React.Component); InputTextFuzzy.propTypes = process.env.NODE_ENV !== "production" ? { /** The id of the typeahead element. */ id: PropTypes.string.isRequired, /** The label text above the input text box. */ label: PropTypes.string, /** The placeholder text to appear in the input text box. */ placeholder: PropTypes.string, /** Style the input with a box outline. */ boxed: PropTypes.bool, /** The keys within options that will be searched (part of fuseOptions). * https://fusejs.io/api/options.html#keys */ keys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object])).isRequired, /** An array of objects representing all searchable values. */ options: PropTypes.arrayOf(PropTypes.shape({ label: PropTypes.string, id: PropTypes.string, // eslint-disable-next-line react/forbid-prop-types options: PropTypes.any, keys: PropTypes.arrayOf(PropTypes.string), selected: PropTypes.string, placeholder: PropTypes.string, onChange: PropTypes.func })).isRequired, /** Any Fusejs options to override the default options set in this component. * API doc: https://fusejs.io/api/options.html * */ /* eslint-disable-next-line react/forbid-prop-types */ fuseOptions: PropTypes.object, /** Disables input. */ disabled: PropTypes.bool, /** Function that runs after changes to the input happen. */ onChange: PropTypes.func, onFocus: PropTypes.func, onBlur: PropTypes.func, /** Function that runs after a suggestion has been clicked. */ onSuggestionClick: PropTypes.func, /** Custom keydown callback */ onKeyDown: PropTypes.func, /** The default value for the select box. */ selected: PropTypes.string, /** The id of the the input tag */ inputId: PropTypes.string, /** By default all options will be rendered as suggestions on input focus */ renderDefaultSuggestion: PropTypes.bool, /** Focus on typeahead input */ autoFocusInput: PropTypes.bool } : {}; InputTextFuzzy.defaultProps = { fuseOptions: { /** Set the result list to sort by score. */ shouldSort: true, /** Prevents matching from stopping at the first match found. */ findAllMatches: true, /** Lets the matches found be included in the result set. This field must be true for the highlight to work. */ includeMatches: true, /** Match sensitivity. 0 means what's been typed must be a perfect match, 1 means anything typed matches. */ threshold: 0.3, /** Prevents matches against empty strings. */ minMatchCharLength: 1, /** Allows more characters for long queries. */ maxPatternLength: 300 }, autoFocusInput: false, disabled: false, boxed: false, renderDefaultSuggestion: true }; export default InputTextFuzzy;