UNPKG

optimizely-oui

Version:

Optimizely's Component Library.

383 lines (314 loc) 15.3 kB
var _class, _class2, _temp; function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 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 ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } 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 { debounce, noop } from "lodash"; import PropTypes from "prop-types"; import React from "react"; import { keyboardTracker } from "../../utils/accessibility"; import Input from "../Input"; var INITIAL_SEARCH_PAGE_SIZE = 5; var INPUT_DEBOUNCE_PERIOD = 120; var SearchPicker = keyboardTracker(_class = (_temp = _class2 = /*#__PURE__*/ function (_React$Component) { _inherits(SearchPicker, _React$Component); function SearchPicker() { var _getPrototypeOf2; var _this; _classCallCheck(this, SearchPicker); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(SearchPicker)).call.apply(_getPrototypeOf2, [this].concat(args))); _defineProperty(_assertThisInitialized(_this), "componentDidMount", function () { var _this$props = _this.props, searchFunction = _this$props.searchFunction, searchOptions = _this$props.searchOptions, setOnItemSelect = _this$props.setOnItemSelect, supportedTypes = _this$props.supportedTypes; setOnItemSelect(function () { return _this.handleItemSelected; }); searchFunction(_objectSpread({}, searchOptions, { types: supportedTypes, query: "", per_page: INITIAL_SEARCH_PAGE_SIZE })).then(function (results) { // Make this Promise catch if the results are not an array _this.verifyResultOrThrow(results); _this.setState({ defaultResults: results }); })["finally"](function () { var searchQuery = _this.state.searchQuery; // Always set loading false as long as searchQuery is empty if (!searchQuery) { _this.setState({ isLoading: false }); } }); }); _defineProperty(_assertThisInitialized(_this), "componentDidUpdate", function () { var items = _this.getAvailableEntities(); _this.props.setItemCount(items.length); }); _defineProperty(_assertThisInitialized(_this), "state", { currentSearch: null, defaultResults: [], isLoading: true, results: null, searchQuery: "" }); _defineProperty(_assertThisInitialized(_this), "handleItemSelected", function (index) { var onItemSelected = _this.props.onItemSelected; var searchQuery = _this.state.searchQuery; onItemSelected(index, _this.getAvailableEntities(), searchQuery); }); _defineProperty(_assertThisInitialized(_this), "handleOnInput", function (event) { var value = event.target.value; _this.setState({ searchQuery: value }); if (value) { _this.handleOnInputDebounced(value); } else { var currentSearch = _this.state.currentSearch; if (currentSearch) { currentSearch.reject("Search interrupted by empty search query."); } _this.setState({ isLoading: false, results: null, currentSearch: null }); } }); _defineProperty(_assertThisInitialized(_this), "executeNewSearch", function (query) { return new Promise(function (resolve, reject) { var _this$props2 = _this.props, searchFunction = _this$props2.searchFunction, searchOptions = _this$props2.searchOptions, supportedTypes = _this$props2.supportedTypes; var currentSearch = _this.state.currentSearch; if (currentSearch) { currentSearch.reject("Search interrupted by new search query: ".concat(query)); } _this.setState({ currentSearch: { resolve: resolve, reject: reject }, isLoading: true }); searchFunction(_objectSpread({}, searchOptions, { types: supportedTypes, query: query.toLowerCase() })).then(resolve, reject); }); }); _defineProperty(_assertThisInitialized(_this), "handleOnInputDebounced", debounce(function (query) { _this.executeNewSearch(query).then(function (results) { var searchQuery = _this.state.searchQuery; _this.setState({ isLoading: false, currentSearch: null }); // Ensure the query wasn't killed while waiting for the result. if (searchQuery) { _this.setState({ results: results }); } }, function (e) { /** Swallow rejections */ }); }, !!process.env.JEST_WORKER_ID ? 0 : INPUT_DEBOUNCE_PERIOD)); _defineProperty(_assertThisInitialized(_this), "getAvailableEntities", function () { var _this$props3 = _this.props, selectedEntityIds = _this$props3.selectedEntityIds, filterAvailableEntities = _this$props3.filterAvailableEntities; if (typeof filterAvailableEntities === "function") { return filterAvailableEntities(_this.getResultSet(), selectedEntityIds); } return _this.getResultSet().filter(function (result) { return !selectedEntityIds.includes(result.id); }); }); _defineProperty(_assertThisInitialized(_this), "getResultSet", function () { var _this$state = _this.state, results = _this$state.results, defaultResults = _this$state.defaultResults; return results || defaultResults; }); _defineProperty(_assertThisInitialized(_this), "getResultsText", function () { var supportedTypes = _this.props.supportedTypes; var _this$state2 = _this.state, isLoading = _this$state2.isLoading, searchQuery = _this$state2.searchQuery; var resultCount = _this.getAvailableEntities().length; var summaryNoun = supportedTypes.length > 1 ? "entities" : "".concat(supportedTypes[0], "s"); var summary = "Recently created ".concat(summaryNoun); if (isLoading) { summary = "Searching for \"".concat(summaryNoun, "\" matching \"").concat(searchQuery, "\""); } else if (searchQuery) { if (resultCount) { summary = "Found ".concat(resultCount, " ").concat(summaryNoun, " matching \"").concat(searchQuery, "\""); } else { summary = "No ".concat(summaryNoun, " found matching \"").concat(searchQuery, "\""); } } return { summary: summary }; }); _defineProperty(_assertThisInitialized(_this), "verifyResultOrThrow", function (results) { if (!Array.isArray(results)) { throw new Error("SearchPicker props.searchFunction resolved with a value that is not an Array."); } }); _defineProperty(_assertThisInitialized(_this), "renderInput", function () { var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var _this$props4 = _this.props, handleKeyDown = _this$props4.handleKeyDown, supportedTypes = _this$props4.supportedTypes; var searchQuery = _this.state.searchQuery; var _assertThisInitialize = _assertThisInitialized(_this), handleOnInput = _assertThisInitialize.handleOnInput; var placeholderNoun = supportedTypes.map(function (i) { return "".concat(i, "s"); }).join(","); return React.createElement(Input, _extends({ isFilter: true, onChange: handleOnInput, placeholder: "Search for ".concat(placeholderNoun), testSection: "filter-".concat(placeholderNoun, "-input"), type: "search", value: searchQuery, onKeyDown: handleKeyDown }, props)); }); return _this; } _createClass(SearchPicker, [{ key: "render", /** * A simple render method that passes relevant state and controls to the * children. * @returns {React.Component} */ value: function render() { var _this$props5 = this.props, children = _this$props5.children, currentFauxFocusIndex = _this$props5.currentFauxFocusIndex; var _this$state3 = this.state, searchQuery = _this$state3.searchQuery, isLoading = _this$state3.isLoading; var renderInput = this.renderInput, handleOnInputDebounced = this.handleOnInputDebounced; var availableEntities = this.getAvailableEntities(); return children({ availableEntities: availableEntities, isLoading: isLoading, renderInput: renderInput, searchQuery: searchQuery, makeSearchRequest: handleOnInputDebounced, currentFauxFocusIndex: currentFauxFocusIndex, resultsText: this.getResultsText() }); } }]); return SearchPicker; }(React.Component), _defineProperty(_class2, "propTypes", { /** * A render function that is invoked with the following info: * availableEntities {Array<Entity>} - The list of entities available * based on the current input. If no query term is * entered, the default search collection is used. * * isLoading {Boolean} - Whether or not a search is in progress. * renderInput {Function<props>} - A function to render the <Input> * searchQuery {String} - The current search term * currentFauxFocusIndex {Number} - Index of the item currently selected. * resultsText {Object} - An object containing search result * summaries based on the the types provided * See this.getResultsText * */ children: PropTypes.func.isRequired, /** * Which index in the list is currently selected. * via @keyboardTracker */ currentFauxFocusIndex: PropTypes.number.isRequired, /** * This function can be set when custom search results filtering is required * It will override the internal search results filtering * * @param {Array} searchResults * @param {Array} selectedEntityIds * @param {Array} filteredSearchResults */ filterAvailableEntities: PropTypes.func, /** * A handler for the input element event onKeyDown * via @keyboardTracker */ handleKeyDown: PropTypes.func.isRequired, /** * The element ref to use for capturing keyboard input. * via @keyboardTracker */ keyboardRef: PropTypes.shape({ current: PropTypes.elementType }), /** * Handler to call when an item is selected via the keyboard. */ onItemSelected: PropTypes.func.isRequired, /** * The function to invoke to execute an authenticated public API search. * Different consumers will have different methods of authenticating. * * @param {Object} requestConfig * @return {Promise} */ searchFunction: PropTypes.func.isRequired, /** * Additional options to pass to the search function when a search is * executed. Type and query will be overridden by this component. */ searchOptions: PropTypes.object, /** * An optional list of ids which should be considered "selected". * If provided, these ids will be filtered out of the list. */ selectedEntityIds: PropTypes.array, /** * Sets the number of items for the list index tracker. * via @keyboardTracker */ setItemCount: PropTypes.func, /** * Sets the item select callback fn for the list index tracker. * via @keyboardTracker */ setOnItemSelect: PropTypes.func, /* The entity types we should query search for. */ supportedTypes: PropTypes.array.isRequired }), _defineProperty(_class2, "defaultProps", { searchOptions: {}, selectedEntityIds: [], setItemCount: noop, setOnItemSelect: noop }), _temp)) || _class; export default SearchPicker;