UNPKG

react-bootstrap-typeahead

Version:
162 lines (157 loc) 7.94 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.useAsync = useAsync; exports.withAsync = withAsync; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _lodash = _interopRequireDefault(require("lodash.debounce")); var _propTypes = _interopRequireDefault(require("prop-types")); var _react = _interopRequireWildcard(require("react")); var _useForceUpdate = _interopRequireDefault(require("@restart/hooks/useForceUpdate")); var _usePrevious = _interopRequireDefault(require("@restart/hooks/usePrevious")); var _propTypes2 = require("../propTypes"); var _utils = require("../utils"); var _excluded = ["allowNew", "delay", "emptyLabel", "isLoading", "minLength", "onInputChange", "onSearch", "options", "promptText", "searchText", "useCache"]; function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } var propTypes = { /** * Delay, in milliseconds, before performing search. */ delay: _propTypes["default"].number, /** * Whether or not a request is currently pending. Necessary for the * container to know when new results are available. */ isLoading: _propTypes["default"].bool.isRequired, /** * Number of input characters that must be entered before showing results. */ minLength: _propTypes["default"].number, /** * Callback to perform when the search is executed. */ onSearch: _propTypes["default"].func.isRequired, /** * Options to be passed to the typeahead. Will typically be the query * results, but can also be initial default options. */ options: _propTypes["default"].arrayOf(_propTypes2.optionType), /** * Message displayed in the menu when there is no user input. */ promptText: _propTypes["default"].node, /** * Message displayed in the menu while the request is pending. */ searchText: _propTypes["default"].node, /** * Whether or not the component should cache query results. */ useCache: _propTypes["default"].bool }; /** * Logic that encapsulates common behavior and functionality around * asynchronous searches, including: * * - Debouncing user input * - Optional query caching * - Search prompt and empty results behaviors */ function useAsync(props) { var allowNew = props.allowNew, _props$delay = props.delay, delay = _props$delay === void 0 ? 200 : _props$delay, emptyLabel = props.emptyLabel, isLoading = props.isLoading, _props$minLength = props.minLength, minLength = _props$minLength === void 0 ? 2 : _props$minLength, onInputChange = props.onInputChange, onSearch = props.onSearch, _props$options = props.options, options = _props$options === void 0 ? [] : _props$options, _props$promptText = props.promptText, promptText = _props$promptText === void 0 ? 'Type to search...' : _props$promptText, _props$searchText = props.searchText, searchText = _props$searchText === void 0 ? 'Searching...' : _props$searchText, _props$useCache = props.useCache, useCache = _props$useCache === void 0 ? true : _props$useCache, otherProps = (0, _objectWithoutProperties2["default"])(props, _excluded); var cacheRef = (0, _react.useRef)({}); var handleSearchDebouncedRef = (0, _react.useRef)(null); var queryRef = (0, _react.useRef)(props.defaultInputValue || ''); var forceUpdate = (0, _useForceUpdate["default"])(); var prevProps = (0, _usePrevious["default"])(props); var handleSearch = (0, _react.useCallback)(function (query) { queryRef.current = query; if (!query || minLength && query.length < minLength) { return; } // Use cached results, if applicable. if (useCache && cacheRef.current[query]) { // Re-render the component with the cached results. forceUpdate(); return; } // Perform the search. onSearch(query); }, [forceUpdate, minLength, onSearch, useCache]); // Set the debounced search function. (0, _react.useEffect)(function () { handleSearchDebouncedRef.current = (0, _lodash["default"])(handleSearch, delay); return function () { handleSearchDebouncedRef.current && handleSearchDebouncedRef.current.cancel(); }; }, [delay, handleSearch]); (0, _react.useEffect)(function () { // Ensure that we've gone from a loading to a completed state. Otherwise // an empty response could get cached if the component updates during the // request (eg: if the parent re-renders for some reason). if (!isLoading && prevProps && prevProps.isLoading && useCache) { cacheRef.current[queryRef.current] = options; } }); var getEmptyLabel = function getEmptyLabel() { if (!queryRef.current.length) { return promptText; } if (isLoading) { return searchText; } return emptyLabel; }; var handleInputChange = (0, _react.useCallback)(function (query, e) { onInputChange && onInputChange(query, e); handleSearchDebouncedRef.current && handleSearchDebouncedRef.current(query); }, [onInputChange]); var cachedQuery = cacheRef.current[queryRef.current]; return _objectSpread(_objectSpread({}, otherProps), {}, { // Disable custom selections during a search if `allowNew` isn't a function. allowNew: (0, _utils.isFunction)(allowNew) ? allowNew : allowNew && !isLoading, emptyLabel: getEmptyLabel(), isLoading: isLoading, minLength: minLength, onInputChange: handleInputChange, options: useCache && cachedQuery ? cachedQuery : options }); } /* istanbul ignore next */ function withAsync(Component) { (0, _utils.warn)(false, 'Warning: `withAsync` is deprecated and will be removed in the next ' + 'major version. Use `useAsync` instead.'); var AsyncTypeahead = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) { return /*#__PURE__*/_react["default"].createElement(Component, (0, _extends2["default"])({}, props, useAsync(props), { ref: ref })); }); AsyncTypeahead.displayName = "withAsync(".concat((0, _utils.getDisplayName)(Component), ")"); // @ts-ignore AsyncTypeahead.propTypes = propTypes; return AsyncTypeahead; }