'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _objectWithoutPropertiesLoose = require('@babel/runtime/helpers/objectWithoutPropertiesLoose'); var _extends = require('@babel/runtime/helpers/extends'); var _assertThisInitialized = require('@babel/runtime/helpers/assertThisInitialized'); var _inheritsLoose = require('@babel/runtime/helpers/inheritsLoose'); var PropTypes = require('prop-types'); var react = require('react'); var reactIs = require('react-is'); var compute = require('compute-scroll-into-view'); var tslib = require('tslib'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var _objectWithoutPropertiesLoose__default = /*#__PURE__*/_interopDefaultLegacy(_objectWithoutPropertiesLoose); var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends); var _assertThisInitialized__default = /*#__PURE__*/_interopDefaultLegacy(_assertThisInitialized); var _inheritsLoose__default = /*#__PURE__*/_interopDefaultLegacy(_inheritsLoose); var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes); var compute__default = /*#__PURE__*/_interopDefaultLegacy(compute); var idCounter = 0; /** * Accepts a parameter and returns it if it's a function * or a noop function if it's not. This allows us to * accept a callback, but not worry about it if it's not * passed. * @param {Function} cb the callback * @return {Function} a function */ function cbToCb(cb) { return typeof cb === 'function' ? cb : noop; } function noop() {} /** * Scroll node into view if necessary * @param {HTMLElement} node the element that should scroll into view * @param {HTMLElement} menuNode the menu element of the component */ function scrollIntoView(node, menuNode) { if (!node) { return; } var actions = compute__default["default"](node, { boundary: menuNode, block: 'nearest', scrollMode: 'if-needed' }); actions.forEach(function (_ref) { var el = _ref.el, top = _ref.top, left = _ref.left; el.scrollTop = top; el.scrollLeft = left; }); } /** * @param {HTMLElement} parent the parent node * @param {HTMLElement} child the child node * @param {Window} environment The window context where downshift renders. * @return {Boolean} whether the parent is the child or the child is in the parent */ function isOrContainsNode(parent, child, environment) { var result = parent === child || child instanceof environment.Node && parent.contains && parent.contains(child); return result; } /** * Simple debounce implementation. Will call the given * function once after the time given has passed since * it was last called. * @param {Function} fn the function to call after the time * @param {Number} time the time to wait * @return {Function} the debounced function */ function debounce(fn, time) { var timeoutId; function cancel() { if (timeoutId) { clearTimeout(timeoutId); } } function wrapper() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } cancel(); timeoutId = setTimeout(function () { timeoutId = null; fn.apply(void 0, args); }, time); } wrapper.cancel = cancel; return wrapper; } /** * This is intended to be used to compose event handlers. * They are executed in order until one of them sets * `event.preventDownshiftDefault = true`. * @param {...Function} fns the event handler functions * @return {Function} the event handler to add to an element */ function callAllEventHandlers() { for (var _len2 = arguments.length, fns = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { fns[_key2] = arguments[_key2]; } return function (event) { for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { args[_key3 - 1] = arguments[_key3]; } return fns.some(function (fn) { if (fn) { fn.apply(void 0, [event].concat(args)); } return event.preventDownshiftDefault || event.hasOwnProperty('nativeEvent') && event.nativeEvent.preventDownshiftDefault; }); }; } function handleRefs() { for (var _len4 = arguments.length, refs = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { refs[_key4] = arguments[_key4]; } return function (node) { refs.forEach(function (ref) { if (typeof ref === 'function') { ref(node); } else if (ref) { ref.current = node; } }); }; } /** * This generates a unique ID for an instance of Downshift * @return {String} the unique ID */ function generateId() { return String(idCounter++); } /** * Resets idCounter to 0. Used for SSR. */ function resetIdCounter() { idCounter = 0; } /** * Default implementation for status message. Only added when menu is open. * Will specify if there are results in the list, and if so, how many, * and what keys are relevant. * * @param {Object} param the downshift state and other relevant properties * @return {String} the a11y status message */ function getA11yStatusMessage$1(_ref2) { var isOpen = _ref2.isOpen, resultCount = _ref2.resultCount, previousResultCount = _ref2.previousResultCount; if (!isOpen) { return ''; } if (!resultCount) { return 'No results are available.'; } if (resultCount !== previousResultCount) { return resultCount + " result" + (resultCount === 1 ? ' is' : 's are') + " available, use up and down arrow keys to navigate. Press Enter key to select."; } return ''; } /** * Takes an argument and if it's an array, returns the first item in the array * otherwise returns the argument * @param {*} arg the maybe-array * @param {*} defaultValue the value if arg is falsey not defined * @return {*} the arg or it's first item */ function unwrapArray(arg, defaultValue) { arg = Array.isArray(arg) ? /* istanbul ignore next (preact) */arg[0] : arg; if (!arg && defaultValue) { return defaultValue; } else { return arg; } } /** * @param {Object} element (P)react element * @return {Boolean} whether it's a DOM element */ function isDOMElement(element) { // then we assume this is react return typeof element.type === 'string'; } /** * @param {Object} element (P)react element * @return {Object} the props */ function getElementProps(element) { return element.props; } /** * Throws a helpful error message for required properties. Useful * to be used as a default in destructuring or object params. * @param {String} fnName the function name * @param {String} propName the prop name */ function requiredProp(fnName, propName) { // eslint-disable-next-line no-console console.error("The property \"" + propName + "\" is required in \"" + fnName + "\""); } var stateKeys = ['highlightedIndex', 'inputValue', 'isOpen', 'selectedItem', 'type']; /** * @param {Object} state the state object * @return {Object} state that is relevant to downshift */ function pickState(state) { if (state === void 0) { state = {}; } var result = {}; stateKeys.forEach(function (k) { if (state.hasOwnProperty(k)) { result[k] = state[k]; } }); return result; } /** * This will perform a shallow merge of the given state object * with the state coming from props * (for the controlled component scenario) * This is used in state updater functions so they're referencing * the right state regardless of where it comes from. * * @param {Object} state The state of the component/hook. * @param {Object} props The props that may contain controlled values. * @returns {Object} The merged controlled state. */ function getState(state, props) { return Object.keys(state).reduce(function (prevState, key) { prevState[key] = isControlledProp(props, key) ? props[key] : state[key]; return prevState; }, {}); } /** * This determines whether a prop is a "controlled prop" meaning it is * state which is controlled by the outside of this component rather * than within this component. * * @param {Object} props The props that may contain controlled values. * @param {String} key the key to check * @return {Boolean} whether it is a controlled controlled prop */ function isControlledProp(props, key) { return props[key] !== undefined; } /** * Normalizes the 'key' property of a KeyboardEvent in IE/Edge * @param {Object} event a keyboardEvent object * @return {String} keyboard key */ function normalizeArrowKey(event) { var key = event.key, keyCode = event.keyCode; /* istanbul ignore next (ie) */ if (keyCode >= 37 && keyCode <= 40 && key.indexOf('Arrow') !== 0) { return "Arrow" + key; } return key; } /** * Simple check if the value passed is object literal * @param {*} obj any things * @return {Boolean} whether it's object literal */ function isPlainObject(obj) { return Object.prototype.toString.call(obj) === '[object Object]'; } /** * Returns the new index in the list, in a circular way. If next value is out of bonds from the total, * it will wrap to either 0 or itemCount - 1. * * @param {number} moveAmount Number of positions to move. Negative to move backwards, positive forwards. * @param {number} baseIndex The initial position to move from. * @param {number} itemCount The total number of items. * @param {Function} getItemNodeFromIndex Used to check if item is disabled. * @param {boolean} circular Specify if navigation is circular. Default is true. * @returns {number} The new index after the move. */ function getNextWrappingIndex(moveAmount, baseIndex, itemCount, getItemNodeFromIndex, circular) { if (circular === void 0) { circular = true; } if (itemCount === 0) { return -1; } var itemsLastIndex = itemCount - 1; if (typeof baseIndex !== 'number' || baseIndex < 0 || baseIndex >= itemCount) { baseIndex = moveAmount > 0 ? -1 : itemsLastIndex + 1; } var newIndex = baseIndex + moveAmount; if (newIndex < 0) { newIndex = circular ? itemsLastIndex : 0; } else if (newIndex > itemsLastIndex) { newIndex = circular ? 0 : itemsLastIndex; } var nonDisabledNewIndex = getNextNonDisabledIndex(moveAmount, newIndex, itemCount, getItemNodeFromIndex, circular); if (nonDisabledNewIndex === -1) { return baseIndex >= itemCount ? -1 : baseIndex; } return nonDisabledNewIndex; } /** * Returns the next index in the list of an item that is not disabled. * * @param {number} moveAmount Number of positions to move. Negative to move backwards, positive forwards. * @param {number} baseIndex The initial position to move from. * @param {number} itemCount The total number of items. * @param {Function} getItemNodeFromIndex Used to check if item is disabled. * @param {boolean} circular Specify if navigation is circular. Default is true. * @returns {number} The new index. Returns baseIndex if item is not disabled. Returns next non-disabled item otherwise. If no non-disabled found it will return -1. */ function getNextNonDisabledIndex(moveAmount, baseIndex, itemCount, getItemNodeFromIndex, circular) { var currentElementNode = getItemNodeFromIndex(baseIndex); if (!currentElementNode || !currentElementNode.hasAttribute('disabled')) { return baseIndex; } if (moveAmount > 0) { for (var index = baseIndex + 1; index < itemCount; index++) { if (!getItemNodeFromIndex(index).hasAttribute('disabled')) { return index; } } } else { for (var _index = baseIndex - 1; _index >= 0; _index--) { if (!getItemNodeFromIndex(_index).hasAttribute('disabled')) { return _index; } } } if (circular) { return moveAmount > 0 ? getNextNonDisabledIndex(1, 0, itemCount, getItemNodeFromIndex, false) : getNextNonDisabledIndex(-1, itemCount - 1, itemCount, getItemNodeFromIndex, false); } return -1; } /** * Checks if event target is within the downshift elements. * * @param {EventTarget} target Target to check. * @param {HTMLElement[]} downshiftElements The elements that form downshift (list, toggle button etc). * @param {Window} environment The window context where downshift renders. * @param {boolean} checkActiveElement Whether to also check activeElement. * * @returns {boolean} Whether or not the target is within downshift elements. */ function targetWithinDownshift(target, downshiftElements, environment, checkActiveElement) { if (checkActiveElement === void 0) { checkActiveElement = true; } return downshiftElements.some(function (contextNode) { return contextNode && (isOrContainsNode(contextNode, target, environment) || checkActiveElement && isOrContainsNode(contextNode, environment.document.activeElement, environment)); }); } // eslint-disable-next-line import/no-mutable-exports var validateControlledUnchanged = noop; /* istanbul ignore next */ if (process.env.NODE_ENV !== 'production') { validateControlledUnchanged = function validateControlledUnchanged(state, prevProps, nextProps) { var warningDescription = "This prop should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled Downshift element for the lifetime of the component. More info: https://github.com/downshift-js/downshift#control-props"; Object.keys(state).forEach(function (propKey) { if (prevProps[propKey] !== undefined && nextProps[propKey] === undefined) { // eslint-disable-next-line no-console console.error("downshift: A component has changed the controlled prop \"" + propKey + "\" to be uncontrolled. " + warningDescription); } else if (prevProps[propKey] === undefined && nextProps[propKey] !== undefined) { // eslint-disable-next-line no-console console.error("downshift: A component has changed the uncontrolled prop \"" + propKey + "\" to be controlled. " + warningDescription); } }); }; } var cleanupStatus = debounce(function (documentProp) { getStatusDiv(documentProp).textContent = ''; }, 500); /** * @param {String} status the status message * @param {Object} documentProp document passed by the user. */ function setStatus(status, documentProp) { var div = getStatusDiv(documentProp); if (!status) { return; } div.textContent = status; cleanupStatus(documentProp); } /** * Get the status node or create it if it does not already exist. * @param {Object} documentProp document passed by the user. * @return {HTMLElement} the status node. */ function getStatusDiv(documentProp) { if (documentProp === void 0) { documentProp = document; } var statusDiv = documentProp.getElementById('a11y-status-message'); if (statusDiv) { return statusDiv; } statusDiv = documentProp.createElement('div'); statusDiv.setAttribute('id', 'a11y-status-message'); statusDiv.setAttribute('role', 'status'); statusDiv.setAttribute('aria-live', 'polite'); statusDiv.setAttribute('aria-relevant', 'additions text'); Object.assign(statusDiv.style, { border: '0', clip: 'rect(0 0 0 0)', height: '1px', margin: '-1px', overflow: 'hidden', padding: '0', position: 'absolute', width: '1px' }); documentProp.body.appendChild(statusDiv); return statusDiv; } var unknown = process.env.NODE_ENV !== "production" ? '__autocomplete_unknown__' : 0; var mouseUp = process.env.NODE_ENV !== "production" ? '__autocomplete_mouseup__' : 1; var itemMouseEnter = process.env.NODE_ENV !== "production" ? '__autocomplete_item_mouseenter__' : 2; var keyDownArrowUp = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_arrow_up__' : 3; var keyDownArrowDown = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_arrow_down__' : 4; var keyDownEscape = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_escape__' : 5; var keyDownEnter = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_enter__' : 6; var keyDownHome = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_home__' : 7; var keyDownEnd = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_end__' : 8; var clickItem = process.env.NODE_ENV !== "production" ? '__autocomplete_click_item__' : 9; var blurInput = process.env.NODE_ENV !== "production" ? '__autocomplete_blur_input__' : 10; var changeInput = process.env.NODE_ENV !== "production" ? '__autocomplete_change_input__' : 11; var keyDownSpaceButton = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_space_button__' : 12; var clickButton = process.env.NODE_ENV !== "production" ? '__autocomplete_click_button__' : 13; var blurButton = process.env.NODE_ENV !== "production" ? '__autocomplete_blur_button__' : 14; var controlledPropUpdatedSelectedItem = process.env.NODE_ENV !== "production" ? '__autocomplete_controlled_prop_updated_selected_item__' : 15; var touchEnd = process.env.NODE_ENV !== "production" ? '__autocomplete_touchend__' : 16; var stateChangeTypes$3 = /*#__PURE__*/Object.freeze({ __proto__: null, unknown: unknown, mouseUp: mouseUp, itemMouseEnter: itemMouseEnter, keyDownArrowUp: keyDownArrowUp, keyDownArrowDown: keyDownArrowDown, keyDownEscape: keyDownEscape, keyDownEnter: keyDownEnter, keyDownHome: keyDownHome, keyDownEnd: keyDownEnd, clickItem: clickItem, blurInput: blurInput, changeInput: changeInput, keyDownSpaceButton: keyDownSpaceButton, clickButton: clickButton, blurButton: blurButton, controlledPropUpdatedSelectedItem: controlledPropUpdatedSelectedItem, touchEnd: touchEnd }); var _excluded$4 = ["refKey", "ref"], _excluded2$3 = ["onClick", "onPress", "onKeyDown", "onKeyUp", "onBlur"], _excluded3$2 = ["onKeyDown", "onBlur", "onChange", "onInput", "onChangeText"], _excluded4$1 = ["refKey", "ref"], _excluded5 = ["onMouseMove", "onMouseDown", "onClick", "onPress", "index", "item"]; var Downshift = /*#__PURE__*/function () { var Downshift = /*#__PURE__*/function (_Component) { _inheritsLoose__default["default"](Downshift, _Component); function Downshift(_props) { var _this; _this = _Component.call(this, _props) || this; // fancy destructuring + defaults + aliases // this basically says each value of state should either be set to // the initial value or the default value if the initial value is not provided _this.id = _this.props.id || "downshift-" + generateId(); _this.menuId = _this.props.menuId || _this.id + "-menu"; _this.labelId = _this.props.labelId || _this.id + "-label"; _this.inputId = _this.props.inputId || _this.id + "-input"; _this.getItemId = _this.props.getItemId || function (index) { return _this.id + "-item-" + index; }; _this.input = null; _this.items = []; // itemCount can be changed asynchronously // from within downshift (so it can't come from a prop) // this is why we store it as an instance and use // getItemCount rather than just use items.length // (to support windowing + async) _this.itemCount = null; _this.previousResultCount = 0; _this.timeoutIds = []; /** * @param {Function} fn the function to call after the time * @param {Number} time the time to wait */ _this.internalSetTimeout = function (fn, time) { var id = setTimeout(function () { _this.timeoutIds = _this.timeoutIds.filter(function (i) { return i !== id; }); fn(); }, time); _this.timeoutIds.push(id); }; _this.setItemCount = function (count) { _this.itemCount = count; }; _this.unsetItemCount = function () { _this.itemCount = null; }; _this.setHighlightedIndex = function (highlightedIndex, otherStateToSet) { if (highlightedIndex === void 0) { highlightedIndex = _this.props.defaultHighlightedIndex; } if (otherStateToSet === void 0) { otherStateToSet = {}; } otherStateToSet = pickState(otherStateToSet); _this.internalSetState(_extends__default["default"]({ highlightedIndex: highlightedIndex }, otherStateToSet)); }; _this.clearSelection = function (cb) { _this.internalSetState({ selectedItem: null, inputValue: '', highlightedIndex: _this.props.defaultHighlightedIndex, isOpen: _this.props.defaultIsOpen }, cb); }; _this.selectItem = function (item, otherStateToSet, cb) { otherStateToSet = pickState(otherStateToSet); _this.internalSetState(_extends__default["default"]({ isOpen: _this.props.defaultIsOpen, highlightedIndex: _this.props.defaultHighlightedIndex, selectedItem: item, inputValue: _this.props.itemToString(item) }, otherStateToSet), cb); }; _this.selectItemAtIndex = function (itemIndex, otherStateToSet, cb) { var item = _this.items[itemIndex]; if (item == null) { return; } _this.selectItem(item, otherStateToSet, cb); }; _this.selectHighlightedItem = function (otherStateToSet, cb) { return _this.selectItemAtIndex(_this.getState().highlightedIndex, otherStateToSet, cb); }; // any piece of our state can live in two places: // 1. Uncontrolled: it's internal (this.state) // We will call this.setState to update that state // 2. Controlled: it's external (this.props) // We will call this.props.onStateChange to update that state // // In addition, we'll call this.props.onChange if the // selectedItem is changed. _this.internalSetState = function (stateToSet, cb) { var isItemSelected, onChangeArg; var onStateChangeArg = {}; var isStateToSetFunction = typeof stateToSet === 'function'; // we want to call `onInputValueChange` before the `setState` call // so someone controlling the `inputValue` state gets notified of // the input change as soon as possible. This avoids issues with // preserving the cursor position. // See https://github.com/downshift-js/downshift/issues/217 for more info. if (!isStateToSetFunction && stateToSet.hasOwnProperty('inputValue')) { _this.props.onInputValueChange(stateToSet.inputValue, _extends__default["default"]({}, _this.getStateAndHelpers(), stateToSet)); } return _this.setState(function (state) { state = _this.getState(state); var newStateToSet = isStateToSetFunction ? stateToSet(state) : stateToSet; // Your own function that could modify the state that will be set. newStateToSet = _this.props.stateReducer(state, newStateToSet); // checks if an item is selected, regardless of if it's different from // what was selected before // used to determine if onSelect and onChange callbacks should be called isItemSelected = newStateToSet.hasOwnProperty('selectedItem'); // this keeps track of the object we want to call with setState var nextState = {}; // we need to call on change if the outside world is controlling any of our state // and we're trying to update that state. OR if the selection has changed and we're // trying to update the selection if (isItemSelected && newStateToSet.selectedItem !== state.selectedItem) { onChangeArg = newStateToSet.selectedItem; } newStateToSet.type = newStateToSet.type || unknown; Object.keys(newStateToSet).forEach(function (key) { // onStateChangeArg should only have the state that is // actually changing if (state[key] !== newStateToSet[key]) { onStateChangeArg[key] = newStateToSet[key]; } // the type is useful for the onStateChangeArg // but we don't actually want to set it in internal state. // this is an undocumented feature for now... Not all internalSetState // calls support it and I'm not certain we want them to yet. // But it enables users controlling the isOpen state to know when // the isOpen state changes due to mouseup events which is quite handy. if (key === 'type') { return; } newStateToSet[key]; // if it's coming from props, then we don't care to set it internally if (!isControlledProp(_this.props, key)) { nextState[key] = newStateToSet[key]; } }); // if stateToSet is a function, then we weren't able to call onInputValueChange // earlier, so we'll call it now that we know what the inputValue state will be. if (isStateToSetFunction && newStateToSet.hasOwnProperty('inputValue')) { _this.props.onInputValueChange(newStateToSet.inputValue, _extends__default["default"]({}, _this.getStateAndHelpers(), newStateToSet)); } return nextState; }, function () { // call the provided callback if it's a function cbToCb(cb)(); // only call the onStateChange and onChange callbacks if // we have relevant information to pass them. var hasMoreStateThanType = Object.keys(onStateChangeArg).length > 1; if (hasMoreStateThanType) { _this.props.onStateChange(onStateChangeArg, _this.getStateAndHelpers()); } if (isItemSelected) { _this.props.onSelect(stateToSet.selectedItem, _this.getStateAndHelpers()); } if (onChangeArg !== undefined) { _this.props.onChange(onChangeArg, _this.getStateAndHelpers()); } // this is currently undocumented and therefore subject to change // We'll try to not break it, but just be warned. _this.props.onUserAction(onStateChangeArg, _this.getStateAndHelpers()); }); }; //////////////////////////// ROOT _this.rootRef = function (node) { return _this._rootNode = node; }; _this.getRootProps = function (_temp, _temp2) { var _extends2; var _ref = _temp === void 0 ? {} : _temp, _ref$refKey = _ref.refKey, refKey = _ref$refKey === void 0 ? 'ref' : _ref$refKey, ref = _ref.ref, rest = _objectWithoutPropertiesLoose__default["default"](_ref, _excluded$4); var _ref2 = _temp2 === void 0 ? {} : _temp2, _ref2$suppressRefErro = _ref2.suppressRefError, suppressRefError = _ref2$suppressRefErro === void 0 ? false : _ref2$suppressRefErro; // this is used in the render to know whether the user has called getRootProps. // It uses that to know whether to apply the props automatically _this.getRootProps.called = true; _this.getRootProps.refKey = refKey; _this.getRootProps.suppressRefError = suppressRefError; var _this$getState = _this.getState(), isOpen = _this$getState.isOpen; return _extends__default["default"]((_extends2 = {}, _extends2[refKey] = handleRefs(ref, _this.rootRef), _extends2.role = 'combobox', _extends2['aria-expanded'] = isOpen, _extends2['aria-haspopup'] = 'listbox', _extends2['aria-owns'] = isOpen ? _this.menuId : null, _extends2['aria-labelledby'] = _this.labelId, _extends2), rest); }; //\\\\\\\\\\\\\\\\\\\\\\\\\\ ROOT _this.keyDownHandlers = { ArrowDown: function ArrowDown(event) { var _this2 = this; event.preventDefault(); if (this.getState().isOpen) { var amount = event.shiftKey ? 5 : 1; this.moveHighlightedIndex(amount, { type: keyDownArrowDown }); } else { this.internalSetState({ isOpen: true, type: keyDownArrowDown }, function () { var itemCount = _this2.getItemCount(); if (itemCount > 0) { var _this2$getState = _this2.getState(), highlightedIndex = _this2$getState.highlightedIndex; var nextHighlightedIndex = getNextWrappingIndex(1, highlightedIndex, itemCount, function (index) { return _this2.getItemNodeFromIndex(index); }); _this2.setHighlightedIndex(nextHighlightedIndex, { type: keyDownArrowDown }); } }); } }, ArrowUp: function ArrowUp(event) { var _this3 = this; event.preventDefault(); if (this.getState().isOpen) { var amount = event.shiftKey ? -5 : -1; this.moveHighlightedIndex(amount, { type: keyDownArrowUp }); } else { this.internalSetState({ isOpen: true, type: keyDownArrowUp }, function () { var itemCount = _this3.getItemCount(); if (itemCount > 0) { var _this3$getState = _this3.getState(), highlightedIndex = _this3$getState.highlightedIndex; var nextHighlightedIndex = getNextWrappingIndex(-1, highlightedIndex, itemCount, function (index) { return _this3.getItemNodeFromIndex(index); }); _this3.setHighlightedIndex(nextHighlightedIndex, { type: keyDownArrowUp }); } }); } }, Enter: function Enter(event) { if (event.which === 229) { return; } var _this$getState2 = this.getState(), isOpen = _this$getState2.isOpen, highlightedIndex = _this$getState2.highlightedIndex; if (isOpen && highlightedIndex != null) { event.preventDefault(); var item = this.items[highlightedIndex]; var itemNode = this.getItemNodeFromIndex(highlightedIndex); if (item == null || itemNode && itemNode.hasAttribute('disabled')) { return; } this.selectHighlightedItem({ type: keyDownEnter }); } }, Escape: function Escape(event) { event.preventDefault(); this.reset(_extends__default["default"]({ type: keyDownEscape }, !this.state.isOpen && { selectedItem: null, inputValue: '' })); } }; //////////////////////////// BUTTON _this.buttonKeyDownHandlers = _extends__default["default"]({}, _this.keyDownHandlers, { ' ': function _(event) { event.preventDefault(); this.toggleMenu({ type: keyDownSpaceButton }); } }); _this.inputKeyDownHandlers = _extends__default["default"]({}, _this.keyDownHandlers, { Home: function Home(event) { var _this4 = this; var _this$getState3 = this.getState(), isOpen = _this$getState3.isOpen; if (!isOpen) { return; } event.preventDefault(); var itemCount = this.getItemCount(); if (itemCount <= 0 || !isOpen) { return; } // get next non-disabled starting downwards from 0 if that's disabled. var newHighlightedIndex = getNextNonDisabledIndex(1, 0, itemCount, function (index) { return _this4.getItemNodeFromIndex(index); }, false); this.setHighlightedIndex(newHighlightedIndex, { type: keyDownHome }); }, End: function End(event) { var _this5 = this; var _this$getState4 = this.getState(), isOpen = _this$getState4.isOpen; if (!isOpen) { return; } event.preventDefault(); var itemCount = this.getItemCount(); if (itemCount <= 0 || !isOpen) { return; } // get next non-disabled starting upwards from last index if that's disabled. var newHighlightedIndex = getNextNonDisabledIndex(-1, itemCount - 1, itemCount, function (index) { return _this5.getItemNodeFromIndex(index); }, false); this.setHighlightedIndex(newHighlightedIndex, { type: keyDownEnd }); } }); _this.getToggleButtonProps = function (_temp3) { var _ref3 = _temp3 === void 0 ? {} : _temp3, onClick = _ref3.onClick; _ref3.onPress; var onKeyDown = _ref3.onKeyDown, onKeyUp = _ref3.onKeyUp, onBlur = _ref3.onBlur, rest = _objectWithoutPropertiesLoose__default["default"](_ref3, _excluded2$3); var _this$getState5 = _this.getState(), isOpen = _this$getState5.isOpen; var enabledEventHandlers = { onClick: callAllEventHandlers(onClick, _this.buttonHandleClick), onKeyDown: callAllEventHandlers(onKeyDown, _this.buttonHandleKeyDown), onKeyUp: callAllEventHandlers(onKeyUp, _this.buttonHandleKeyUp), onBlur: callAllEventHandlers(onBlur, _this.buttonHandleBlur) }; var eventHandlers = rest.disabled ? {} : enabledEventHandlers; return _extends__default["default"]({ type: 'button', role: 'button', 'aria-label': isOpen ? 'close menu' : 'open menu', 'aria-haspopup': true, 'data-toggle': true }, eventHandlers, rest); }; _this.buttonHandleKeyUp = function (event) { // Prevent click event from emitting in Firefox event.preventDefault(); }; _this.buttonHandleKeyDown = function (event) { var key = normalizeArrowKey(event); if (_this.buttonKeyDownHandlers[key]) { _this.buttonKeyDownHandlers[key].call(_assertThisInitialized__default["default"](_this), event); } }; _this.buttonHandleClick = function (event) { event.preventDefault(); // handle odd case for Safari and Firefox which // don't give the button the focus properly. /* istanbul ignore if (can't reasonably test this) */ if (_this.props.environment.document.activeElement === _this.props.environment.document.body) { event.target.focus(); } // to simplify testing components that use downshift, we'll not wrap this in a setTimeout // if the NODE_ENV is test. With the proper build system, this should be dead code eliminated // when building for production and should therefore have no impact on production code. if (process.env.NODE_ENV === 'test') { _this.toggleMenu({ type: clickButton }); } else { // Ensure that toggle of menu occurs after the potential blur event in iOS _this.internalSetTimeout(function () { return _this.toggleMenu({ type: clickButton }); }); } }; _this.buttonHandleBlur = function (event) { var blurTarget = event.target; // Save blur target for comparison with activeElement later // Need setTimeout, so that when the user presses Tab, the activeElement is the next focused element, not body element _this.internalSetTimeout(function () { if (!_this.isMouseDown && (_this.props.environment.document.activeElement == null || _this.props.environment.document.activeElement.id !== _this.inputId) && _this.props.environment.document.activeElement !== blurTarget // Do nothing if we refocus the same element again (to solve issue in Safari on iOS) ) { _this.reset({ type: blurButton }); } }); }; //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ BUTTON /////////////////////////////// LABEL _this.getLabelProps = function (props) { return _extends__default["default"]({ htmlFor: _this.inputId, id: _this.labelId }, props); }; //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ LABEL /////////////////////////////// INPUT _this.getInputProps = function (_temp4) { var _ref4 = _temp4 === void 0 ? {} : _temp4, onKeyDown = _ref4.onKeyDown, onBlur = _ref4.onBlur, onChange = _ref4.onChange, onInput = _ref4.onInput; _ref4.onChangeText; var rest = _objectWithoutPropertiesLoose__default["default"](_ref4, _excluded3$2); var onChangeKey; var eventHandlers = {}; /* istanbul ignore next (preact) */ { onChangeKey = 'onChange'; } var _this$getState6 = _this.getState(), inputValue = _this$getState6.inputValue, isOpen = _this$getState6.isOpen, highlightedIndex = _this$getState6.highlightedIndex; if (!rest.disabled) { var _eventHandlers; eventHandlers = (_eventHandlers = {}, _eventHandlers[onChangeKey] = callAllEventHandlers(onChange, onInput, _this.inputHandleChange), _eventHandlers.onKeyDown = callAllEventHandlers(onKeyDown, _this.inputHandleKeyDown), _eventHandlers.onBlur = callAllEventHandlers(onBlur, _this.inputHandleBlur), _eventHandlers); } return _extends__default["default"]({ 'aria-autocomplete': 'list', 'aria-activedescendant': isOpen && typeof highlightedIndex === 'number' && highlightedIndex >= 0 ? _this.getItemId(highlightedIndex) : null, 'aria-controls': isOpen ? _this.menuId : null, 'aria-labelledby': rest && rest['aria-label'] ? undefined : _this.labelId, // https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion // revert back since autocomplete="nope" is ignored on latest Chrome and Opera autoComplete: 'off', value: inputValue, id: _this.inputId }, eventHandlers, rest); }; _this.inputHandleKeyDown = function (event) { var key = normalizeArrowKey(event); if (key && _this.inputKeyDownHandlers[key]) { _this.inputKeyDownHandlers[key].call(_assertThisInitialized__default["default"](_this), event); } }; _this.inputHandleChange = function (event) { _this.internalSetState({ type: changeInput, isOpen: true, inputValue: event.target.value, highlightedIndex: _this.props.defaultHighlightedIndex }); }; _this.inputHandleBlur = function () { // Need setTimeout, so that when the user presses Tab, the activeElement is the next focused element, not the body element _this.internalSetTimeout(function () { var downshiftButtonIsActive = _this.props.environment.document && !!_this.props.environment.document.activeElement && !!_this.props.environment.document.activeElement.dataset && _this.props.environment.document.activeElement.dataset.toggle && _this._rootNode && _this._rootNode.contains(_this.props.environment.document.activeElement); if (!_this.isMouseDown && !downshiftButtonIsActive) { _this.reset({ type: blurInput }); } }); }; //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ INPUT /////////////////////////////// MENU _this.menuRef = function (node) { _this._menuNode = node; }; _this.getMenuProps = function (_temp5, _temp6) { var _extends3; var _ref5 = _temp5 === void 0 ? {} : _temp5, _ref5$refKey = _ref5.refKey, refKey = _ref5$refKey === void 0 ? 'ref' : _ref5$refKey, ref = _ref5.ref, props = _objectWithoutPropertiesLoose__default["default"](_ref5, _excluded4$1); var _ref6 = _temp6 === void 0 ? {} : _temp6, _ref6$suppressRefErro = _ref6.suppressRefError, suppressRefError = _ref6$suppressRefErro === void 0 ? false : _ref6$suppressRefErro; _this.getMenuProps.called = true; _this.getMenuProps.refKey = refKey; _this.getMenuProps.suppressRefError = suppressRefError; return _extends__default["default"]((_extends3 = {}, _extends3[refKey] = handleRefs(ref, _this.menuRef), _extends3.role = 'listbox', _extends3['aria-labelledby'] = props && props['aria-label'] ? null : _this.labelId, _extends3.id = _this.menuId, _extends3), props); }; //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ MENU /////////////////////////////// ITEM _this.getItemProps = function (_temp7) { var _enabledEventHandlers; var _ref7 = _temp7 === void 0 ? {} : _temp7, onMouseMove = _ref7.onMouseMove, onMouseDown = _ref7.onMouseDown, onClick = _ref7.onClick; _ref7.onPress; var index = _ref7.index, _ref7$item = _ref7.item, item = _ref7$item === void 0 ? process.env.NODE_ENV === 'production' ? /* istanbul ignore next */undefined : requiredProp('getItemProps', 'item') : _ref7$item, rest = _objectWithoutPropertiesLoose__default["default"](_ref7, _excluded5); if (index === undefined) { _this.items.push(item); index = _this.items.indexOf(item); } else { _this.items[index] = item; } var onSelectKey = 'onClick'; var customClickHandler = onClick; var enabledEventHandlers = (_enabledEventHandlers = { // onMouseMove is used over onMouseEnter here. onMouseMove // is only triggered on actual mouse movement while onMouseEnter // can fire on DOM changes, interrupting keyboard navigation onMouseMove: callAllEventHandlers(onMouseMove, function () { if (index === _this.getState().highlightedIndex) { return; } _this.setHighlightedIndex(index, { type: itemMouseEnter }); // We never want to manually scroll when changing state based // on `onMouseMove` because we will be moving the element out // from under the user which is currently scrolling/moving the // cursor _this.avoidScrolling = true; _this.internalSetTimeout(function () { return _this.avoidScrolling = false; }, 250); }), onMouseDown: callAllEventHandlers(onMouseDown, function (event) { // This prevents the activeElement from being changed // to the item so it can remain with the current activeElement // which is a more common use case. event.preventDefault(); }) }, _enabledEventHandlers[onSelectKey] = callAllEventHandlers(customClickHandler, function () { _this.selectItemAtIndex(index, { type: clickItem }); }), _enabledEventHandlers); // Passing down the onMouseDown handler to prevent redirect // of the activeElement if clicking on disabled items var eventHandlers = rest.disabled ? { onMouseDown: enabledEventHandlers.onMouseDown } : enabledEventHandlers; return _extends__default["default"]({ id: _this.getItemId(index), role: 'option', 'aria-selected': _this.getState().highlightedIndex === index }, eventHandlers, rest); }; //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ITEM _this.clearItems = function () { _this.items = []; }; _this.reset = function (otherStateToSet, cb) { if (otherStateToSet === void 0) { otherStateToSet = {}; } otherStateToSet = pickState(otherStateToSet); _this.internalSetState(function (_ref8) { var selectedItem = _ref8.selectedItem; return _extends__default["default"]({ isOpen: _this.props.defaultIsOpen, highlightedIndex: _this.props.defaultHighlightedIndex, inputValue: _this.props.itemToString(selectedItem) }, otherStateToSet); }, cb); }; _this.toggleMenu = function (otherStateToSet, cb) { if (otherStateToSet === void 0) { otherStateToSet = {}; } otherStateToSet = pickState(otherStateToSet); _this.internalSetState(function (_ref9) { var isOpen = _ref9.isOpen; return _extends__default["default"]({ isOpen: !isOpen }, isOpen && { highlightedIndex: _this.props.defaultHighlightedIndex }, otherStateToSet); }, function () { var _this$getState7 = _this.getState(), isOpen = _this$getState7.isOpen, highlightedIndex = _this$getState7.highlightedIndex; if (isOpen) { if (_this.getItemCount() > 0 && typeof highlightedIndex === 'number') { _this.setHighlightedIndex(highlightedIndex, otherStateToSet); } } cbToCb(cb)(); }); }; _this.openMenu = function (cb) { _this.internalSetState({ isOpen: true }, cb); }; _this.closeMenu = function (cb) { _this.internalSetState({ isOpen: false }, cb); }; _this.updateStatus = debounce(function () { var state = _this.getState(); var item = _this.items[state.highlightedIndex]; var resultCount = _this.getItemCount(); var status = _this.props.getA11yStatusMessage(_extends__default["default"]({ itemToString: _this.props.itemToString, previousResultCount: _this.previousResultCount, resultCount: resultCount, highlightedItem: item }, state)); _this.previousResultCount = resultCount; setStatus(status, _this.props.environment.document); }, 200); var _this$props = _this.props, defaultHighlightedIndex = _this$props.defaultHighlightedIndex, _this$props$initialHi = _this$props.initialHighlightedIndex, _highlightedIndex = _this$props$initialHi === void 0 ? defaultHighlightedIndex : _this$props$initialHi, defaultIsOpen = _this$props.defaultIsOpen, _this$props$initialIs = _this$props.initialIsOpen, _isOpen = _this$props$initialIs === void 0 ? defaultIsOpen : _this$props$initialIs, _this$props$initialIn = _this$props.initialInputValue, _inputValue = _this$props$initialIn === void 0 ? '' : _this$props$initialIn, _this$props$initialSe = _this$props.initialSelectedItem, _selectedItem = _this$props$initialSe === void 0 ? null : _this$props$initialSe; var _state = _this.getState({ highlightedIndex: _highlightedIndex, isOpen: _isOpen, inputValue: _inputValue, selectedItem: _selectedItem }); if (_state.selectedItem != null && _this.props.initialInputValue === undefined) { _state.inputValue = _this.props.itemToString(_state.selectedItem); } _this.state = _state; return _this; } var _proto = Downshift.prototype; /** * Clear all running timeouts */ _proto.internalClearTimeouts = function internalClearTimeouts() { this.timeoutIds.forEach(function (id) { clearTimeout(id); }); this.timeoutIds = []; } /** * Gets the state based on internal state or props * If a state value is passed via props, then that * is the value given, otherwise it's retrieved from * stateToMerge * * @param {Object} stateToMerge defaults to this.state * @return {Object} the state */; _proto.getState = function getState$1(stateToMerge) { if (stateToMerge === void 0) { stateToMerge = this.state; } return getState(stateToMerge, this.props); }; _proto.getItemCount = function getItemCount() { // things read better this way. They're in priority order: // 1. `this.itemCount` // 2. `this.props.itemCount` // 3. `this.items.length` var itemCount = this.items.length; if (this.itemCount != null) { itemCount = this.itemCount; } else if (this.props.itemCount !== undefined) { itemCount = this.props.itemCount; } return itemCount; }; _proto.getItemNodeFromIndex = function getItemNodeFromIndex(index) { return this.props.environment.document.getElementById(this.getItemId(index)); }; _proto.scrollHighlightedItemIntoView = function scrollHighlightedItemIntoView() { /* istanbul ignore else (react-native) */ { var node = this.getItemNodeFromIndex(this.getState().highlightedIndex); this.props.scrollIntoView(node, this._menuNode); } }; _proto.moveHighlightedIndex = function moveHighlightedIndex(amount, otherStateToSet) { var _this6 = this; var itemCount = this.getItemCount(); var _this$getState8 = this.getState(), highlightedIndex = _this$getState8.highlightedIndex; if (itemCount > 0) { var nextHighlightedIndex = getNextWrappingIndex(amount, highlightedIndex, itemCount, function (index) { return _this6.getItemNodeFromIndex(index); }); this.setHighlightedIndex(nextHighlightedIndex, otherStateToSet); } }; _proto.getStateAndHelpers = function getStateAndHelpers() { var _this$getState9 = this.getState(), highlightedIndex = _this$getState9.highlightedIndex, inputValue = _this$getState9.inputValue, selectedItem = _this$getState9.selectedItem, isOpen = _this$getState9.isOpen; var itemToString = this.props.itemToString; var id = this.id; var getRootProps = this.getRootProps, getToggleButtonProps = this.getToggleButtonProps, getLabelProps = this.getLabelProps, getMenuProps = this.getMenuProps, getInputProps = this.getInputProps, getItemProps = this.getItemProps, openMenu = this.openMenu, closeMenu = this.closeMenu, toggleMenu = this.toggleMenu, selectItem = this.selectItem, selectItemAtIndex = this.selectItemAtIndex, selectHighlightedItem = this.selectHighlightedItem, setHighlightedIndex = this.setHighlightedIndex, clearSelection = this.clearSelection, clearItems = this.clearItems, reset = this.reset, setItemCount = this.setItemCount, unsetItemCount = this.unsetItemCount, setState = this.internalSetState; return { // prop getters getRootProps: getRootProps, getToggleButtonProps: getToggleButtonProps, getLabelProps: getLabelProps, getMenuProps: getMenuProps, getInputProps: getInputProps, getItemProps: getItemProps, // actions reset: reset, openMenu: openMenu, closeMenu: closeMenu, toggleMenu: toggleMenu, selectItem: selectItem, selectItemAtIndex: selectItemAtIndex, selectHighlightedItem: selectHighlightedItem, setHighlightedIndex: setHighlightedIndex, clearSelection: clearSelection, clearItems: clearItems, setItemCount: setItemCount, unsetItemCount: unsetItemCount, setState: setState, // props itemToString: itemToString, // derived id: id, // state highlightedIndex: highlightedIndex, inputValue: inputValue, isOpen: isOpen, selectedItem: selectedItem }; }; _proto.componentDidMount = function componentDidMount() { var _this7 = this; /* istanbul ignore if (react-native) */ if (process.env.NODE_ENV !== 'production' && !false && this.getMenuProps.called && !this.getMenuProps.suppressRefError) { validateGetMenuPropsCalledCorrectly(this._menuNode, this.getMenuProps); } /* istanbul ignore if (react-native) */ { // this.isMouseDown helps us track whether the mouse is currently held down. // This is useful when the user clicks on an item in the list, but holds the mouse // down long enough for the list to disappear (because the blur event fires on the input) // this.isMouseDown is used in the blur handler on the input to determine whether the blur event should // trigger hiding the menu. var onMouseDown = function onMouseDown() { _this7.isMouseDown = true; }; var onMouseUp = function onMouseUp(event) { _this7.isMouseDown = false; // if the target element or the activeElement is within a downshift node // then we don't want to reset downshift var contextWithinDownshift = targetWithinDownshift(event.target, [_this7._rootNode, _this7._menuNode], _this7.props.environment); if (!contextWithinDownshift && _this7.getState().isOpen) { _this7.reset({ type: mouseUp }, function () { return _this7.props.onOuterClick(_this7.getStateAndHelpers()); }); } }; // Touching an element in iOS gives focus and hover states, but touching out of // the element will remove hover, and persist the focus state, resulting in the // blur event not being triggered. // this.isTouchMove helps us track whether the user is tapping or swiping on a touch screen. // If the user taps outside of Downshift, the component should be reset, // but not if the user is swiping var onTouchStart = function onTouchStart() { _this7.isTouchMove = false; }; var onTouchMove = function onTouchMove() { _this7.isTouchMove = true; }; var onTouchEnd = function onTouchEnd(event) { var contextWithinDownshift = targetWithinDownshift(event.target, [_this7._rootNode, _this7._menuNode], _this7.props.environment, false); if (!_this7.isTouchMove && !contextWithinDownshift && _this7.getState().isOpen) { _this7.reset({ type: touchEnd }, function () { return _this7.props.onOuterClick(_this7.getStateAndHelpers()); }); } }; var environment = this.props.environment; environment.addEventListener('mousedown', onMouseDown); environment.addEventListener('mouseup', onMouseUp); environment.addEventListener('touchstart', onTouchStart); environment.addEventListener('touchmove', onTouchMove); environment.addEventListener('touchend', onTouchEnd); this.cleanup = function () { _this7.internalClearTimeouts(); _this7.updateStatus.cancel(); environment.removeEventListener('mousedown', onMouseDown); environment.removeEventListener('mouseup', onMouseUp); environment.removeEventListener('touchstart', onTouchStart); environment.removeEventListener('touchmove', onTouchMove); environment.removeEventListener('touchend', onTouchEnd); }; } }; _proto.shouldScroll = function shouldScroll(prevState, prevProps) { var _ref10 = this.props.highlightedIndex === undefined ? this.getState() : this.props, currentHighlightedIndex = _ref10.highlightedIndex; var _ref11 = prevProps.highlightedIndex === undefined ? prevState : prevProps, prevHighlightedIndex = _ref11.highlightedIndex; var scrollWhenOpen = currentHighlightedIndex && this.getState().isOpen && !prevState.isOpen; var scrollWhenNavigating = currentHighlightedIndex !== prevHighlightedIndex; return scrollWhenOpen || scrollWhenNavigating; }; _proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState) { if (process.env.NODE_ENV !== 'production') { validateControlledUnchanged(this.state, prevProps, this.props); /* istanbul ignore if (react-native) */ if (this.getMenuProps.called && !this.getMenuProps.suppressRefError) { validateGetMenuPropsCalledCorrectly(this._menuNode, this.getMenuProps); } } if (isControlledProp(this.props, 'selectedItem') && this.props.selectedItemChanged(prevProps.selectedItem, this.props.selectedItem)) { this.internalSetState({ type: controlledPropUpdatedSelectedItem, inputValue: this.props.itemToString(this.props.selectedItem) }); } if (!this.avoidScrolling && this.shouldScroll(prevState, prevProps)) { this.scrollHighlightedItemIntoView(); } /* istanbul ignore else (react-native) */ { this.updateStatus(); } }; _proto.componentWillUnmount = function componentWillUnmount() { this.cleanup(); // avoids memory leak }; _proto.render = function render() { var children = unwrapArray(this.props.children, noop); // because the items are rerendered every time we call the children // we clear this out each render and it will be populated again as // getItemProps is called. this.clearItems(); // we reset this so we know whether the user calls getRootProps during // this render. If they do then we don't need to do anything, // if they don't then we need to clone the element they return and // apply the props for them. this.getRootProps.called = false; this.getRootProps.refKey = undefined; this.getRootProps.suppressRefError = undefined; // we do something similar for getMenuProps this.getMenuProps.called = false; this.getMenuProps.refKey = undefined; this.getMenuProps.suppressRefError = undefined; // we do something similar for getLabelProps this.getLabelProps.called = false; // and something similar for getInputProps this.getInputProps.called = false; var element = unwrapArray(children(this.getStateAndHelpers())); if (!element) { return null; } if (this.getRootProps.called || this.props.suppressRefError) { if (process.env.NODE_ENV !== 'production' && !this.getRootProps.suppressRefError && !this.props.suppressRefError) { validateGetRootPropsCalledCorrectly(element, this.getRootProps); } return element; } else if (isDOMElement(element)) { // they didn't apply the root props, but we can clone // this and apply the props ourselves return /*#__PURE__*/react.cloneElement(element, this.getRootProps(getElementProps(element))); } /* istanbul ignore else */ if (process.env.NODE_ENV !== 'production') { // they didn't apply the root props, but they need to // otherwise we can't query around the autocomplete throw new Error('downshift: If you return a non-DOM element, you must apply the getRootProps function'); } /* istanbul ignore next */ return undefined; }; return Downshift; }(react.Component); Downshift.defaultProps = { defaultHighlightedIndex: null, defaultIsOpen: false, getA11yStatusMessage: getA11yStatusMessage$1, itemToString: function itemToString(i) { if (i == null) { return ''; } if (process.env.NODE_ENV !== 'production' && isPlainObject(i) && !i.hasOwnProperty('toString')) { // eslint-disable-next-line no-console console.warn('downshift: An object was passed to the default implementation of `itemToString`. You should probably provide your own `itemToString` implementation. Please refer to the `itemToString` API documentation.', 'The object that was passed:', i); } return String(i); }, onStateChange: noop, onInputValueChange: noop, onUserAction: noop, onChange: noop, onSelect: noop, onOuterClick: noop, selectedItemChanged: function selectedItemChanged(prevItem, item) { return prevItem !== item; }, environment: /* istanbul ignore next (ssr) */ typeof window === 'undefined' ? {} : window, stateReducer: function stateReducer(state, stateToSet) { return stateToSet; }, suppressRefError: false, scrollIntoView: scrollIntoView }; Downshift.stateChangeTypes = stateChangeTypes$3; return Downshift; }(); process.env.NODE_ENV !== "production" ? Downshift.propTypes = { children: PropTypes__default["default"].func, defaultHighlightedIndex: PropTypes__default["default"].number, defaultIsOpen: PropTypes__default["default"].bool, initialHighlightedIndex: PropTypes__default["default"].number, initialSelectedItem: PropTypes__default["default"].any, initialInputValue: PropTypes__default["default"].string, initialIsOpen: PropTypes__default["default"].bool, getA11yStatusMessage: PropTypes__default["default"].func, itemToString: PropTypes__default["default"].func, onChange: PropTypes__default["default"].func, onSelect: PropTypes__default["default"].func, onStateChange: PropTypes__default["default"].func, onInputValueChange: PropTypes__default["default"].func, onUserAction: PropTypes__default["default"].func, onOuterClick: PropTypes__default["default"].func, selectedItemChanged: PropTypes__default["default"].func, stateReducer: PropTypes__default["default"].func, itemCount: PropTypes__default["default"].number, id: PropTypes__default["default"].string, environment: PropTypes__default["default"].shape({ addEventListener: PropTypes__default["default"].func, removeEventListener: PropTypes__default["default"].func, document: PropTypes__default["default"].shape({ getElementById: PropTypes__default["default"].func, activeElement: PropTypes__default["default"].any, body: PropTypes__default["default"].any }) }), suppressRefError: PropTypes__default["default"].bool, scrollIntoView: PropTypes__default["default"].func, // things we keep in state for uncontrolled components // but can accept as props for controlled components /* eslint-disable react/no-unused-prop-types */ selectedItem: PropTypes__default["default"].any, isOpen: PropTypes__default["default"].bool, inputValue: PropTypes__default["default"].string, highlightedIndex: PropTypes__default["default"].number, labelId: PropTypes__default["default"].string, inputId: PropTypes__default["default"].string, menuId: PropTypes__default["default"].string, getItemId: PropTypes__default["default"].func /* eslint-enable react/no-unused-prop-types */ } : void 0; var Downshift$1 = Downshift; function validateGetMenuPropsCalledCorrectly(node, _ref12) { var refKey = _ref12.refKey; if (!node) { // eslint-disable-next-line no-console console.error("downshift: The ref prop \"" + refKey + "\" from getMenuProps was not applied correctly on your menu element."); } } function validateGetRootPropsCalledCorrectly(element, _ref13) { var refKey = _ref13.refKey; var refKeySpecified = refKey !== 'ref'; var isComposite = !isDOMElement(element); if (isComposite && !refKeySpecified && !reactIs.isForwardRef(element)) { // eslint-disable-next-line no-console console.error('downshift: You returned a non-DOM element. You must specify a refKey in getRootProps'); } else if (!isComposite && refKeySpecified) { // eslint-disable-next-line no-console console.error("downshift: You returned a DOM element. You should not specify a refKey in getRootProps. You specified \"" + refKey + "\""); } if (!reactIs.isForwardRef(element) && !getElementProps(element)[refKey]) { // eslint-disable-next-line no-console console.error("downshift: You must apply the ref prop \"" + refKey + "\" from getRootProps onto your root element."); } } var _excluded$3 = ["isInitialMount", "highlightedIndex", "items", "environment"]; var dropdownDefaultStateValues = { highlightedIndex: -1, isOpen: false, selectedItem: null, inputValue: '' }; function callOnChangeProps(action, state, newState) { var props = action.props, type = action.type; var changes = {}; Object.keys(state).forEach(function (key) { invokeOnChangeHandler(key, action, state, newState); if (newState[key] !== state[key]) { changes[key] = newState[key]; } }); if (props.onStateChange && Object.keys(changes).length) { props.onStateChange(_extends__default["default"]({ type: type }, changes)); } } function invokeOnChangeHandler(key, action, state, newState) { var props = action.props, type = action.type; var handler = "on" + capitalizeString(key) + "Change"; if (props[handler] && newState[key] !== undefined && newState[key] !== state[key]) { props[handler](_extends__default["default"]({ type: type }, newState)); } } /** * Default state reducer that returns the changes. * * @param {Object} s state. * @param {Object} a action with changes. * @returns {Object} changes. */ function stateReducer(s, a) { return a.changes; } /** * Returns a message to be added to aria-live region when item is selected. * * @param {Object} selectionParameters Parameters required to build the message. * @returns {string} The a11y message. */ function getA11ySelectionMessage(selectionParameters) { var selectedItem = selectionParameters.selectedItem, itemToStringLocal = selectionParameters.itemToString; return selectedItem ? itemToStringLocal(selectedItem) + " has been selected." : ''; } /** * Debounced call for updating the a11y message. */ var updateA11yStatus = debounce(function (getA11yMessage, document) { setStatus(getA11yMessage(), document); }, 200); // istanbul ignore next var useIsomorphicLayoutEffect = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined' ? react.useLayoutEffect : react.useEffect; function useElementIds(_ref) { var _ref$id = _ref.id, id = _ref$id === void 0 ? "downshift-" + generateId() : _ref$id, labelId = _ref.labelId, menuId = _ref.menuId, getItemId = _ref.getItemId, toggleButtonId = _ref.toggleButtonId, inputId = _ref.inputId; var elementIdsRef = react.useRef({ labelId: labelId || id + "-label", menuId: menuId || id + "-menu", getItemId: getItemId || function (index) { return id + "-item-" + index; }, toggleButtonId: toggleButtonId || id + "-toggle-button", inputId: inputId || id + "-input" }); return elementIdsRef.current; } function getItemAndIndex(itemProp, indexProp, items, errorMessage) { var item, index; if (itemProp === undefined) { if (indexProp === undefined) { throw new Error(errorMessage); } item = items[indexProp]; index = indexProp; } else { index = indexProp === undefined ? items.indexOf(itemProp) : indexProp; item = itemProp; } return [item, index]; } function itemToString(item) { return item ? String(item) : ''; } function isAcceptedCharacterKey(key) { return /^\S{1}$/.test(key); } function capitalizeString(string) { return "" + string.slice(0, 1).toUpperCase() + string.slice(1); } function useLatestRef(val) { var ref = react.useRef(val); // technically this is not "concurrent mode safe" because we're manipulating // the value during render (so it's not idempotent). However, the places this // hook is used is to support memoizing callbacks which will be called // *during* render, so we need the latest values *during* render. // If not for this, then we'd probably want to use useLayoutEffect instead. ref.current = val; return ref; } /** * Computes the controlled state using a the previous state, props, * two reducers, one from downshift and an optional one from the user. * Also calls the onChange handlers for state values that have changed. * * @param {Function} reducer Reducer function from downshift. * @param {Object} initialState Initial state of the hook. * @param {Object} props The hook props. * @returns {Array} An array with the state and an action dispatcher. */ function useEnhancedReducer(reducer, initialState, props) { var prevStateRef = react.useRef(); var actionRef = react.useRef(); var enhancedReducer = react.useCallback(function (state, action) { actionRef.current = action; state = getState(state, action.props); var changes = reducer(state, action); var newState = action.props.stateReducer(state, _extends__default["default"]({}, action, { changes: changes })); return newState; }, [reducer]); var _useReducer = react.useReducer(enhancedReducer, initialState), state = _useReducer[0], dispatch = _useReducer[1]; var propsRef = useLatestRef(props); var dispatchWithProps = react.useCallback(function (action) { return dispatch(_extends__default["default"]({ props: propsRef.current }, action)); }, [propsRef]); var action = actionRef.current; react.useEffect(function () { if (action && prevStateRef.current && prevStateRef.current !== state) { callOnChangeProps(action, getState(prevStateRef.current, action.props), state); } prevStateRef.current = state; }, [state, props, action]); return [state, dispatchWithProps]; } /** * Wraps the useEnhancedReducer and applies the controlled prop values before * returning the new state. * * @param {Function} reducer Reducer function from downshift. * @param {Object} initialState Initial state of the hook. * @param {Object} props The hook props. * @returns {Array} An array with the state and an action dispatcher. */ function useControlledReducer$1(reducer, initialState, props) { var _useEnhancedReducer = useEnhancedReducer(reducer, initialState, props), state = _useEnhancedReducer[0], dispatch = _useEnhancedReducer[1]; return [getState(state, props), dispatch]; } var defaultProps$3 = { itemToString: itemToString, stateReducer: stateReducer, getA11ySelectionMessage: getA11ySelectionMessage, scrollIntoView: scrollIntoView, environment: /* istanbul ignore next (ssr) */ typeof window === 'undefined' ? {} : window }; function getDefaultValue$1(props, propKey, defaultStateValues) { if (defaultStateValues === void 0) { defaultStateValues = dropdownDefaultStateValues; } var defaultValue = props["default" + capitalizeString(propKey)]; if (defaultValue !== undefined) { return defaultValue; } return defaultStateValues[propKey]; } function getInitialValue$1(props, propKey, defaultStateValues) { if (defaultStateValues === void 0) { defaultStateValues = dropdownDefaultStateValues; } var value = props[propKey]; if (value !== undefined) { return value; } var initialValue = props["initial" + capitalizeString(propKey)]; if (initialValue !== undefined) { return initialValue; } return getDefaultValue$1(props, propKey, defaultStateValues); } function getInitialState$2(props) { var selectedItem = getInitialValue$1(props, 'selectedItem'); var isOpen = getInitialValue$1(props, 'isOpen'); var highlightedIndex = getInitialValue$1(props, 'highlightedIndex'); var inputValue = getInitialValue$1(props, 'inputValue'); return { highlightedIndex: highlightedIndex < 0 && selectedItem && isOpen ? props.items.indexOf(selectedItem) : highlightedIndex, isOpen: isOpen, selectedItem: selectedItem, inputValue: inputValue }; } function getHighlightedIndexOnOpen(props, state, offset) { var items = props.items, initialHighlightedIndex = props.initialHighlightedIndex, defaultHighlightedIndex = props.defaultHighlightedIndex; var selectedItem = state.selectedItem, highlightedIndex = state.highlightedIndex; if (items.length === 0) { return -1; } // initialHighlightedIndex will give value to highlightedIndex on initial state only. if (initialHighlightedIndex !== undefined && highlightedIndex === initialHighlightedIndex) { return initialHighlightedIndex; } if (defaultHighlightedIndex !== undefined) { return defaultHighlightedIndex; } if (selectedItem) { return items.indexOf(selectedItem); } if (offset === 0) { return -1; } return offset < 0 ? items.length - 1 : 0; } /** * Reuse the movement tracking of mouse and touch events. * * @param {boolean} isOpen Whether the dropdown is open or not. * @param {Array} downshiftElementRefs Downshift element refs to track movement (toggleButton, menu etc.) * @param {Object} environment Environment where component/hook exists. * @param {Function} handleBlur Handler on blur from mouse or touch. * @returns {Object} Ref containing whether mouseDown or touchMove event is happening */ function useMouseAndTouchTracker(isOpen, downshiftElementRefs, environment, handleBlur) { var mouseAndTouchTrackersRef = react.useRef({ isMouseDown: false, isTouchMove: false }); react.useEffect(function () { if ((environment == null ? void 0 : environment.addEventListener) == null) { return; } // The same strategy for checking if a click occurred inside or outside downshift // as in downshift.js. var onMouseDown = function onMouseDown() { mouseAndTouchTrackersRef.current.isMouseDown = true; }; var onMouseUp = function onMouseUp(event) { mouseAndTouchTrackersRef.current.isMouseDown = false; if (isOpen && !targetWithinDownshift(event.target, downshiftElementRefs.map(function (ref) { return ref.current; }), environment)) { handleBlur(); } }; var onTouchStart = function onTouchStart() { mouseAndTouchTrackersRef.current.isTouchMove = false; }; var onTouchMove = function onTouchMove() { mouseAndTouchTrackersRef.current.isTouchMove = true; }; var onTouchEnd = function onTouchEnd(event) { if (isOpen && !mouseAndTouchTrackersRef.current.isTouchMove && !targetWithinDownshift(event.target, downshiftElementRefs.map(function (ref) { return ref.current; }), environment, false)) { handleBlur(); } }; environment.addEventListener('mousedown', onMouseDown); environment.addEventListener('mouseup', onMouseUp); environment.addEventListener('touchstart', onTouchStart); environment.addEventListener('touchmove', onTouchMove); environment.addEventListener('touchend', onTouchEnd); // eslint-disable-next-line consistent-return return function cleanup() { environment.removeEventListener('mousedown', onMouseDown); environment.removeEventListener('mouseup', onMouseUp); environment.removeEventListener('touchstart', onTouchStart); environment.removeEventListener('touchmove', onTouchMove); environment.removeEventListener('touchend', onTouchEnd); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [isOpen, environment]); return mouseAndTouchTrackersRef; } /* istanbul ignore next */ // eslint-disable-next-line import/no-mutable-exports var useGetterPropsCalledChecker = function useGetterPropsCalledChecker() { return noop; }; /** * Custom hook that checks if getter props are called correctly. * * @param {...any} propKeys Getter prop names to be handled. * @returns {Function} Setter function called inside getter props to set call information. */ /* istanbul ignore next */ if (process.env.NODE_ENV !== 'production') { useGetterPropsCalledChecker = function useGetterPropsCalledChecker() { var isInitialMountRef = react.useRef(true); for (var _len = arguments.length, propKeys = new Array(_len), _key = 0; _key < _len; _key++) { propKeys[_key] = arguments[_key]; } var getterPropsCalledRef = react.useRef(propKeys.reduce(function (acc, propKey) { acc[propKey] = {}; return acc; }, {})); react.useEffect(function () { Object.keys(getterPropsCalledRef.current).forEach(function (propKey) { var propCallInfo = getterPropsCalledRef.current[propKey]; if (isInitialMountRef.current) { if (!Object.keys(propCallInfo).length) { // eslint-disable-next-line no-console console.error("downshift: You forgot to call the " + propKey + " getter function on your component / element."); return; } } var suppressRefError = propCallInfo.suppressRefError, refKey = propCallInfo.refKey, elementRef = propCallInfo.elementRef; if ((!elementRef || !elementRef.current) && !suppressRefError) { // eslint-disable-next-line no-console console.error("downshift: The ref prop \"" + refKey + "\" from " + propKey + " was not applied correctly on your element."); } }); isInitialMountRef.current = false; }); var setGetterPropCallInfo = react.useCallback(function (propKey, suppressRefError, refKey, elementRef) { getterPropsCalledRef.current[propKey] = { suppressRefError: suppressRefError, refKey: refKey, elementRef: elementRef }; }, []); return setGetterPropCallInfo; }; } function useA11yMessageSetter(getA11yMessage, dependencyArray, _ref2) { var isInitialMount = _ref2.isInitialMount, highlightedIndex = _ref2.highlightedIndex, items = _ref2.items, environment = _ref2.environment, rest = _objectWithoutPropertiesLoose__default["default"](_ref2, _excluded$3); // Sets a11y status message on changes in state. react.useEffect(function () { if (isInitialMount || false) { return; } updateA11yStatus(function () { return getA11yMessage(_extends__default["default"]({ highlightedIndex: highlightedIndex, highlightedItem: items[highlightedIndex], resultCount: items.length }, rest)); }, environment.document); // eslint-disable-next-line react-hooks/exhaustive-deps }, dependencyArray); } function useScrollIntoView(_ref3) { var highlightedIndex = _ref3.highlightedIndex, isOpen = _ref3.isOpen, itemRefs = _ref3.itemRefs, getItemNodeFromIndex = _ref3.getItemNodeFromIndex, menuElement = _ref3.menuElement, scrollIntoViewProp = _ref3.scrollIntoView; // used not to scroll on highlight by mouse. var shouldScrollRef = react.useRef(true); // Scroll on highlighted item if change comes from keyboard. useIsomorphicLayoutEffect(function () { if (highlightedIndex < 0 || !isOpen || !Object.keys(itemRefs.current).length) { return; } if (shouldScrollRef.current === false) { shouldScrollRef.current = true; } else { scrollIntoViewProp(getItemNodeFromIndex(highlightedIndex), menuElement); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [highlightedIndex]); return shouldScrollRef; } // eslint-disable-next-line import/no-mutable-exports var useControlPropsValidator = noop; /* istanbul ignore next */ if (process.env.NODE_ENV !== 'production') { useControlPropsValidator = function useControlPropsValidator(_ref4) { var isInitialMount = _ref4.isInitialMount, props = _ref4.props, state = _ref4.state; // used for checking when props are moving from controlled to uncontrolled. var prevPropsRef = react.useRef(props); react.useEffect(function () { if (isInitialMount) { return; } validateControlledUnchanged(state, prevPropsRef.current, props); prevPropsRef.current = props; }, [state, props, isInitialMount]); }; } /** * Handles selection on Enter / Alt + ArrowUp. Closes the menu and resets the highlighted index, unless there is a highlighted. * In that case, selects the item and resets to defaults for open state and highlighted idex. * @param {Object} props The useCombobox props. * @param {number} highlightedIndex The index from the state. * @param {boolean} inputValue Also return the input value for state. * @returns The changes for the state. */ function getChangesOnSelection(props, highlightedIndex, inputValue) { var _props$items; if (inputValue === void 0) { inputValue = true; } var shouldSelect = ((_props$items = props.items) == null ? void 0 : _props$items.length) && highlightedIndex >= 0; return _extends__default["default"]({ isOpen: false, highlightedIndex: -1 }, shouldSelect && _extends__default["default"]({ selectedItem: props.items[highlightedIndex], isOpen: getDefaultValue$1(props, 'isOpen'), highlightedIndex: getDefaultValue$1(props, 'highlightedIndex') }, inputValue && { inputValue: props.itemToString(props.items[highlightedIndex]) })); } function downshiftCommonReducer(state, action, stateChangeTypes) { var type = action.type, props = action.props; var changes; switch (type) { case stateChangeTypes.ItemMouseMove: changes = { highlightedIndex: action.disabled ? -1 : action.index }; break; case stateChangeTypes.MenuMouseLeave: changes = { highlightedIndex: -1 }; break; case stateChangeTypes.ToggleButtonClick: case stateChangeTypes.FunctionToggleMenu: changes = { isOpen: !state.isOpen, highlightedIndex: state.isOpen ? -1 : getHighlightedIndexOnOpen(props, state, 0) }; break; case stateChangeTypes.FunctionOpenMenu: changes = { isOpen: true, highlightedIndex: getHighlightedIndexOnOpen(props, state, 0) }; break; case stateChangeTypes.FunctionCloseMenu: changes = { isOpen: false }; break; case stateChangeTypes.FunctionSetHighlightedIndex: changes = { highlightedIndex: action.highlightedIndex }; break; case stateChangeTypes.FunctionSetInputValue: changes = { inputValue: action.inputValue }; break; case stateChangeTypes.FunctionReset: changes = { highlightedIndex: getDefaultValue$1(props, 'highlightedIndex'), isOpen: getDefaultValue$1(props, 'isOpen'), selectedItem: getDefaultValue$1(props, 'selectedItem'), inputValue: getDefaultValue$1(props, 'inputValue') }; break; default: throw new Error('Reducer called without proper action type.'); } return _extends__default["default"]({}, state, changes); } /* eslint-enable complexity */ function getItemIndexByCharacterKey(_a) { var keysSoFar = _a.keysSoFar, highlightedIndex = _a.highlightedIndex, items = _a.items, itemToString = _a.itemToString, getItemNodeFromIndex = _a.getItemNodeFromIndex; var lowerCasedKeysSoFar = keysSoFar.toLowerCase(); for (var index = 0; index < items.length; index++) { // if we already have a search query in progress, we also consider the current highlighted item. var offsetIndex = (index + highlightedIndex + (keysSoFar.length < 2 ? 1 : 0)) % items.length; var item = items[offsetIndex]; if (item !== undefined && itemToString(item).toLowerCase().startsWith(lowerCasedKeysSoFar)) { var element = getItemNodeFromIndex(offsetIndex); if (!(element === null || element === void 0 ? void 0 : element.hasAttribute('disabled'))) { return offsetIndex; } } } return highlightedIndex; } var propTypes$2 = { items: PropTypes__default["default"].array.isRequired, itemToString: PropTypes__default["default"].func, getA11yStatusMessage: PropTypes__default["default"].func, getA11ySelectionMessage: PropTypes__default["default"].func, highlightedIndex: PropTypes__default["default"].number, defaultHighlightedIndex: PropTypes__default["default"].number, initialHighlightedIndex: PropTypes__default["default"].number, isOpen: PropTypes__default["default"].bool, defaultIsOpen: PropTypes__default["default"].bool, initialIsOpen: PropTypes__default["default"].bool, selectedItem: PropTypes__default["default"].any, initialSelectedItem: PropTypes__default["default"].any, defaultSelectedItem: PropTypes__default["default"].any, id: PropTypes__default["default"].string, labelId: PropTypes__default["default"].string, menuId: PropTypes__default["default"].string, getItemId: PropTypes__default["default"].func, toggleButtonId: PropTypes__default["default"].string, stateReducer: PropTypes__default["default"].func, onSelectedItemChange: PropTypes__default["default"].func, onHighlightedIndexChange: PropTypes__default["default"].func, onStateChange: PropTypes__default["default"].func, onIsOpenChange: PropTypes__default["default"].func, environment: PropTypes__default["default"].shape({ addEventListener: PropTypes__default["default"].func, removeEventListener: PropTypes__default["default"].func, document: PropTypes__default["default"].shape({ getElementById: PropTypes__default["default"].func, activeElement: PropTypes__default["default"].any, body: PropTypes__default["default"].any }) }) }; /** * Default implementation for status message. Only added when menu is open. * Will specift if there are results in the list, and if so, how many, * and what keys are relevant. * * @param {Object} param the downshift state and other relevant properties * @return {String} the a11y status message */ function getA11yStatusMessage(_a) { var isOpen = _a.isOpen, resultCount = _a.resultCount, previousResultCount = _a.previousResultCount; if (!isOpen) { return ''; } if (!resultCount) { return 'No results are available.'; } if (resultCount !== previousResultCount) { return "".concat(resultCount, " result").concat(resultCount === 1 ? ' is' : 's are', " available, use up and down arrow keys to navigate. Press Enter or Space Bar keys to select."); } return ''; } var defaultProps$2 = tslib.__assign(tslib.__assign({}, defaultProps$3), { getA11yStatusMessage: getA11yStatusMessage }); // eslint-disable-next-line import/no-mutable-exports var validatePropTypes$2 = noop; /* istanbul ignore next */ if (process.env.NODE_ENV !== 'production') { validatePropTypes$2 = function (options, caller) { PropTypes__default["default"].checkPropTypes(propTypes$2, options, 'prop', caller.name); }; } var ToggleButtonClick$1 = process.env.NODE_ENV !== "production" ? '__togglebutton_click__' : 0; var ToggleButtonKeyDownArrowDown = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_arrow_down__' : 1; var ToggleButtonKeyDownArrowUp = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_arrow_up__' : 2; var ToggleButtonKeyDownCharacter = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_character__' : 3; var ToggleButtonKeyDownEscape = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_escape__' : 4; var ToggleButtonKeyDownHome = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_home__' : 5; var ToggleButtonKeyDownEnd = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_end__' : 6; var ToggleButtonKeyDownEnter = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_enter__' : 7; var ToggleButtonKeyDownSpaceButton = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_space_button__' : 8; var ToggleButtonKeyDownPageUp = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_page_up__' : 9; var ToggleButtonKeyDownPageDown = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_page_down__' : 10; var ToggleButtonBlur = process.env.NODE_ENV !== "production" ? '__togglebutton_blur__' : 11; var MenuMouseLeave$1 = process.env.NODE_ENV !== "production" ? '__menu_mouse_leave__' : 12; var ItemMouseMove$1 = process.env.NODE_ENV !== "production" ? '__item_mouse_move__' : 13; var ItemClick$1 = process.env.NODE_ENV !== "production" ? '__item_click__' : 14; var FunctionToggleMenu$1 = process.env.NODE_ENV !== "production" ? '__function_toggle_menu__' : 15; var FunctionOpenMenu$1 = process.env.NODE_ENV !== "production" ? '__function_open_menu__' : 16; var FunctionCloseMenu$1 = process.env.NODE_ENV !== "production" ? '__function_close_menu__' : 17; var FunctionSetHighlightedIndex$1 = process.env.NODE_ENV !== "production" ? '__function_set_highlighted_index__' : 18; var FunctionSelectItem$1 = process.env.NODE_ENV !== "production" ? '__function_select_item__' : 19; var FunctionSetInputValue$1 = process.env.NODE_ENV !== "production" ? '__function_set_input_value__' : 20; var FunctionReset$2 = process.env.NODE_ENV !== "production" ? '__function_reset__' : 21; var stateChangeTypes$2 = /*#__PURE__*/Object.freeze({ __proto__: null, ToggleButtonClick: ToggleButtonClick$1, ToggleButtonKeyDownArrowDown: ToggleButtonKeyDownArrowDown, ToggleButtonKeyDownArrowUp: ToggleButtonKeyDownArrowUp, ToggleButtonKeyDownCharacter: ToggleButtonKeyDownCharacter, ToggleButtonKeyDownEscape: ToggleButtonKeyDownEscape, ToggleButtonKeyDownHome: ToggleButtonKeyDownHome, ToggleButtonKeyDownEnd: ToggleButtonKeyDownEnd, ToggleButtonKeyDownEnter: ToggleButtonKeyDownEnter, ToggleButtonKeyDownSpaceButton: ToggleButtonKeyDownSpaceButton, ToggleButtonKeyDownPageUp: ToggleButtonKeyDownPageUp, ToggleButtonKeyDownPageDown: ToggleButtonKeyDownPageDown, ToggleButtonBlur: ToggleButtonBlur, MenuMouseLeave: MenuMouseLeave$1, ItemMouseMove: ItemMouseMove$1, ItemClick: ItemClick$1, FunctionToggleMenu: FunctionToggleMenu$1, FunctionOpenMenu: FunctionOpenMenu$1, FunctionCloseMenu: FunctionCloseMenu$1, FunctionSetHighlightedIndex: FunctionSetHighlightedIndex$1, FunctionSelectItem: FunctionSelectItem$1, FunctionSetInputValue: FunctionSetInputValue$1, FunctionReset: FunctionReset$2 }); /* eslint-disable complexity */ function downshiftSelectReducer(state, action) { var _props$items; var type = action.type, props = action.props, altKey = action.altKey; var changes; switch (type) { case ItemClick$1: changes = { isOpen: getDefaultValue$1(props, 'isOpen'), highlightedIndex: getDefaultValue$1(props, 'highlightedIndex'), selectedItem: props.items[action.index] }; break; case ToggleButtonKeyDownCharacter: { var lowercasedKey = action.key; var inputValue = "" + state.inputValue + lowercasedKey; var prevHighlightedIndex = !state.isOpen && state.selectedItem ? props.items.indexOf(state.selectedItem) : state.highlightedIndex; var highlightedIndex = getItemIndexByCharacterKey({ keysSoFar: inputValue, highlightedIndex: prevHighlightedIndex, items: props.items, itemToString: props.itemToString, getItemNodeFromIndex: action.getItemNodeFromIndex }); changes = { inputValue: inputValue, highlightedIndex: highlightedIndex, isOpen: true }; } break; case ToggleButtonKeyDownArrowDown: { var _highlightedIndex = state.isOpen ? getNextWrappingIndex(1, state.highlightedIndex, props.items.length, action.getItemNodeFromIndex, false) : altKey && state.selectedItem == null ? -1 : getHighlightedIndexOnOpen(props, state, 1); changes = { highlightedIndex: _highlightedIndex, isOpen: true }; } break; case ToggleButtonKeyDownArrowUp: if (state.isOpen && altKey) { changes = getChangesOnSelection(props, state.highlightedIndex, false); } else { var _highlightedIndex2 = state.isOpen ? getNextWrappingIndex(-1, state.highlightedIndex, props.items.length, action.getItemNodeFromIndex, false) : getHighlightedIndexOnOpen(props, state, -1); changes = { highlightedIndex: _highlightedIndex2, isOpen: true }; } break; // only triggered when menu is open. case ToggleButtonKeyDownEnter: case ToggleButtonKeyDownSpaceButton: changes = getChangesOnSelection(props, state.highlightedIndex, false); break; case ToggleButtonKeyDownHome: changes = { highlightedIndex: getNextNonDisabledIndex(1, 0, props.items.length, action.getItemNodeFromIndex, false), isOpen: true }; break; case ToggleButtonKeyDownEnd: changes = { highlightedIndex: getNextNonDisabledIndex(-1, props.items.length - 1, props.items.length, action.getItemNodeFromIndex, false), isOpen: true }; break; case ToggleButtonKeyDownPageUp: changes = { highlightedIndex: getNextWrappingIndex(-10, state.highlightedIndex, props.items.length, action.getItemNodeFromIndex, false) }; break; case ToggleButtonKeyDownPageDown: changes = { highlightedIndex: getNextWrappingIndex(10, state.highlightedIndex, props.items.length, action.getItemNodeFromIndex, false) }; break; case ToggleButtonKeyDownEscape: changes = { isOpen: false, highlightedIndex: -1 }; break; case ToggleButtonBlur: changes = _extends__default["default"]({ isOpen: false, highlightedIndex: -1 }, state.highlightedIndex >= 0 && ((_props$items = props.items) == null ? void 0 : _props$items.length) && { selectedItem: props.items[state.highlightedIndex] }); break; case FunctionSelectItem$1: changes = { selectedItem: action.selectedItem }; break; default: return downshiftCommonReducer(state, action, stateChangeTypes$2); } return _extends__default["default"]({}, state, changes); } /* eslint-enable complexity */ var _excluded$2 = ["onMouseLeave", "refKey", "onKeyDown", "onBlur", "ref"], _excluded2$2 = ["onBlur", "onClick", "onPress", "onKeyDown", "refKey", "ref"], _excluded3$1 = ["item", "index", "onMouseMove", "onClick", "onPress", "refKey", "ref", "disabled"]; useSelect.stateChangeTypes = stateChangeTypes$2; function useSelect(userProps) { if (userProps === void 0) { userProps = {}; } validatePropTypes$2(userProps, useSelect); // Props defaults and destructuring. var props = _extends__default["default"]({}, defaultProps$2, userProps); var items = props.items, scrollIntoView = props.scrollIntoView, environment = props.environment, itemToString = props.itemToString, getA11ySelectionMessage = props.getA11ySelectionMessage, getA11yStatusMessage = props.getA11yStatusMessage; // Initial state depending on controlled props. var initialState = getInitialState$2(props); var _useControlledReducer = useControlledReducer$1(downshiftSelectReducer, initialState, props), state = _useControlledReducer[0], dispatch = _useControlledReducer[1]; var isOpen = state.isOpen, highlightedIndex = state.highlightedIndex, selectedItem = state.selectedItem, inputValue = state.inputValue; // Element efs. var toggleButtonRef = react.useRef(null); var menuRef = react.useRef(null); var itemRefs = react.useRef({}); // used to keep the inputValue clearTimeout object between renders. var clearTimeoutRef = react.useRef(null); // prevent id re-generation between renders. var elementIds = useElementIds(props); // used to keep track of how many items we had on previous cycle. var previousResultCountRef = react.useRef(); var isInitialMountRef = react.useRef(true); // utility callback to get item element. var latest = useLatestRef({ state: state, props: props }); // Some utils. var getItemNodeFromIndex = react.useCallback(function (index) { return itemRefs.current[elementIds.getItemId(index)]; }, [elementIds]); // Effects. // Sets a11y status message on changes in state. useA11yMessageSetter(getA11yStatusMessage, [isOpen, highlightedIndex, inputValue, items], _extends__default["default"]({ isInitialMount: isInitialMountRef.current, previousResultCount: previousResultCountRef.current, items: items, environment: environment, itemToString: itemToString }, state)); // Sets a11y status message on changes in selectedItem. useA11yMessageSetter(getA11ySelectionMessage, [selectedItem], _extends__default["default"]({ isInitialMount: isInitialMountRef.current, previousResultCount: previousResultCountRef.current, items: items, environment: environment, itemToString: itemToString }, state)); // Scroll on highlighted item if change comes from keyboard. var shouldScrollRef = useScrollIntoView({ menuElement: menuRef.current, highlightedIndex: highlightedIndex, isOpen: isOpen, itemRefs: itemRefs, scrollIntoView: scrollIntoView, getItemNodeFromIndex: getItemNodeFromIndex }); // Sets cleanup for the keysSoFar callback, debounded after 500ms. react.useEffect(function () { // init the clean function here as we need access to dispatch. clearTimeoutRef.current = debounce(function (outerDispatch) { outerDispatch({ type: FunctionSetInputValue$1, inputValue: '' }); }, 500); // Cancel any pending debounced calls on mount return function () { clearTimeoutRef.current.cancel(); }; }, []); // Invokes the keysSoFar callback set up above. react.useEffect(function () { if (!inputValue) { return; } clearTimeoutRef.current(dispatch); }, [dispatch, inputValue]); useControlPropsValidator({ isInitialMount: isInitialMountRef.current, props: props, state: state }); react.useEffect(function () { if (isInitialMountRef.current) { return; } previousResultCountRef.current = items.length; }); // Add mouse/touch events to document. var mouseAndTouchTrackersRef = useMouseAndTouchTracker(isOpen, [menuRef, toggleButtonRef], environment, function () { dispatch({ type: ToggleButtonBlur }); }); var setGetterPropCallInfo = useGetterPropsCalledChecker('getMenuProps', 'getToggleButtonProps'); // Make initial ref false. react.useEffect(function () { isInitialMountRef.current = false; return function () { isInitialMountRef.current = true; }; }, []); // Reset itemRefs on close. react.useEffect(function () { if (!isOpen) { itemRefs.current = {}; } }, [isOpen]); // Event handler functions. var toggleButtonKeyDownHandlers = react.useMemo(function () { return { ArrowDown: function ArrowDown(event) { event.preventDefault(); dispatch({ type: ToggleButtonKeyDownArrowDown, getItemNodeFromIndex: getItemNodeFromIndex, altKey: event.altKey }); }, ArrowUp: function ArrowUp(event) { event.preventDefault(); dispatch({ type: ToggleButtonKeyDownArrowUp, getItemNodeFromIndex: getItemNodeFromIndex, altKey: event.altKey }); }, Home: function Home(event) { event.preventDefault(); dispatch({ type: ToggleButtonKeyDownHome, getItemNodeFromIndex: getItemNodeFromIndex }); }, End: function End(event) { event.preventDefault(); dispatch({ type: ToggleButtonKeyDownEnd, getItemNodeFromIndex: getItemNodeFromIndex }); }, Escape: function Escape() { if (latest.current.state.isOpen) { dispatch({ type: ToggleButtonKeyDownEscape }); } }, Enter: function Enter(event) { event.preventDefault(); dispatch({ type: latest.current.state.isOpen ? ToggleButtonKeyDownEnter : ToggleButtonClick$1 }); }, PageUp: function PageUp(event) { if (latest.current.state.isOpen) { event.preventDefault(); dispatch({ type: ToggleButtonKeyDownPageUp, getItemNodeFromIndex: getItemNodeFromIndex }); } }, PageDown: function PageDown(event) { if (latest.current.state.isOpen) { event.preventDefault(); dispatch({ type: ToggleButtonKeyDownPageDown, getItemNodeFromIndex: getItemNodeFromIndex }); } }, ' ': function _(event) { event.preventDefault(); var currentState = latest.current.state; if (!currentState.isOpen) { dispatch({ type: ToggleButtonClick$1 }); return; } if (currentState.inputValue) { dispatch({ type: ToggleButtonKeyDownCharacter, key: ' ', getItemNodeFromIndex: getItemNodeFromIndex }); } else { dispatch({ type: ToggleButtonKeyDownSpaceButton }); } } }; }, [dispatch, getItemNodeFromIndex, latest]); // Action functions. var toggleMenu = react.useCallback(function () { dispatch({ type: FunctionToggleMenu$1 }); }, [dispatch]); var closeMenu = react.useCallback(function () { dispatch({ type: FunctionCloseMenu$1 }); }, [dispatch]); var openMenu = react.useCallback(function () { dispatch({ type: FunctionOpenMenu$1 }); }, [dispatch]); var setHighlightedIndex = react.useCallback(function (newHighlightedIndex) { dispatch({ type: FunctionSetHighlightedIndex$1, highlightedIndex: newHighlightedIndex }); }, [dispatch]); var selectItem = react.useCallback(function (newSelectedItem) { dispatch({ type: FunctionSelectItem$1, selectedItem: newSelectedItem }); }, [dispatch]); var reset = react.useCallback(function () { dispatch({ type: FunctionReset$2 }); }, [dispatch]); var setInputValue = react.useCallback(function (newInputValue) { dispatch({ type: FunctionSetInputValue$1, inputValue: newInputValue }); }, [dispatch]); // Getter functions. var getLabelProps = react.useCallback(function (labelProps) { return _extends__default["default"]({ id: elementIds.labelId, htmlFor: elementIds.toggleButtonId }, labelProps); }, [elementIds]); var getMenuProps = react.useCallback(function (_temp, _temp2) { var _extends2; var _ref = _temp === void 0 ? {} : _temp, onMouseLeave = _ref.onMouseLeave, _ref$refKey = _ref.refKey, refKey = _ref$refKey === void 0 ? 'ref' : _ref$refKey; _ref.onKeyDown; _ref.onBlur; var ref = _ref.ref, rest = _objectWithoutPropertiesLoose__default["default"](_ref, _excluded$2); var _ref2 = _temp2 === void 0 ? {} : _temp2, _ref2$suppressRefErro = _ref2.suppressRefError, suppressRefError = _ref2$suppressRefErro === void 0 ? false : _ref2$suppressRefErro; var menuHandleMouseLeave = function menuHandleMouseLeave() { dispatch({ type: MenuMouseLeave$1 }); }; setGetterPropCallInfo('getMenuProps', suppressRefError, refKey, menuRef); return _extends__default["default"]((_extends2 = {}, _extends2[refKey] = handleRefs(ref, function (menuNode) { menuRef.current = menuNode; }), _extends2.id = elementIds.menuId, _extends2.role = 'listbox', _extends2['aria-labelledby'] = rest && rest['aria-label'] ? undefined : "" + elementIds.labelId, _extends2.onMouseLeave = callAllEventHandlers(onMouseLeave, menuHandleMouseLeave), _extends2), rest); }, [dispatch, setGetterPropCallInfo, elementIds]); var getToggleButtonProps = react.useCallback(function (_temp3, _temp4) { var _extends3; var _ref3 = _temp3 === void 0 ? {} : _temp3, onBlur = _ref3.onBlur, onClick = _ref3.onClick; _ref3.onPress; var onKeyDown = _ref3.onKeyDown, _ref3$refKey = _ref3.refKey, refKey = _ref3$refKey === void 0 ? 'ref' : _ref3$refKey, ref = _ref3.ref, rest = _objectWithoutPropertiesLoose__default["default"](_ref3, _excluded2$2); var _ref4 = _temp4 === void 0 ? {} : _temp4, _ref4$suppressRefErro = _ref4.suppressRefError, suppressRefError = _ref4$suppressRefErro === void 0 ? false : _ref4$suppressRefErro; var latestState = latest.current.state; var toggleButtonHandleClick = function toggleButtonHandleClick() { dispatch({ type: ToggleButtonClick$1 }); }; var toggleButtonHandleBlur = function toggleButtonHandleBlur() { if (latestState.isOpen && !mouseAndTouchTrackersRef.current.isMouseDown) { dispatch({ type: ToggleButtonBlur }); } }; var toggleButtonHandleKeyDown = function toggleButtonHandleKeyDown(event) { var key = normalizeArrowKey(event); if (key && toggleButtonKeyDownHandlers[key]) { toggleButtonKeyDownHandlers[key](event); } else if (isAcceptedCharacterKey(key)) { dispatch({ type: ToggleButtonKeyDownCharacter, key: key, getItemNodeFromIndex: getItemNodeFromIndex }); } }; var toggleProps = _extends__default["default"]((_extends3 = {}, _extends3[refKey] = handleRefs(ref, function (toggleButtonNode) { toggleButtonRef.current = toggleButtonNode; }), _extends3['aria-activedescendant'] = latestState.isOpen && latestState.highlightedIndex > -1 ? elementIds.getItemId(latestState.highlightedIndex) : '', _extends3['aria-controls'] = elementIds.menuId, _extends3['aria-expanded'] = latest.current.state.isOpen, _extends3['aria-haspopup'] = 'listbox', _extends3['aria-labelledby'] = rest && rest['aria-label'] ? undefined : "" + elementIds.labelId, _extends3.id = elementIds.toggleButtonId, _extends3.role = 'combobox', _extends3.tabIndex = 0, _extends3.onBlur = callAllEventHandlers(onBlur, toggleButtonHandleBlur), _extends3), rest); if (!rest.disabled) { /* istanbul ignore if (react-native) */ { toggleProps.onClick = callAllEventHandlers(onClick, toggleButtonHandleClick); toggleProps.onKeyDown = callAllEventHandlers(onKeyDown, toggleButtonHandleKeyDown); } } setGetterPropCallInfo('getToggleButtonProps', suppressRefError, refKey, toggleButtonRef); return toggleProps; }, [latest, elementIds, setGetterPropCallInfo, dispatch, mouseAndTouchTrackersRef, toggleButtonKeyDownHandlers, getItemNodeFromIndex]); var getItemProps = react.useCallback(function (_temp5) { var _extends4; var _ref5 = _temp5 === void 0 ? {} : _temp5, itemProp = _ref5.item, indexProp = _ref5.index, onMouseMove = _ref5.onMouseMove, onClick = _ref5.onClick; _ref5.onPress; var _ref5$refKey = _ref5.refKey, refKey = _ref5$refKey === void 0 ? 'ref' : _ref5$refKey, ref = _ref5.ref, disabled = _ref5.disabled, rest = _objectWithoutPropertiesLoose__default["default"](_ref5, _excluded3$1); var _latest$current = latest.current, latestState = _latest$current.state, latestProps = _latest$current.props; var _getItemAndIndex = getItemAndIndex(itemProp, indexProp, latestProps.items, 'Pass either item or index to getItemProps!'), item = _getItemAndIndex[0], index = _getItemAndIndex[1]; var itemHandleMouseMove = function itemHandleMouseMove() { if (index === latestState.highlightedIndex) { return; } shouldScrollRef.current = false; dispatch({ type: ItemMouseMove$1, index: index, disabled: disabled }); }; var itemHandleClick = function itemHandleClick() { dispatch({ type: ItemClick$1, index: index }); }; var itemProps = _extends__default["default"]((_extends4 = { disabled: disabled, role: 'option', 'aria-selected': "" + (item === selectedItem), id: elementIds.getItemId(index) }, _extends4[refKey] = handleRefs(ref, function (itemNode) { if (itemNode) { itemRefs.current[elementIds.getItemId(index)] = itemNode; } }), _extends4), rest); if (!disabled) { /* istanbul ignore next (react-native) */ { itemProps.onClick = callAllEventHandlers(onClick, itemHandleClick); } } itemProps.onMouseMove = callAllEventHandlers(onMouseMove, itemHandleMouseMove); return itemProps; }, [latest, selectedItem, elementIds, shouldScrollRef, dispatch]); return { // prop getters. getToggleButtonProps: getToggleButtonProps, getLabelProps: getLabelProps, getMenuProps: getMenuProps, getItemProps: getItemProps, // actions. toggleMenu: toggleMenu, openMenu: openMenu, closeMenu: closeMenu, setHighlightedIndex: setHighlightedIndex, selectItem: selectItem, reset: reset, setInputValue: setInputValue, // state. highlightedIndex: highlightedIndex, isOpen: isOpen, selectedItem: selectedItem, inputValue: inputValue }; } var InputKeyDownArrowDown = process.env.NODE_ENV !== "production" ? '__input_keydown_arrow_down__' : 0; var InputKeyDownArrowUp = process.env.NODE_ENV !== "production" ? '__input_keydown_arrow_up__' : 1; var InputKeyDownEscape = process.env.NODE_ENV !== "production" ? '__input_keydown_escape__' : 2; var InputKeyDownHome = process.env.NODE_ENV !== "production" ? '__input_keydown_home__' : 3; var InputKeyDownEnd = process.env.NODE_ENV !== "production" ? '__input_keydown_end__' : 4; var InputKeyDownPageUp = process.env.NODE_ENV !== "production" ? '__input_keydown_page_up__' : 5; var InputKeyDownPageDown = process.env.NODE_ENV !== "production" ? '__input_keydown_page_down__' : 6; var InputKeyDownEnter = process.env.NODE_ENV !== "production" ? '__input_keydown_enter__' : 7; var InputChange = process.env.NODE_ENV !== "production" ? '__input_change__' : 8; var InputBlur = process.env.NODE_ENV !== "production" ? '__input_blur__' : 9; var InputFocus = process.env.NODE_ENV !== "production" ? '__input_focus__' : 10; var MenuMouseLeave = process.env.NODE_ENV !== "production" ? '__menu_mouse_leave__' : 11; var ItemMouseMove = process.env.NODE_ENV !== "production" ? '__item_mouse_move__' : 12; var ItemClick = process.env.NODE_ENV !== "production" ? '__item_click__' : 13; var ToggleButtonClick = process.env.NODE_ENV !== "production" ? '__togglebutton_click__' : 14; var FunctionToggleMenu = process.env.NODE_ENV !== "production" ? '__function_toggle_menu__' : 15; var FunctionOpenMenu = process.env.NODE_ENV !== "production" ? '__function_open_menu__' : 16; var FunctionCloseMenu = process.env.NODE_ENV !== "production" ? '__function_close_menu__' : 17; var FunctionSetHighlightedIndex = process.env.NODE_ENV !== "production" ? '__function_set_highlighted_index__' : 18; var FunctionSelectItem = process.env.NODE_ENV !== "production" ? '__function_select_item__' : 19; var FunctionSetInputValue = process.env.NODE_ENV !== "production" ? '__function_set_input_value__' : 20; var FunctionReset$1 = process.env.NODE_ENV !== "production" ? '__function_reset__' : 21; var ControlledPropUpdatedSelectedItem = process.env.NODE_ENV !== "production" ? '__controlled_prop_updated_selected_item__' : 22; var stateChangeTypes$1 = /*#__PURE__*/Object.freeze({ __proto__: null, InputKeyDownArrowDown: InputKeyDownArrowDown, InputKeyDownArrowUp: InputKeyDownArrowUp, InputKeyDownEscape: InputKeyDownEscape, InputKeyDownHome: InputKeyDownHome, InputKeyDownEnd: InputKeyDownEnd, InputKeyDownPageUp: InputKeyDownPageUp, InputKeyDownPageDown: InputKeyDownPageDown, InputKeyDownEnter: InputKeyDownEnter, InputChange: InputChange, InputBlur: InputBlur, InputFocus: InputFocus, MenuMouseLeave: MenuMouseLeave, ItemMouseMove: ItemMouseMove, ItemClick: ItemClick, ToggleButtonClick: ToggleButtonClick, FunctionToggleMenu: FunctionToggleMenu, FunctionOpenMenu: FunctionOpenMenu, FunctionCloseMenu: FunctionCloseMenu, FunctionSetHighlightedIndex: FunctionSetHighlightedIndex, FunctionSelectItem: FunctionSelectItem, FunctionSetInputValue: FunctionSetInputValue, FunctionReset: FunctionReset$1, ControlledPropUpdatedSelectedItem: ControlledPropUpdatedSelectedItem }); function getInitialState$1(props) { var initialState = getInitialState$2(props); var selectedItem = initialState.selectedItem; var inputValue = initialState.inputValue; if (inputValue === '' && selectedItem && props.defaultInputValue === undefined && props.initialInputValue === undefined && props.inputValue === undefined) { inputValue = props.itemToString(selectedItem); } return _extends__default["default"]({}, initialState, { inputValue: inputValue }); } var propTypes$1 = { items: PropTypes__default["default"].array.isRequired, itemToString: PropTypes__default["default"].func, selectedItemChanged: PropTypes__default["default"].func, getA11yStatusMessage: PropTypes__default["default"].func, getA11ySelectionMessage: PropTypes__default["default"].func, highlightedIndex: PropTypes__default["default"].number, defaultHighlightedIndex: PropTypes__default["default"].number, initialHighlightedIndex: PropTypes__default["default"].number, isOpen: PropTypes__default["default"].bool, defaultIsOpen: PropTypes__default["default"].bool, initialIsOpen: PropTypes__default["default"].bool, selectedItem: PropTypes__default["default"].any, initialSelectedItem: PropTypes__default["default"].any, defaultSelectedItem: PropTypes__default["default"].any, inputValue: PropTypes__default["default"].string, defaultInputValue: PropTypes__default["default"].string, initialInputValue: PropTypes__default["default"].string, id: PropTypes__default["default"].string, labelId: PropTypes__default["default"].string, menuId: PropTypes__default["default"].string, getItemId: PropTypes__default["default"].func, inputId: PropTypes__default["default"].string, toggleButtonId: PropTypes__default["default"].string, stateReducer: PropTypes__default["default"].func, onSelectedItemChange: PropTypes__default["default"].func, onHighlightedIndexChange: PropTypes__default["default"].func, onStateChange: PropTypes__default["default"].func, onIsOpenChange: PropTypes__default["default"].func, onInputValueChange: PropTypes__default["default"].func, environment: PropTypes__default["default"].shape({ addEventListener: PropTypes__default["default"].func, removeEventListener: PropTypes__default["default"].func, document: PropTypes__default["default"].shape({ getElementById: PropTypes__default["default"].func, activeElement: PropTypes__default["default"].any, body: PropTypes__default["default"].any }) }) }; /** * The useCombobox version of useControlledReducer, which also * checks if the controlled prop selectedItem changed between * renders. If so, it will also update inputValue with its * string equivalent. It uses the common useEnhancedReducer to * compute the rest of the state. * * @param {Function} reducer Reducer function from downshift. * @param {Object} initialState Initial state of the hook. * @param {Object} props The hook props. * @returns {Array} An array with the state and an action dispatcher. */ function useControlledReducer(reducer, initialState, props) { var previousSelectedItemRef = react.useRef(); var _useEnhancedReducer = useEnhancedReducer(reducer, initialState, props), state = _useEnhancedReducer[0], dispatch = _useEnhancedReducer[1]; // ToDo: if needed, make same approach as selectedItemChanged from Downshift. react.useEffect(function () { if (!isControlledProp(props, 'selectedItem')) { return; } if (props.selectedItemChanged(previousSelectedItemRef.current, props.selectedItem)) { dispatch({ type: ControlledPropUpdatedSelectedItem, inputValue: props.itemToString(props.selectedItem) }); } previousSelectedItemRef.current = state.selectedItem === previousSelectedItemRef.current ? props.selectedItem : state.selectedItem; // eslint-disable-next-line react-hooks/exhaustive-deps }, [state.selectedItem, props.selectedItem]); return [getState(state, props), dispatch]; } // eslint-disable-next-line import/no-mutable-exports var validatePropTypes$1 = noop; /* istanbul ignore next */ if (process.env.NODE_ENV !== 'production') { validatePropTypes$1 = function validatePropTypes(options, caller) { PropTypes__default["default"].checkPropTypes(propTypes$1, options, 'prop', caller.name); }; } var defaultProps$1 = _extends__default["default"]({}, defaultProps$3, { selectedItemChanged: function selectedItemChanged(prevItem, item) { return prevItem !== item; }, getA11yStatusMessage: getA11yStatusMessage$1 }); /* eslint-disable complexity */ function downshiftUseComboboxReducer(state, action) { var _props$items; var type = action.type, props = action.props, altKey = action.altKey; var changes; switch (type) { case ItemClick: changes = { isOpen: getDefaultValue$1(props, 'isOpen'), highlightedIndex: getDefaultValue$1(props, 'highlightedIndex'), selectedItem: props.items[action.index], inputValue: props.itemToString(props.items[action.index]) }; break; case InputKeyDownArrowDown: if (state.isOpen) { changes = { highlightedIndex: getNextWrappingIndex(1, state.highlightedIndex, props.items.length, action.getItemNodeFromIndex, true) }; } else { changes = { highlightedIndex: altKey && state.selectedItem == null ? -1 : getHighlightedIndexOnOpen(props, state, 1, action.getItemNodeFromIndex), isOpen: props.items.length >= 0 }; } break; case InputKeyDownArrowUp: if (state.isOpen) { if (altKey) { changes = getChangesOnSelection(props, state.highlightedIndex); } else { changes = { highlightedIndex: getNextWrappingIndex(-1, state.highlightedIndex, props.items.length, action.getItemNodeFromIndex, true) }; } } else { changes = { highlightedIndex: getHighlightedIndexOnOpen(props, state, -1, action.getItemNodeFromIndex), isOpen: props.items.length >= 0 }; } break; case InputKeyDownEnter: changes = getChangesOnSelection(props, state.highlightedIndex); break; case InputKeyDownEscape: changes = _extends__default["default"]({ isOpen: false, highlightedIndex: -1 }, !state.isOpen && { selectedItem: null, inputValue: '' }); break; case InputKeyDownPageUp: changes = { highlightedIndex: getNextWrappingIndex(-10, state.highlightedIndex, props.items.length, action.getItemNodeFromIndex, false) }; break; case InputKeyDownPageDown: changes = { highlightedIndex: getNextWrappingIndex(10, state.highlightedIndex, props.items.length, action.getItemNodeFromIndex, false) }; break; case InputKeyDownHome: changes = { highlightedIndex: getNextNonDisabledIndex(1, 0, props.items.length, action.getItemNodeFromIndex, false) }; break; case InputKeyDownEnd: changes = { highlightedIndex: getNextNonDisabledIndex(-1, props.items.length - 1, props.items.length, action.getItemNodeFromIndex, false) }; break; case InputBlur: changes = _extends__default["default"]({ isOpen: false, highlightedIndex: -1 }, state.highlightedIndex >= 0 && ((_props$items = props.items) == null ? void 0 : _props$items.length) && action.selectItem && { selectedItem: props.items[state.highlightedIndex], inputValue: props.itemToString(props.items[state.highlightedIndex]) }); break; case InputChange: changes = { isOpen: true, highlightedIndex: getDefaultValue$1(props, 'highlightedIndex'), inputValue: action.inputValue }; break; case InputFocus: changes = { isOpen: true, highlightedIndex: getHighlightedIndexOnOpen(props, state, 0) }; break; case FunctionSelectItem: changes = { selectedItem: action.selectedItem, inputValue: props.itemToString(action.selectedItem) }; break; case ControlledPropUpdatedSelectedItem: changes = { inputValue: action.inputValue }; break; default: return downshiftCommonReducer(state, action, stateChangeTypes$1); } return _extends__default["default"]({}, state, changes); } /* eslint-enable complexity */ var _excluded$1 = ["onMouseLeave", "refKey", "ref"], _excluded2$1 = ["item", "index", "refKey", "ref", "onMouseMove", "onMouseDown", "onClick", "onPress", "disabled"], _excluded3 = ["onClick", "onPress", "refKey", "ref"], _excluded4 = ["onKeyDown", "onChange", "onInput", "onFocus", "onBlur", "onChangeText", "refKey", "ref"]; useCombobox.stateChangeTypes = stateChangeTypes$1; function useCombobox(userProps) { if (userProps === void 0) { userProps = {}; } validatePropTypes$1(userProps, useCombobox); // Props defaults and destructuring. var props = _extends__default["default"]({}, defaultProps$1, userProps); var initialIsOpen = props.initialIsOpen, defaultIsOpen = props.defaultIsOpen, items = props.items, scrollIntoView = props.scrollIntoView, environment = props.environment, getA11yStatusMessage = props.getA11yStatusMessage, getA11ySelectionMessage = props.getA11ySelectionMessage, itemToString = props.itemToString; // Initial state depending on controlled props. var initialState = getInitialState$1(props); var _useControlledReducer = useControlledReducer(downshiftUseComboboxReducer, initialState, props), state = _useControlledReducer[0], dispatch = _useControlledReducer[1]; var isOpen = state.isOpen, highlightedIndex = state.highlightedIndex, selectedItem = state.selectedItem, inputValue = state.inputValue; // Element refs. var menuRef = react.useRef(null); var itemRefs = react.useRef({}); var inputRef = react.useRef(null); var toggleButtonRef = react.useRef(null); var isInitialMountRef = react.useRef(true); // prevent id re-generation between renders. var elementIds = useElementIds(props); // used to keep track of how many items we had on previous cycle. var previousResultCountRef = react.useRef(); // utility callback to get item element. var latest = useLatestRef({ state: state, props: props }); var getItemNodeFromIndex = react.useCallback(function (index) { return itemRefs.current[elementIds.getItemId(index)]; }, [elementIds]); // Effects. // Sets a11y status message on changes in state. useA11yMessageSetter(getA11yStatusMessage, [isOpen, highlightedIndex, inputValue, items], _extends__default["default"]({ isInitialMount: isInitialMountRef.current, previousResultCount: previousResultCountRef.current, items: items, environment: environment, itemToString: itemToString }, state)); // Sets a11y status message on changes in selectedItem. useA11yMessageSetter(getA11ySelectionMessage, [selectedItem], _extends__default["default"]({ isInitialMount: isInitialMountRef.current, previousResultCount: previousResultCountRef.current, items: items, environment: environment, itemToString: itemToString }, state)); // Scroll on highlighted item if change comes from keyboard. var shouldScrollRef = useScrollIntoView({ menuElement: menuRef.current, highlightedIndex: highlightedIndex, isOpen: isOpen, itemRefs: itemRefs, scrollIntoView: scrollIntoView, getItemNodeFromIndex: getItemNodeFromIndex }); useControlPropsValidator({ isInitialMount: isInitialMountRef.current, props: props, state: state }); // Focus the input on first render if required. react.useEffect(function () { var focusOnOpen = initialIsOpen || defaultIsOpen || isOpen; if (focusOnOpen && inputRef.current) { inputRef.current.focus(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); react.useEffect(function () { if (isInitialMountRef.current) { return; } previousResultCountRef.current = items.length; }); // Add mouse/touch events to document. var mouseAndTouchTrackersRef = useMouseAndTouchTracker(isOpen, [inputRef, menuRef, toggleButtonRef], environment, function () { dispatch({ type: InputBlur, selectItem: false }); }); var setGetterPropCallInfo = useGetterPropsCalledChecker('getInputProps', 'getMenuProps'); // Make initial ref false. react.useEffect(function () { isInitialMountRef.current = false; return function () { isInitialMountRef.current = true; }; }, []); // Reset itemRefs on close. react.useEffect(function () { var _environment$document; if (!isOpen) { itemRefs.current = {}; } else if (((_environment$document = environment.document) == null ? void 0 : _environment$document.activeElement) !== inputRef.current) { var _inputRef$current; inputRef == null || (_inputRef$current = inputRef.current) == null ? void 0 : _inputRef$current.focus(); } }, [isOpen, environment]); /* Event handler functions */ var inputKeyDownHandlers = react.useMemo(function () { return { ArrowDown: function ArrowDown(event) { event.preventDefault(); dispatch({ type: InputKeyDownArrowDown, altKey: event.altKey, getItemNodeFromIndex: getItemNodeFromIndex }); }, ArrowUp: function ArrowUp(event) { event.preventDefault(); dispatch({ type: InputKeyDownArrowUp, altKey: event.altKey, getItemNodeFromIndex: getItemNodeFromIndex }); }, Home: function Home(event) { if (!latest.current.state.isOpen) { return; } event.preventDefault(); dispatch({ type: InputKeyDownHome, getItemNodeFromIndex: getItemNodeFromIndex }); }, End: function End(event) { if (!latest.current.state.isOpen) { return; } event.preventDefault(); dispatch({ type: InputKeyDownEnd, getItemNodeFromIndex: getItemNodeFromIndex }); }, Escape: function Escape(event) { var latestState = latest.current.state; if (latestState.isOpen || latestState.inputValue || latestState.selectedItem || latestState.highlightedIndex > -1) { event.preventDefault(); dispatch({ type: InputKeyDownEscape }); } }, Enter: function Enter(event) { var latestState = latest.current.state; // if closed or no highlighted index, do nothing. if (!latestState.isOpen || event.which === 229 // if IME composing, wait for next Enter keydown event. ) { return; } event.preventDefault(); dispatch({ type: InputKeyDownEnter, getItemNodeFromIndex: getItemNodeFromIndex }); }, PageUp: function PageUp(event) { if (latest.current.state.isOpen) { event.preventDefault(); dispatch({ type: InputKeyDownPageUp, getItemNodeFromIndex: getItemNodeFromIndex }); } }, PageDown: function PageDown(event) { if (latest.current.state.isOpen) { event.preventDefault(); dispatch({ type: InputKeyDownPageDown, getItemNodeFromIndex: getItemNodeFromIndex }); } } }; }, [dispatch, latest, getItemNodeFromIndex]); // Getter props. var getLabelProps = react.useCallback(function (labelProps) { return _extends__default["default"]({ id: elementIds.labelId, htmlFor: elementIds.inputId }, labelProps); }, [elementIds]); var getMenuProps = react.useCallback(function (_temp, _temp2) { var _extends2; var _ref = _temp === void 0 ? {} : _temp, onMouseLeave = _ref.onMouseLeave, _ref$refKey = _ref.refKey, refKey = _ref$refKey === void 0 ? 'ref' : _ref$refKey, ref = _ref.ref, rest = _objectWithoutPropertiesLoose__default["default"](_ref, _excluded$1); var _ref2 = _temp2 === void 0 ? {} : _temp2, _ref2$suppressRefErro = _ref2.suppressRefError, suppressRefError = _ref2$suppressRefErro === void 0 ? false : _ref2$suppressRefErro; setGetterPropCallInfo('getMenuProps', suppressRefError, refKey, menuRef); return _extends__default["default"]((_extends2 = {}, _extends2[refKey] = handleRefs(ref, function (menuNode) { menuRef.current = menuNode; }), _extends2.id = elementIds.menuId, _extends2.role = 'listbox', _extends2['aria-labelledby'] = rest && rest['aria-label'] ? undefined : "" + elementIds.labelId, _extends2.onMouseLeave = callAllEventHandlers(onMouseLeave, function () { dispatch({ type: MenuMouseLeave }); }), _extends2), rest); }, [dispatch, setGetterPropCallInfo, elementIds]); var getItemProps = react.useCallback(function (_temp3) { var _extends3, _ref4; var _ref3 = _temp3 === void 0 ? {} : _temp3, itemProp = _ref3.item, indexProp = _ref3.index, _ref3$refKey = _ref3.refKey, refKey = _ref3$refKey === void 0 ? 'ref' : _ref3$refKey, ref = _ref3.ref, onMouseMove = _ref3.onMouseMove, onMouseDown = _ref3.onMouseDown, onClick = _ref3.onClick; _ref3.onPress; var disabled = _ref3.disabled, rest = _objectWithoutPropertiesLoose__default["default"](_ref3, _excluded2$1); var _latest$current = latest.current, latestProps = _latest$current.props, latestState = _latest$current.state; var _getItemAndIndex = getItemAndIndex(itemProp, indexProp, latestProps.items, 'Pass either item or index to getItemProps!'), index = _getItemAndIndex[1]; var onSelectKey = 'onClick'; var customClickHandler = onClick; var itemHandleMouseMove = function itemHandleMouseMove() { if (index === latestState.highlightedIndex) { return; } shouldScrollRef.current = false; dispatch({ type: ItemMouseMove, index: index, disabled: disabled }); }; var itemHandleClick = function itemHandleClick() { dispatch({ type: ItemClick, index: index }); }; var itemHandleMouseDown = function itemHandleMouseDown(e) { return e.preventDefault(); }; return _extends__default["default"]((_extends3 = {}, _extends3[refKey] = handleRefs(ref, function (itemNode) { if (itemNode) { itemRefs.current[elementIds.getItemId(index)] = itemNode; } }), _extends3.disabled = disabled, _extends3.role = 'option', _extends3['aria-selected'] = "" + (index === latestState.highlightedIndex), _extends3.id = elementIds.getItemId(index), _extends3), !disabled && (_ref4 = {}, _ref4[onSelectKey] = callAllEventHandlers(customClickHandler, itemHandleClick), _ref4), { onMouseMove: callAllEventHandlers(onMouseMove, itemHandleMouseMove), onMouseDown: callAllEventHandlers(onMouseDown, itemHandleMouseDown) }, rest); }, [dispatch, latest, shouldScrollRef, elementIds]); var getToggleButtonProps = react.useCallback(function (_temp4) { var _extends4; var _ref5 = _temp4 === void 0 ? {} : _temp4, onClick = _ref5.onClick; _ref5.onPress; var _ref5$refKey = _ref5.refKey, refKey = _ref5$refKey === void 0 ? 'ref' : _ref5$refKey, ref = _ref5.ref, rest = _objectWithoutPropertiesLoose__default["default"](_ref5, _excluded3); var latestState = latest.current.state; var toggleButtonHandleClick = function toggleButtonHandleClick() { dispatch({ type: ToggleButtonClick }); }; return _extends__default["default"]((_extends4 = {}, _extends4[refKey] = handleRefs(ref, function (toggleButtonNode) { toggleButtonRef.current = toggleButtonNode; }), _extends4['aria-controls'] = elementIds.menuId, _extends4['aria-expanded'] = latestState.isOpen, _extends4.id = elementIds.toggleButtonId, _extends4.tabIndex = -1, _extends4), !rest.disabled && _extends__default["default"]({}, { onClick: callAllEventHandlers(onClick, toggleButtonHandleClick) }), rest); }, [dispatch, latest, elementIds]); var getInputProps = react.useCallback(function (_temp5, _temp6) { var _extends5; var _ref6 = _temp5 === void 0 ? {} : _temp5, onKeyDown = _ref6.onKeyDown, onChange = _ref6.onChange, onInput = _ref6.onInput, onFocus = _ref6.onFocus, onBlur = _ref6.onBlur; _ref6.onChangeText; var _ref6$refKey = _ref6.refKey, refKey = _ref6$refKey === void 0 ? 'ref' : _ref6$refKey, ref = _ref6.ref, rest = _objectWithoutPropertiesLoose__default["default"](_ref6, _excluded4); var _ref7 = _temp6 === void 0 ? {} : _temp6, _ref7$suppressRefErro = _ref7.suppressRefError, suppressRefError = _ref7$suppressRefErro === void 0 ? false : _ref7$suppressRefErro; setGetterPropCallInfo('getInputProps', suppressRefError, refKey, inputRef); var latestState = latest.current.state; var inputHandleKeyDown = function inputHandleKeyDown(event) { var key = normalizeArrowKey(event); if (key && inputKeyDownHandlers[key]) { inputKeyDownHandlers[key](event); } }; var inputHandleChange = function inputHandleChange(event) { dispatch({ type: InputChange, inputValue: event.target.value }); }; var inputHandleBlur = function inputHandleBlur(event) { /* istanbul ignore else */ if (latestState.isOpen && !mouseAndTouchTrackersRef.current.isMouseDown) { var isBlurByTabChange = event.relatedTarget === null && environment.document.activeElement !== environment.document.body; dispatch({ type: InputBlur, selectItem: !isBlurByTabChange }); } }; var inputHandleFocus = function inputHandleFocus() { if (!latestState.isOpen) { dispatch({ type: InputFocus }); } }; /* istanbul ignore next (preact) */ var onChangeKey = 'onChange'; var eventHandlers = {}; if (!rest.disabled) { var _eventHandlers; eventHandlers = (_eventHandlers = {}, _eventHandlers[onChangeKey] = callAllEventHandlers(onChange, onInput, inputHandleChange), _eventHandlers.onKeyDown = callAllEventHandlers(onKeyDown, inputHandleKeyDown), _eventHandlers.onBlur = callAllEventHandlers(onBlur, inputHandleBlur), _eventHandlers.onFocus = callAllEventHandlers(onFocus, inputHandleFocus), _eventHandlers); } return _extends__default["default"]((_extends5 = {}, _extends5[refKey] = handleRefs(ref, function (inputNode) { inputRef.current = inputNode; }), _extends5['aria-activedescendant'] = latestState.isOpen && latestState.highlightedIndex > -1 ? elementIds.getItemId(latestState.highlightedIndex) : '', _extends5['aria-autocomplete'] = 'list', _extends5['aria-controls'] = elementIds.menuId, _extends5['aria-expanded'] = latestState.isOpen, _extends5['aria-labelledby'] = rest && rest['aria-label'] ? undefined : "" + elementIds.labelId, _extends5.autoComplete = 'off', _extends5.id = elementIds.inputId, _extends5.role = 'combobox', _extends5.value = latestState.inputValue, _extends5), eventHandlers, rest); }, [setGetterPropCallInfo, latest, elementIds, inputKeyDownHandlers, dispatch, mouseAndTouchTrackersRef, environment]); // returns var toggleMenu = react.useCallback(function () { dispatch({ type: FunctionToggleMenu }); }, [dispatch]); var closeMenu = react.useCallback(function () { dispatch({ type: FunctionCloseMenu }); }, [dispatch]); var openMenu = react.useCallback(function () { dispatch({ type: FunctionOpenMenu }); }, [dispatch]); var setHighlightedIndex = react.useCallback(function (newHighlightedIndex) { dispatch({ type: FunctionSetHighlightedIndex, highlightedIndex: newHighlightedIndex }); }, [dispatch]); var selectItem = react.useCallback(function (newSelectedItem) { dispatch({ type: FunctionSelectItem, selectedItem: newSelectedItem }); }, [dispatch]); var setInputValue = react.useCallback(function (newInputValue) { dispatch({ type: FunctionSetInputValue, inputValue: newInputValue }); }, [dispatch]); var reset = react.useCallback(function () { dispatch({ type: FunctionReset$1 }); }, [dispatch]); return { // prop getters. getItemProps: getItemProps, getLabelProps: getLabelProps, getMenuProps: getMenuProps, getInputProps: getInputProps, getToggleButtonProps: getToggleButtonProps, // actions. toggleMenu: toggleMenu, openMenu: openMenu, closeMenu: closeMenu, setHighlightedIndex: setHighlightedIndex, setInputValue: setInputValue, selectItem: selectItem, reset: reset, // state. highlightedIndex: highlightedIndex, isOpen: isOpen, selectedItem: selectedItem, inputValue: inputValue }; } var defaultStateValues = { activeIndex: -1, selectedItems: [] }; /** * Returns the initial value for a state key in the following order: * 1. controlled prop, 2. initial prop, 3. default prop, 4. default * value from Downshift. * * @param {Object} props Props passed to the hook. * @param {string} propKey Props key to generate the value for. * @returns {any} The initial value for that prop. */ function getInitialValue(props, propKey) { return getInitialValue$1(props, propKey, defaultStateValues); } /** * Returns the default value for a state key in the following order: * 1. controlled prop, 2. default prop, 3. default value from Downshift. * * @param {Object} props Props passed to the hook. * @param {string} propKey Props key to generate the value for. * @returns {any} The initial value for that prop. */ function getDefaultValue(props, propKey) { return getDefaultValue$1(props, propKey, defaultStateValues); } /** * Gets the initial state based on the provided props. It uses initial, default * and controlled props related to state in order to compute the initial value. * * @param {Object} props Props passed to the hook. * @returns {Object} The initial state. */ function getInitialState(props) { var activeIndex = getInitialValue(props, 'activeIndex'); var selectedItems = getInitialValue(props, 'selectedItems'); return { activeIndex: activeIndex, selectedItems: selectedItems }; } /** * Returns true if dropdown keydown operation is permitted. Should not be * allowed on keydown with modifier keys (ctrl, alt, shift, meta), on * input element with text content that is either highlighted or selection * cursor is not at the starting position. * * @param {KeyboardEvent} event The event from keydown. * @returns {boolean} Whether the operation is allowed. */ function isKeyDownOperationPermitted(event) { if (event.shiftKey || event.metaKey || event.ctrlKey || event.altKey) { return false; } var element = event.target; if (element instanceof HTMLInputElement && // if element is a text input element.value !== '' && ( // and we have text in it // and cursor is either not at the start or is currently highlighting text. element.selectionStart !== 0 || element.selectionEnd !== 0)) { return false; } return true; } /** * Returns a message to be added to aria-live region when item is removed. * * @param {Object} selectionParameters Parameters required to build the message. * @returns {string} The a11y message. */ function getA11yRemovalMessage(selectionParameters) { var removedSelectedItem = selectionParameters.removedSelectedItem, itemToStringLocal = selectionParameters.itemToString; return itemToStringLocal(removedSelectedItem) + " has been removed."; } var propTypes = { selectedItems: PropTypes__default["default"].array, initialSelectedItems: PropTypes__default["default"].array, defaultSelectedItems: PropTypes__default["default"].array, itemToString: PropTypes__default["default"].func, getA11yRemovalMessage: PropTypes__default["default"].func, stateReducer: PropTypes__default["default"].func, activeIndex: PropTypes__default["default"].number, initialActiveIndex: PropTypes__default["default"].number, defaultActiveIndex: PropTypes__default["default"].number, onActiveIndexChange: PropTypes__default["default"].func, onSelectedItemsChange: PropTypes__default["default"].func, keyNavigationNext: PropTypes__default["default"].string, keyNavigationPrevious: PropTypes__default["default"].string, environment: PropTypes__default["default"].shape({ addEventListener: PropTypes__default["default"].func, removeEventListener: PropTypes__default["default"].func, document: PropTypes__default["default"].shape({ getElementById: PropTypes__default["default"].func, activeElement: PropTypes__default["default"].any, body: PropTypes__default["default"].any }) }) }; var defaultProps = { itemToString: defaultProps$3.itemToString, stateReducer: defaultProps$3.stateReducer, environment: defaultProps$3.environment, getA11yRemovalMessage: getA11yRemovalMessage, keyNavigationNext: 'ArrowRight', keyNavigationPrevious: 'ArrowLeft' }; // eslint-disable-next-line import/no-mutable-exports var validatePropTypes = noop; /* istanbul ignore next */ if (process.env.NODE_ENV !== 'production') { validatePropTypes = function validatePropTypes(options, caller) { PropTypes__default["default"].checkPropTypes(propTypes, options, 'prop', caller.name); }; } var SelectedItemClick = process.env.NODE_ENV !== "production" ? '__selected_item_click__' : 0; var SelectedItemKeyDownDelete = process.env.NODE_ENV !== "production" ? '__selected_item_keydown_delete__' : 1; var SelectedItemKeyDownBackspace = process.env.NODE_ENV !== "production" ? '__selected_item_keydown_backspace__' : 2; var SelectedItemKeyDownNavigationNext = process.env.NODE_ENV !== "production" ? '__selected_item_keydown_navigation_next__' : 3; var SelectedItemKeyDownNavigationPrevious = process.env.NODE_ENV !== "production" ? '__selected_item_keydown_navigation_previous__' : 4; var DropdownKeyDownNavigationPrevious = process.env.NODE_ENV !== "production" ? '__dropdown_keydown_navigation_previous__' : 5; var DropdownKeyDownBackspace = process.env.NODE_ENV !== "production" ? '__dropdown_keydown_backspace__' : 6; var DropdownClick = process.env.NODE_ENV !== "production" ? '__dropdown_click__' : 7; var FunctionAddSelectedItem = process.env.NODE_ENV !== "production" ? '__function_add_selected_item__' : 8; var FunctionRemoveSelectedItem = process.env.NODE_ENV !== "production" ? '__function_remove_selected_item__' : 9; var FunctionSetSelectedItems = process.env.NODE_ENV !== "production" ? '__function_set_selected_items__' : 10; var FunctionSetActiveIndex = process.env.NODE_ENV !== "production" ? '__function_set_active_index__' : 11; var FunctionReset = process.env.NODE_ENV !== "production" ? '__function_reset__' : 12; var stateChangeTypes = /*#__PURE__*/Object.freeze({ __proto__: null, SelectedItemClick: SelectedItemClick, SelectedItemKeyDownDelete: SelectedItemKeyDownDelete, SelectedItemKeyDownBackspace: SelectedItemKeyDownBackspace, SelectedItemKeyDownNavigationNext: SelectedItemKeyDownNavigationNext, SelectedItemKeyDownNavigationPrevious: SelectedItemKeyDownNavigationPrevious, DropdownKeyDownNavigationPrevious: DropdownKeyDownNavigationPrevious, DropdownKeyDownBackspace: DropdownKeyDownBackspace, DropdownClick: DropdownClick, FunctionAddSelectedItem: FunctionAddSelectedItem, FunctionRemoveSelectedItem: FunctionRemoveSelectedItem, FunctionSetSelectedItems: FunctionSetSelectedItems, FunctionSetActiveIndex: FunctionSetActiveIndex, FunctionReset: FunctionReset }); /* eslint-disable complexity */ function downshiftMultipleSelectionReducer(state, action) { var type = action.type, index = action.index, props = action.props, selectedItem = action.selectedItem; var activeIndex = state.activeIndex, selectedItems = state.selectedItems; var changes; switch (type) { case SelectedItemClick: changes = { activeIndex: index }; break; case SelectedItemKeyDownNavigationPrevious: changes = { activeIndex: activeIndex - 1 < 0 ? 0 : activeIndex - 1 }; break; case SelectedItemKeyDownNavigationNext: changes = { activeIndex: activeIndex + 1 >= selectedItems.length ? -1 : activeIndex + 1 }; break; case SelectedItemKeyDownBackspace: case SelectedItemKeyDownDelete: { if (activeIndex < 0) { break; } var newActiveIndex = activeIndex; if (selectedItems.length === 1) { newActiveIndex = -1; } else if (activeIndex === selectedItems.length - 1) { newActiveIndex = selectedItems.length - 2; } changes = _extends__default["default"]({ selectedItems: [].concat(selectedItems.slice(0, activeIndex), selectedItems.slice(activeIndex + 1)) }, { activeIndex: newActiveIndex }); break; } case DropdownKeyDownNavigationPrevious: changes = { activeIndex: selectedItems.length - 1 }; break; case DropdownKeyDownBackspace: changes = { selectedItems: selectedItems.slice(0, selectedItems.length - 1) }; break; case FunctionAddSelectedItem: changes = { selectedItems: [].concat(selectedItems, [selectedItem]) }; break; case DropdownClick: changes = { activeIndex: -1 }; break; case FunctionRemoveSelectedItem: { var _newActiveIndex = activeIndex; var selectedItemIndex = selectedItems.indexOf(selectedItem); if (selectedItemIndex < 0) { break; } if (selectedItems.length === 1) { _newActiveIndex = -1; } else if (selectedItemIndex === selectedItems.length - 1) { _newActiveIndex = selectedItems.length - 2; } changes = { selectedItems: [].concat(selectedItems.slice(0, selectedItemIndex), selectedItems.slice(selectedItemIndex + 1)), activeIndex: _newActiveIndex }; break; } case FunctionSetSelectedItems: { var newSelectedItems = action.selectedItems; changes = { selectedItems: newSelectedItems }; break; } case FunctionSetActiveIndex: { var _newActiveIndex2 = action.activeIndex; changes = { activeIndex: _newActiveIndex2 }; break; } case FunctionReset: changes = { activeIndex: getDefaultValue(props, 'activeIndex'), selectedItems: getDefaultValue(props, 'selectedItems') }; break; default: throw new Error('Reducer called without proper action type.'); } return _extends__default["default"]({}, state, changes); } var _excluded = ["refKey", "ref", "onClick", "onKeyDown", "selectedItem", "index"], _excluded2 = ["refKey", "ref", "onKeyDown", "onClick", "preventKeyAction"]; useMultipleSelection.stateChangeTypes = stateChangeTypes; function useMultipleSelection(userProps) { if (userProps === void 0) { userProps = {}; } validatePropTypes(userProps, useMultipleSelection); // Props defaults and destructuring. var props = _extends__default["default"]({}, defaultProps, userProps); var getA11yRemovalMessage = props.getA11yRemovalMessage, itemToString = props.itemToString, environment = props.environment, keyNavigationNext = props.keyNavigationNext, keyNavigationPrevious = props.keyNavigationPrevious; // Reducer init. var _useControlledReducer = useControlledReducer$1(downshiftMultipleSelectionReducer, getInitialState(props), props), state = _useControlledReducer[0], dispatch = _useControlledReducer[1]; var activeIndex = state.activeIndex, selectedItems = state.selectedItems; // Refs. var isInitialMountRef = react.useRef(true); var dropdownRef = react.useRef(null); var previousSelectedItemsRef = react.useRef(selectedItems); var selectedItemRefs = react.useRef(); selectedItemRefs.current = []; var latest = useLatestRef({ state: state, props: props }); // Effects. /* Sets a11y status message on changes in selectedItem. */ react.useEffect(function () { if (isInitialMountRef.current || false) { return; } if (selectedItems.length < previousSelectedItemsRef.current.length) { var removedSelectedItem = previousSelectedItemsRef.current.find(function (item) { return selectedItems.indexOf(item) < 0; }); setStatus(getA11yRemovalMessage({ itemToString: itemToString, resultCount: selectedItems.length, removedSelectedItem: removedSelectedItem, activeIndex: activeIndex, activeSelectedItem: selectedItems[activeIndex] }), environment.document); } previousSelectedItemsRef.current = selectedItems; // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedItems.length]); // Sets focus on active item. react.useEffect(function () { if (isInitialMountRef.current) { return; } if (activeIndex === -1 && dropdownRef.current) { dropdownRef.current.focus(); } else if (selectedItemRefs.current[activeIndex]) { selectedItemRefs.current[activeIndex].focus(); } }, [activeIndex]); useControlPropsValidator({ isInitialMount: isInitialMountRef.current, props: props, state: state }); var setGetterPropCallInfo = useGetterPropsCalledChecker('getDropdownProps'); // Make initial ref false. react.useEffect(function () { isInitialMountRef.current = false; return function () { isInitialMountRef.current = true; }; }, []); // Event handler functions. var selectedItemKeyDownHandlers = react.useMemo(function () { var _ref; return _ref = {}, _ref[keyNavigationPrevious] = function () { dispatch({ type: SelectedItemKeyDownNavigationPrevious }); }, _ref[keyNavigationNext] = function () { dispatch({ type: SelectedItemKeyDownNavigationNext }); }, _ref.Delete = function Delete() { dispatch({ type: SelectedItemKeyDownDelete }); }, _ref.Backspace = function Backspace() { dispatch({ type: SelectedItemKeyDownBackspace }); }, _ref; }, [dispatch, keyNavigationNext, keyNavigationPrevious]); var dropdownKeyDownHandlers = react.useMemo(function () { var _ref2; return _ref2 = {}, _ref2[keyNavigationPrevious] = function (event) { if (isKeyDownOperationPermitted(event)) { dispatch({ type: DropdownKeyDownNavigationPrevious }); } }, _ref2.Backspace = function Backspace(event) { if (isKeyDownOperationPermitted(event)) { dispatch({ type: DropdownKeyDownBackspace }); } }, _ref2; }, [dispatch, keyNavigationPrevious]); // Getter props. var getSelectedItemProps = react.useCallback(function (_temp) { var _extends2; var _ref3 = _temp === void 0 ? {} : _temp, _ref3$refKey = _ref3.refKey, refKey = _ref3$refKey === void 0 ? 'ref' : _ref3$refKey, ref = _ref3.ref, onClick = _ref3.onClick, onKeyDown = _ref3.onKeyDown, selectedItemProp = _ref3.selectedItem, indexProp = _ref3.index, rest = _objectWithoutPropertiesLoose__default["default"](_ref3, _excluded); var latestState = latest.current.state; var _getItemAndIndex = getItemAndIndex(selectedItemProp, indexProp, latestState.selectedItems, 'Pass either item or index to getSelectedItemProps!'), index = _getItemAndIndex[1]; var isFocusable = index > -1 && index === latestState.activeIndex; var selectedItemHandleClick = function selectedItemHandleClick() { dispatch({ type: SelectedItemClick, index: index }); }; var selectedItemHandleKeyDown = function selectedItemHandleKeyDown(event) { var key = normalizeArrowKey(event); if (key && selectedItemKeyDownHandlers[key]) { selectedItemKeyDownHandlers[key](event); } }; return _extends__default["default"]((_extends2 = {}, _extends2[refKey] = handleRefs(ref, function (selectedItemNode) { if (selectedItemNode) { selectedItemRefs.current.push(selectedItemNode); } }), _extends2.tabIndex = isFocusable ? 0 : -1, _extends2.onClick = callAllEventHandlers(onClick, selectedItemHandleClick), _extends2.onKeyDown = callAllEventHandlers(onKeyDown, selectedItemHandleKeyDown), _extends2), rest); }, [dispatch, latest, selectedItemKeyDownHandlers]); var getDropdownProps = react.useCallback(function (_temp2, _temp3) { var _extends3; var _ref4 = _temp2 === void 0 ? {} : _temp2, _ref4$refKey = _ref4.refKey, refKey = _ref4$refKey === void 0 ? 'ref' : _ref4$refKey, ref = _ref4.ref, onKeyDown = _ref4.onKeyDown, onClick = _ref4.onClick, _ref4$preventKeyActio = _ref4.preventKeyAction, preventKeyAction = _ref4$preventKeyActio === void 0 ? false : _ref4$preventKeyActio, rest = _objectWithoutPropertiesLoose__default["default"](_ref4, _excluded2); var _ref5 = _temp3 === void 0 ? {} : _temp3, _ref5$suppressRefErro = _ref5.suppressRefError, suppressRefError = _ref5$suppressRefErro === void 0 ? false : _ref5$suppressRefErro; setGetterPropCallInfo('getDropdownProps', suppressRefError, refKey, dropdownRef); var dropdownHandleKeyDown = function dropdownHandleKeyDown(event) { var key = normalizeArrowKey(event); if (key && dropdownKeyDownHandlers[key]) { dropdownKeyDownHandlers[key](event); } }; var dropdownHandleClick = function dropdownHandleClick() { dispatch({ type: DropdownClick }); }; return _extends__default["default"]((_extends3 = {}, _extends3[refKey] = handleRefs(ref, function (dropdownNode) { if (dropdownNode) { dropdownRef.current = dropdownNode; } }), _extends3), !preventKeyAction && { onKeyDown: callAllEventHandlers(onKeyDown, dropdownHandleKeyDown), onClick: callAllEventHandlers(onClick, dropdownHandleClick) }, rest); }, [dispatch, dropdownKeyDownHandlers, setGetterPropCallInfo]); // returns var addSelectedItem = react.useCallback(function (selectedItem) { dispatch({ type: FunctionAddSelectedItem, selectedItem: selectedItem }); }, [dispatch]); var removeSelectedItem = react.useCallback(function (selectedItem) { dispatch({ type: FunctionRemoveSelectedItem, selectedItem: selectedItem }); }, [dispatch]); var setSelectedItems = react.useCallback(function (newSelectedItems) { dispatch({ type: FunctionSetSelectedItems, selectedItems: newSelectedItems }); }, [dispatch]); var setActiveIndex = react.useCallback(function (newActiveIndex) { dispatch({ type: FunctionSetActiveIndex, activeIndex: newActiveIndex }); }, [dispatch]); var reset = react.useCallback(function () { dispatch({ type: FunctionReset }); }, [dispatch]); return { getSelectedItemProps: getSelectedItemProps, getDropdownProps: getDropdownProps, addSelectedItem: addSelectedItem, removeSelectedItem: removeSelectedItem, setSelectedItems: setSelectedItems, setActiveIndex: setActiveIndex, reset: reset, selectedItems: selectedItems, activeIndex: activeIndex }; } exports["default"] = Downshift$1; exports.resetIdCounter = resetIdCounter; exports.useCombobox = useCombobox; exports.useMultipleSelection = useMultipleSelection; exports.useSelect = useSelect;