@massds/mayflower-react
Version:
React versions of Mayflower design system UI components
349 lines (291 loc) • 11.8 kB
JavaScript
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 _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
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; }
/**
* 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) {
_inheritsLoose(InputTextFuzzy, _React$Component);
function InputTextFuzzy(props) {
var _this;
_this = _React$Component.call(this, props) || this;
_defineProperty(_assertThisInitialized(_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(_assertThisInitialized(_this), "onSuggestionsClearRequested", () => {
_this.setState({
suggestions: []
});
});
_defineProperty(_assertThisInitialized(_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(_assertThisInitialized(_this), "getSuggestionValue", suggestion => suggestion.item.text);
_defineProperty(_assertThisInitialized(_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(_assertThisInitialized(_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
});
}
});
_defineProperty(_assertThisInitialized(_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(_assertThisInitialized(_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(_assertThisInitialized(_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(_assertThisInitialized(_this), "shouldRenderSuggestions", value => _this.props.renderDefaultSuggestion === true ? value.trim().length >= 0 : value.trim().length > 0);
_defineProperty(_assertThisInitialized(_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(_assertThisInitialized(_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;
}
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.object).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;