UNPKG

146 kBJavaScriptView Raw
1import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/esm/objectWithoutPropertiesLoose';
2import _extends from '@babel/runtime/helpers/esm/extends';
3import _assertThisInitialized from '@babel/runtime/helpers/esm/assertThisInitialized';
4import _inheritsLoose from '@babel/runtime/helpers/esm/inheritsLoose';
5import PropTypes from 'prop-types';
6import { cloneElement, Component, useRef, useEffect, useCallback, useLayoutEffect, useReducer, useMemo } from 'react';
7import { isForwardRef } from 'react-is';
8import computeScrollIntoView from 'compute-scroll-into-view';
9
10var idCounter = 0;
11/**
12 * Accepts a parameter and returns it if it's a function
13 * or a noop function if it's not. This allows us to
14 * accept a callback, but not worry about it if it's not
15 * passed.
16 * @param {Function} cb the callback
17 * @return {Function} a function
18 */
19
20function cbToCb(cb) {
21 return typeof cb === 'function' ? cb : noop;
22}
23
24function noop() {}
25/**
26 * Scroll node into view if necessary
27 * @param {HTMLElement} node the element that should scroll into view
28 * @param {HTMLElement} menuNode the menu element of the component
29 */
30
31
32function scrollIntoView(node, menuNode) {
33 if (!node) {
34 return;
35 }
36
37 var actions = computeScrollIntoView(node, {
38 boundary: menuNode,
39 block: 'nearest',
40 scrollMode: 'if-needed'
41 });
42 actions.forEach(function (_ref) {
43 var el = _ref.el,
44 top = _ref.top,
45 left = _ref.left;
46 el.scrollTop = top;
47 el.scrollLeft = left;
48 });
49}
50/**
51 * @param {HTMLElement} parent the parent node
52 * @param {HTMLElement} child the child node
53 * @return {Boolean} whether the parent is the child or the child is in the parent
54 */
55
56
57function isOrContainsNode(parent, child) {
58 return parent === child || child instanceof Node && parent.contains && parent.contains(child);
59}
60/**
61 * Simple debounce implementation. Will call the given
62 * function once after the time given has passed since
63 * it was last called.
64 * @param {Function} fn the function to call after the time
65 * @param {Number} time the time to wait
66 * @return {Function} the debounced function
67 */
68
69
70function debounce(fn, time) {
71 var timeoutId;
72
73 function cancel() {
74 if (timeoutId) {
75 clearTimeout(timeoutId);
76 }
77 }
78
79 function wrapper() {
80 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
81 args[_key] = arguments[_key];
82 }
83
84 cancel();
85 timeoutId = setTimeout(function () {
86 timeoutId = null;
87 fn.apply(void 0, args);
88 }, time);
89 }
90
91 wrapper.cancel = cancel;
92 return wrapper;
93}
94/**
95 * This is intended to be used to compose event handlers.
96 * They are executed in order until one of them sets
97 * `event.preventDownshiftDefault = true`.
98 * @param {...Function} fns the event handler functions
99 * @return {Function} the event handler to add to an element
100 */
101
102
103function callAllEventHandlers() {
104 for (var _len2 = arguments.length, fns = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
105 fns[_key2] = arguments[_key2];
106 }
107
108 return function (event) {
109 for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
110 args[_key3 - 1] = arguments[_key3];
111 }
112
113 return fns.some(function (fn) {
114 if (fn) {
115 fn.apply(void 0, [event].concat(args));
116 }
117
118 return event.preventDownshiftDefault || event.hasOwnProperty('nativeEvent') && event.nativeEvent.preventDownshiftDefault;
119 });
120 };
121}
122
123function handleRefs() {
124 for (var _len4 = arguments.length, refs = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
125 refs[_key4] = arguments[_key4];
126 }
127
128 return function (node) {
129 refs.forEach(function (ref) {
130 if (typeof ref === 'function') {
131 ref(node);
132 } else if (ref) {
133 ref.current = node;
134 }
135 });
136 };
137}
138/**
139 * This generates a unique ID for an instance of Downshift
140 * @return {String} the unique ID
141 */
142
143
144function generateId() {
145 return String(idCounter++);
146}
147/**
148 * Resets idCounter to 0. Used for SSR.
149 */
150
151
152function resetIdCounter() {
153 idCounter = 0;
154}
155/**
156 * Default implementation for status message. Only added when menu is open.
157 * Will specift if there are results in the list, and if so, how many,
158 * and what keys are relevant.
159 *
160 * @param {Object} param the downshift state and other relevant properties
161 * @return {String} the a11y status message
162 */
163
164
165function getA11yStatusMessage(_ref2) {
166 var isOpen = _ref2.isOpen,
167 resultCount = _ref2.resultCount,
168 previousResultCount = _ref2.previousResultCount;
169
170 if (!isOpen) {
171 return '';
172 }
173
174 if (!resultCount) {
175 return 'No results are available.';
176 }
177
178 if (resultCount !== previousResultCount) {
179 return resultCount + " result" + (resultCount === 1 ? ' is' : 's are') + " available, use up and down arrow keys to navigate. Press Enter key to select.";
180 }
181
182 return '';
183}
184/**
185 * Takes an argument and if it's an array, returns the first item in the array
186 * otherwise returns the argument
187 * @param {*} arg the maybe-array
188 * @param {*} defaultValue the value if arg is falsey not defined
189 * @return {*} the arg or it's first item
190 */
191
192
193function unwrapArray(arg, defaultValue) {
194 arg = Array.isArray(arg) ?
195 /* istanbul ignore next (preact) */
196 arg[0] : arg;
197
198 if (!arg && defaultValue) {
199 return defaultValue;
200 } else {
201 return arg;
202 }
203}
204/**
205 * @param {Object} element (P)react element
206 * @return {Boolean} whether it's a DOM element
207 */
208
209
210function isDOMElement(element) {
211
212
213 return typeof element.type === 'string';
214}
215/**
216 * @param {Object} element (P)react element
217 * @return {Object} the props
218 */
219
220
221function getElementProps(element) {
222
223 return element.props;
224}
225/**
226 * Throws a helpful error message for required properties. Useful
227 * to be used as a default in destructuring or object params.
228 * @param {String} fnName the function name
229 * @param {String} propName the prop name
230 */
231
232
233function requiredProp(fnName, propName) {
234 // eslint-disable-next-line no-console
235 console.error("The property \"" + propName + "\" is required in \"" + fnName + "\"");
236}
237
238var stateKeys = ['highlightedIndex', 'inputValue', 'isOpen', 'selectedItem', 'type'];
239/**
240 * @param {Object} state the state object
241 * @return {Object} state that is relevant to downshift
242 */
243
244function pickState(state) {
245 if (state === void 0) {
246 state = {};
247 }
248
249 var result = {};
250 stateKeys.forEach(function (k) {
251 if (state.hasOwnProperty(k)) {
252 result[k] = state[k];
253 }
254 });
255 return result;
256}
257/**
258 * This will perform a shallow merge of the given state object
259 * with the state coming from props
260 * (for the controlled component scenario)
261 * This is used in state updater functions so they're referencing
262 * the right state regardless of where it comes from.
263 *
264 * @param {Object} state The state of the component/hook.
265 * @param {Object} props The props that may contain controlled values.
266 * @returns {Object} The merged controlled state.
267 */
268
269
270function getState(state, props) {
271 return Object.keys(state).reduce(function (prevState, key) {
272 prevState[key] = isControlledProp(props, key) ? props[key] : state[key];
273 return prevState;
274 }, {});
275}
276/**
277 * This determines whether a prop is a "controlled prop" meaning it is
278 * state which is controlled by the outside of this component rather
279 * than within this component.
280 *
281 * @param {Object} props The props that may contain controlled values.
282 * @param {String} key the key to check
283 * @return {Boolean} whether it is a controlled controlled prop
284 */
285
286
287function isControlledProp(props, key) {
288 return props[key] !== undefined;
289}
290/**
291 * Normalizes the 'key' property of a KeyboardEvent in IE/Edge
292 * @param {Object} event a keyboardEvent object
293 * @return {String} keyboard key
294 */
295
296
297function normalizeArrowKey(event) {
298 var key = event.key,
299 keyCode = event.keyCode;
300 /* istanbul ignore next (ie) */
301
302 if (keyCode >= 37 && keyCode <= 40 && key.indexOf('Arrow') !== 0) {
303 return "Arrow" + key;
304 }
305
306 return key;
307}
308/**
309 * Simple check if the value passed is object literal
310 * @param {*} obj any things
311 * @return {Boolean} whether it's object literal
312 */
313
314
315function isPlainObject(obj) {
316 return Object.prototype.toString.call(obj) === '[object Object]';
317}
318/**
319 * Returns the new index in the list, in a circular way. If next value is out of bonds from the total,
320 * it will wrap to either 0 or itemCount - 1.
321 *
322 * @param {number} moveAmount Number of positions to move. Negative to move backwards, positive forwards.
323 * @param {number} baseIndex The initial position to move from.
324 * @param {number} itemCount The total number of items.
325 * @param {Function} getItemNodeFromIndex Used to check if item is disabled.
326 * @param {boolean} circular Specify if navigation is circular. Default is true.
327 * @returns {number} The new index after the move.
328 */
329
330
331function getNextWrappingIndex(moveAmount, baseIndex, itemCount, getItemNodeFromIndex, circular) {
332 if (circular === void 0) {
333 circular = true;
334 }
335
336 if (itemCount === 0) {
337 return -1;
338 }
339
340 var itemsLastIndex = itemCount - 1;
341
342 if (typeof baseIndex !== 'number' || baseIndex < 0 || baseIndex >= itemCount) {
343 baseIndex = moveAmount > 0 ? -1 : itemsLastIndex + 1;
344 }
345
346 var newIndex = baseIndex + moveAmount;
347
348 if (newIndex < 0) {
349 newIndex = circular ? itemsLastIndex : 0;
350 } else if (newIndex > itemsLastIndex) {
351 newIndex = circular ? 0 : itemsLastIndex;
352 }
353
354 var nonDisabledNewIndex = getNextNonDisabledIndex(moveAmount, newIndex, itemCount, getItemNodeFromIndex, circular);
355
356 if (nonDisabledNewIndex === -1) {
357 return baseIndex >= itemCount ? -1 : baseIndex;
358 }
359
360 return nonDisabledNewIndex;
361}
362/**
363 * Returns the next index in the list of an item that is not disabled.
364 *
365 * @param {number} moveAmount Number of positions to move. Negative to move backwards, positive forwards.
366 * @param {number} baseIndex The initial position to move from.
367 * @param {number} itemCount The total number of items.
368 * @param {Function} getItemNodeFromIndex Used to check if item is disabled.
369 * @param {boolean} circular Specify if navigation is circular. Default is true.
370 * @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.
371 */
372
373
374function getNextNonDisabledIndex(moveAmount, baseIndex, itemCount, getItemNodeFromIndex, circular) {
375 var currentElementNode = getItemNodeFromIndex(baseIndex);
376
377 if (!currentElementNode || !currentElementNode.hasAttribute('disabled')) {
378 return baseIndex;
379 }
380
381 if (moveAmount > 0) {
382 for (var index = baseIndex + 1; index < itemCount; index++) {
383 if (!getItemNodeFromIndex(index).hasAttribute('disabled')) {
384 return index;
385 }
386 }
387 } else {
388 for (var _index = baseIndex - 1; _index >= 0; _index--) {
389 if (!getItemNodeFromIndex(_index).hasAttribute('disabled')) {
390 return _index;
391 }
392 }
393 }
394
395 if (circular) {
396 return moveAmount > 0 ? getNextNonDisabledIndex(1, 0, itemCount, getItemNodeFromIndex, false) : getNextNonDisabledIndex(-1, itemCount - 1, itemCount, getItemNodeFromIndex, false);
397 }
398
399 return -1;
400}
401/**
402 * Checks if event target is within the downshift elements.
403 *
404 * @param {EventTarget} target Target to check.
405 * @param {HTMLElement[]} downshiftElements The elements that form downshift (list, toggle button etc).
406 * @param {Document} document The document.
407 * @param {boolean} checkActiveElement Whether to also check activeElement.
408 *
409 * @returns {boolean} Whether or not the target is within downshift elements.
410 */
411
412
413function targetWithinDownshift(target, downshiftElements, document, checkActiveElement) {
414 if (checkActiveElement === void 0) {
415 checkActiveElement = true;
416 }
417
418 return downshiftElements.some(function (contextNode) {
419 return contextNode && (isOrContainsNode(contextNode, target) || checkActiveElement && isOrContainsNode(contextNode, document.activeElement));
420 });
421}
422
423function validateControlledUnchanged(state, prevProps, nextProps) {
424 if (process.env.NODE_ENV === 'production') {
425 return;
426 }
427
428 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";
429 Object.keys(state).forEach(function (propKey) {
430 if (prevProps[propKey] !== undefined && nextProps[propKey] === undefined) {
431 // eslint-disable-next-line no-console
432 console.error("downshift: A component has changed the controlled prop \"" + propKey + "\" to be uncontrolled. " + warningDescription);
433 } else if (prevProps[propKey] === undefined && nextProps[propKey] !== undefined) {
434 // eslint-disable-next-line no-console
435 console.error("downshift: A component has changed the uncontrolled prop \"" + propKey + "\" to be controlled. " + warningDescription);
436 }
437 });
438}
439
440var cleanupStatus = debounce(function (documentProp) {
441 getStatusDiv(documentProp).textContent = '';
442}, 500);
443/**
444 * @param {String} status the status message
445 * @param {Object} documentProp document passed by the user.
446 */
447
448function setStatus(status, documentProp) {
449 var div = getStatusDiv(documentProp);
450
451 if (!status) {
452 return;
453 }
454
455 div.textContent = status;
456 cleanupStatus(documentProp);
457}
458/**
459 * Get the status node or create it if it does not already exist.
460 * @param {Object} documentProp document passed by the user.
461 * @return {HTMLElement} the status node.
462 */
463
464
465function getStatusDiv(documentProp) {
466 if (documentProp === void 0) {
467 documentProp = document;
468 }
469
470 var statusDiv = documentProp.getElementById('a11y-status-message');
471
472 if (statusDiv) {
473 return statusDiv;
474 }
475
476 statusDiv = documentProp.createElement('div');
477 statusDiv.setAttribute('id', 'a11y-status-message');
478 statusDiv.setAttribute('role', 'status');
479 statusDiv.setAttribute('aria-live', 'polite');
480 statusDiv.setAttribute('aria-relevant', 'additions text');
481 Object.assign(statusDiv.style, {
482 border: '0',
483 clip: 'rect(0 0 0 0)',
484 height: '1px',
485 margin: '-1px',
486 overflow: 'hidden',
487 padding: '0',
488 position: 'absolute',
489 width: '1px'
490 });
491 documentProp.body.appendChild(statusDiv);
492 return statusDiv;
493}
494
495var unknown = process.env.NODE_ENV !== "production" ? '__autocomplete_unknown__' : 0;
496var mouseUp = process.env.NODE_ENV !== "production" ? '__autocomplete_mouseup__' : 1;
497var itemMouseEnter = process.env.NODE_ENV !== "production" ? '__autocomplete_item_mouseenter__' : 2;
498var keyDownArrowUp = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_arrow_up__' : 3;
499var keyDownArrowDown = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_arrow_down__' : 4;
500var keyDownEscape = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_escape__' : 5;
501var keyDownEnter = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_enter__' : 6;
502var keyDownHome = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_home__' : 7;
503var keyDownEnd = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_end__' : 8;
504var clickItem = process.env.NODE_ENV !== "production" ? '__autocomplete_click_item__' : 9;
505var blurInput = process.env.NODE_ENV !== "production" ? '__autocomplete_blur_input__' : 10;
506var changeInput = process.env.NODE_ENV !== "production" ? '__autocomplete_change_input__' : 11;
507var keyDownSpaceButton = process.env.NODE_ENV !== "production" ? '__autocomplete_keydown_space_button__' : 12;
508var clickButton = process.env.NODE_ENV !== "production" ? '__autocomplete_click_button__' : 13;
509var blurButton = process.env.NODE_ENV !== "production" ? '__autocomplete_blur_button__' : 14;
510var controlledPropUpdatedSelectedItem = process.env.NODE_ENV !== "production" ? '__autocomplete_controlled_prop_updated_selected_item__' : 15;
511var touchEnd = process.env.NODE_ENV !== "production" ? '__autocomplete_touchend__' : 16;
512
513var stateChangeTypes = /*#__PURE__*/Object.freeze({
514 __proto__: null,
515 unknown: unknown,
516 mouseUp: mouseUp,
517 itemMouseEnter: itemMouseEnter,
518 keyDownArrowUp: keyDownArrowUp,
519 keyDownArrowDown: keyDownArrowDown,
520 keyDownEscape: keyDownEscape,
521 keyDownEnter: keyDownEnter,
522 keyDownHome: keyDownHome,
523 keyDownEnd: keyDownEnd,
524 clickItem: clickItem,
525 blurInput: blurInput,
526 changeInput: changeInput,
527 keyDownSpaceButton: keyDownSpaceButton,
528 clickButton: clickButton,
529 blurButton: blurButton,
530 controlledPropUpdatedSelectedItem: controlledPropUpdatedSelectedItem,
531 touchEnd: touchEnd
532});
533
534var Downshift = /*#__PURE__*/function () {
535 var Downshift = /*#__PURE__*/function (_Component) {
536 _inheritsLoose(Downshift, _Component);
537
538 function Downshift(_props) {
539 var _this;
540
541 _this = _Component.call(this, _props) || this; // fancy destructuring + defaults + aliases
542 // this basically says each value of state should either be set to
543 // the initial value or the default value if the initial value is not provided
544
545 _this.id = _this.props.id || "downshift-" + generateId();
546 _this.menuId = _this.props.menuId || _this.id + "-menu";
547 _this.labelId = _this.props.labelId || _this.id + "-label";
548 _this.inputId = _this.props.inputId || _this.id + "-input";
549
550 _this.getItemId = _this.props.getItemId || function (index) {
551 return _this.id + "-item-" + index;
552 };
553
554 _this.input = null;
555 _this.items = [];
556 _this.itemCount = null;
557 _this.previousResultCount = 0;
558 _this.timeoutIds = [];
559
560 _this.internalSetTimeout = function (fn, time) {
561 var id = setTimeout(function () {
562 _this.timeoutIds = _this.timeoutIds.filter(function (i) {
563 return i !== id;
564 });
565 fn();
566 }, time);
567
568 _this.timeoutIds.push(id);
569 };
570
571 _this.setItemCount = function (count) {
572 _this.itemCount = count;
573 };
574
575 _this.unsetItemCount = function () {
576 _this.itemCount = null;
577 };
578
579 _this.setHighlightedIndex = function (highlightedIndex, otherStateToSet) {
580 if (highlightedIndex === void 0) {
581 highlightedIndex = _this.props.defaultHighlightedIndex;
582 }
583
584 if (otherStateToSet === void 0) {
585 otherStateToSet = {};
586 }
587
588 otherStateToSet = pickState(otherStateToSet);
589
590 _this.internalSetState(_extends({
591 highlightedIndex: highlightedIndex
592 }, otherStateToSet));
593 };
594
595 _this.clearSelection = function (cb) {
596 _this.internalSetState({
597 selectedItem: null,
598 inputValue: '',
599 highlightedIndex: _this.props.defaultHighlightedIndex,
600 isOpen: _this.props.defaultIsOpen
601 }, cb);
602 };
603
604 _this.selectItem = function (item, otherStateToSet, cb) {
605 otherStateToSet = pickState(otherStateToSet);
606
607 _this.internalSetState(_extends({
608 isOpen: _this.props.defaultIsOpen,
609 highlightedIndex: _this.props.defaultHighlightedIndex,
610 selectedItem: item,
611 inputValue: _this.props.itemToString(item)
612 }, otherStateToSet), cb);
613 };
614
615 _this.selectItemAtIndex = function (itemIndex, otherStateToSet, cb) {
616 var item = _this.items[itemIndex];
617
618 if (item == null) {
619 return;
620 }
621
622 _this.selectItem(item, otherStateToSet, cb);
623 };
624
625 _this.selectHighlightedItem = function (otherStateToSet, cb) {
626 return _this.selectItemAtIndex(_this.getState().highlightedIndex, otherStateToSet, cb);
627 };
628
629 _this.internalSetState = function (stateToSet, cb) {
630 var isItemSelected, onChangeArg;
631 var onStateChangeArg = {};
632 var isStateToSetFunction = typeof stateToSet === 'function'; // we want to call `onInputValueChange` before the `setState` call
633 // so someone controlling the `inputValue` state gets notified of
634 // the input change as soon as possible. This avoids issues with
635 // preserving the cursor position.
636 // See https://github.com/downshift-js/downshift/issues/217 for more info.
637
638 if (!isStateToSetFunction && stateToSet.hasOwnProperty('inputValue')) {
639 _this.props.onInputValueChange(stateToSet.inputValue, _extends({}, _this.getStateAndHelpers(), stateToSet));
640 }
641
642 return _this.setState(function (state) {
643 state = _this.getState(state);
644 var newStateToSet = isStateToSetFunction ? stateToSet(state) : stateToSet; // Your own function that could modify the state that will be set.
645
646 newStateToSet = _this.props.stateReducer(state, newStateToSet); // checks if an item is selected, regardless of if it's different from
647 // what was selected before
648 // used to determine if onSelect and onChange callbacks should be called
649
650 isItemSelected = newStateToSet.hasOwnProperty('selectedItem'); // this keeps track of the object we want to call with setState
651
652 var nextState = {}; // this is just used to tell whether the state changed
653 // and we're trying to update that state. OR if the selection has changed and we're
654 // trying to update the selection
655
656 if (isItemSelected && newStateToSet.selectedItem !== state.selectedItem) {
657 onChangeArg = newStateToSet.selectedItem;
658 }
659
660 newStateToSet.type = newStateToSet.type || unknown;
661 Object.keys(newStateToSet).forEach(function (key) {
662 // onStateChangeArg should only have the state that is
663 // actually changing
664 if (state[key] !== newStateToSet[key]) {
665 onStateChangeArg[key] = newStateToSet[key];
666 } // the type is useful for the onStateChangeArg
667 // but we don't actually want to set it in internal state.
668 // this is an undocumented feature for now... Not all internalSetState
669 // calls support it and I'm not certain we want them to yet.
670 // But it enables users controlling the isOpen state to know when
671 // the isOpen state changes due to mouseup events which is quite handy.
672
673
674 if (key === 'type') {
675 return;
676 }
677
678 newStateToSet[key]; // if it's coming from props, then we don't care to set it internally
679
680 if (!isControlledProp(_this.props, key)) {
681 nextState[key] = newStateToSet[key];
682 }
683 }); // if stateToSet is a function, then we weren't able to call onInputValueChange
684 // earlier, so we'll call it now that we know what the inputValue state will be.
685
686 if (isStateToSetFunction && newStateToSet.hasOwnProperty('inputValue')) {
687 _this.props.onInputValueChange(newStateToSet.inputValue, _extends({}, _this.getStateAndHelpers(), newStateToSet));
688 }
689
690 return nextState;
691 }, function () {
692 // call the provided callback if it's a function
693 cbToCb(cb)(); // only call the onStateChange and onChange callbacks if
694 // we have relevant information to pass them.
695
696 var hasMoreStateThanType = Object.keys(onStateChangeArg).length > 1;
697
698 if (hasMoreStateThanType) {
699 _this.props.onStateChange(onStateChangeArg, _this.getStateAndHelpers());
700 }
701
702 if (isItemSelected) {
703 _this.props.onSelect(stateToSet.selectedItem, _this.getStateAndHelpers());
704 }
705
706 if (onChangeArg !== undefined) {
707 _this.props.onChange(onChangeArg, _this.getStateAndHelpers());
708 } // this is currently undocumented and therefore subject to change
709 // We'll try to not break it, but just be warned.
710
711
712 _this.props.onUserAction(onStateChangeArg, _this.getStateAndHelpers());
713 });
714 };
715
716 _this.rootRef = function (node) {
717 return _this._rootNode = node;
718 };
719
720 _this.getRootProps = function (_temp, _temp2) {
721 var _extends2;
722
723 var _ref = _temp === void 0 ? {} : _temp,
724 _ref$refKey = _ref.refKey,
725 refKey = _ref$refKey === void 0 ? 'ref' : _ref$refKey,
726 ref = _ref.ref,
727 rest = _objectWithoutPropertiesLoose(_ref, ["refKey", "ref"]);
728
729 var _ref2 = _temp2 === void 0 ? {} : _temp2,
730 _ref2$suppressRefErro = _ref2.suppressRefError,
731 suppressRefError = _ref2$suppressRefErro === void 0 ? false : _ref2$suppressRefErro;
732
733 // this is used in the render to know whether the user has called getRootProps.
734 // It uses that to know whether to apply the props automatically
735 _this.getRootProps.called = true;
736 _this.getRootProps.refKey = refKey;
737 _this.getRootProps.suppressRefError = suppressRefError;
738
739 var _this$getState = _this.getState(),
740 isOpen = _this$getState.isOpen;
741
742 return _extends((_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);
743 };
744
745 _this.keyDownHandlers = {
746 ArrowDown: function ArrowDown(event) {
747 var _this2 = this;
748
749 event.preventDefault();
750
751 if (this.getState().isOpen) {
752 var amount = event.shiftKey ? 5 : 1;
753 this.moveHighlightedIndex(amount, {
754 type: keyDownArrowDown
755 });
756 } else {
757 this.internalSetState({
758 isOpen: true,
759 type: keyDownArrowDown
760 }, function () {
761 var itemCount = _this2.getItemCount();
762
763 if (itemCount > 0) {
764 var _this2$getState = _this2.getState(),
765 highlightedIndex = _this2$getState.highlightedIndex;
766
767 var nextHighlightedIndex = getNextWrappingIndex(1, highlightedIndex, itemCount, function (index) {
768 return _this2.getItemNodeFromIndex(index);
769 });
770
771 _this2.setHighlightedIndex(nextHighlightedIndex, {
772 type: keyDownArrowDown
773 });
774 }
775 });
776 }
777 },
778 ArrowUp: function ArrowUp(event) {
779 var _this3 = this;
780
781 event.preventDefault();
782
783 if (this.getState().isOpen) {
784 var amount = event.shiftKey ? -5 : -1;
785 this.moveHighlightedIndex(amount, {
786 type: keyDownArrowUp
787 });
788 } else {
789 this.internalSetState({
790 isOpen: true,
791 type: keyDownArrowUp
792 }, function () {
793 var itemCount = _this3.getItemCount();
794
795 if (itemCount > 0) {
796 var _this3$getState = _this3.getState(),
797 highlightedIndex = _this3$getState.highlightedIndex;
798
799 var nextHighlightedIndex = getNextWrappingIndex(-1, highlightedIndex, itemCount, function (index) {
800 return _this3.getItemNodeFromIndex(index);
801 });
802
803 _this3.setHighlightedIndex(nextHighlightedIndex, {
804 type: keyDownArrowUp
805 });
806 }
807 });
808 }
809 },
810 Enter: function Enter(event) {
811 if (event.which === 229) {
812 return;
813 }
814
815 var _this$getState2 = this.getState(),
816 isOpen = _this$getState2.isOpen,
817 highlightedIndex = _this$getState2.highlightedIndex;
818
819 if (isOpen && highlightedIndex != null) {
820 event.preventDefault();
821 var item = this.items[highlightedIndex];
822 var itemNode = this.getItemNodeFromIndex(highlightedIndex);
823
824 if (item == null || itemNode && itemNode.hasAttribute('disabled')) {
825 return;
826 }
827
828 this.selectHighlightedItem({
829 type: keyDownEnter
830 });
831 }
832 },
833 Escape: function Escape(event) {
834 event.preventDefault();
835 this.reset(_extends({
836 type: keyDownEscape
837 }, !this.state.isOpen && {
838 selectedItem: null,
839 inputValue: ''
840 }));
841 }
842 };
843 _this.buttonKeyDownHandlers = _extends({}, _this.keyDownHandlers, {
844 ' ': function _(event) {
845 event.preventDefault();
846 this.toggleMenu({
847 type: keyDownSpaceButton
848 });
849 }
850 });
851 _this.inputKeyDownHandlers = _extends({}, _this.keyDownHandlers, {
852 Home: function Home(event) {
853 var _this4 = this;
854
855 event.preventDefault();
856 var itemCount = this.getItemCount();
857
858 var _this$getState3 = this.getState(),
859 isOpen = _this$getState3.isOpen;
860
861 if (itemCount <= 0 || !isOpen) {
862 return;
863 } // get next non-disabled starting downwards from 0 if that's disabled.
864
865
866 var newHighlightedIndex = getNextNonDisabledIndex(1, 0, itemCount, function (index) {
867 return _this4.getItemNodeFromIndex(index);
868 }, false);
869 this.setHighlightedIndex(newHighlightedIndex, {
870 type: keyDownHome
871 });
872 },
873 End: function End(event) {
874 var _this5 = this;
875
876 event.preventDefault();
877 var itemCount = this.getItemCount();
878
879 var _this$getState4 = this.getState(),
880 isOpen = _this$getState4.isOpen;
881
882 if (itemCount <= 0 || !isOpen) {
883 return;
884 } // get next non-disabled starting upwards from last index if that's disabled.
885
886
887 var newHighlightedIndex = getNextNonDisabledIndex(-1, itemCount - 1, itemCount, function (index) {
888 return _this5.getItemNodeFromIndex(index);
889 }, false);
890 this.setHighlightedIndex(newHighlightedIndex, {
891 type: keyDownEnd
892 });
893 }
894 });
895
896 _this.getToggleButtonProps = function (_temp3) {
897 var _ref3 = _temp3 === void 0 ? {} : _temp3,
898 onClick = _ref3.onClick,
899 onPress = _ref3.onPress,
900 onKeyDown = _ref3.onKeyDown,
901 onKeyUp = _ref3.onKeyUp,
902 onBlur = _ref3.onBlur,
903 rest = _objectWithoutPropertiesLoose(_ref3, ["onClick", "onPress", "onKeyDown", "onKeyUp", "onBlur"]);
904
905 var _this$getState5 = _this.getState(),
906 isOpen = _this$getState5.isOpen;
907
908 var enabledEventHandlers = {
909 onClick: callAllEventHandlers(onClick, _this.buttonHandleClick),
910 onKeyDown: callAllEventHandlers(onKeyDown, _this.buttonHandleKeyDown),
911 onKeyUp: callAllEventHandlers(onKeyUp, _this.buttonHandleKeyUp),
912 onBlur: callAllEventHandlers(onBlur, _this.buttonHandleBlur)
913 };
914 var eventHandlers = rest.disabled ? {} : enabledEventHandlers;
915 return _extends({
916 type: 'button',
917 role: 'button',
918 'aria-label': isOpen ? 'close menu' : 'open menu',
919 'aria-haspopup': true,
920 'data-toggle': true
921 }, eventHandlers, rest);
922 };
923
924 _this.buttonHandleKeyUp = function (event) {
925 // Prevent click event from emitting in Firefox
926 event.preventDefault();
927 };
928
929 _this.buttonHandleKeyDown = function (event) {
930 var key = normalizeArrowKey(event);
931
932 if (_this.buttonKeyDownHandlers[key]) {
933 _this.buttonKeyDownHandlers[key].call(_assertThisInitialized(_this), event);
934 }
935 };
936
937 _this.buttonHandleClick = function (event) {
938 event.preventDefault(); // handle odd case for Safari and Firefox which
939 // don't give the button the focus properly.
940
941 /* istanbul ignore if (can't reasonably test this) */
942
943 if ( _this.props.environment.document.activeElement === _this.props.environment.document.body) {
944 event.target.focus();
945 } // to simplify testing components that use downshift, we'll not wrap this in a setTimeout
946 // if the NODE_ENV is test. With the proper build system, this should be dead code eliminated
947 // when building for production and should therefore have no impact on production code.
948
949
950 if (process.env.NODE_ENV === 'test') {
951 _this.toggleMenu({
952 type: clickButton
953 });
954 } else {
955 // Ensure that toggle of menu occurs after the potential blur event in iOS
956 _this.internalSetTimeout(function () {
957 return _this.toggleMenu({
958 type: clickButton
959 });
960 });
961 }
962 };
963
964 _this.buttonHandleBlur = function (event) {
965 var blurTarget = event.target; // Save blur target for comparison with activeElement later
966 // Need setTimeout, so that when the user presses Tab, the activeElement is the next focused element, not body element
967
968 _this.internalSetTimeout(function () {
969 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)
970 ) {
971 _this.reset({
972 type: blurButton
973 });
974 }
975 });
976 };
977
978 _this.getLabelProps = function (props) {
979 return _extends({
980 htmlFor: _this.inputId,
981 id: _this.labelId
982 }, props);
983 };
984
985 _this.getInputProps = function (_temp4) {
986 var _ref4 = _temp4 === void 0 ? {} : _temp4,
987 onKeyDown = _ref4.onKeyDown,
988 onBlur = _ref4.onBlur,
989 onChange = _ref4.onChange,
990 onInput = _ref4.onInput,
991 onChangeText = _ref4.onChangeText,
992 rest = _objectWithoutPropertiesLoose(_ref4, ["onKeyDown", "onBlur", "onChange", "onInput", "onChangeText"]);
993
994 var onChangeKey;
995 var eventHandlers = {};
996 /* istanbul ignore next (preact) */
997
998 {
999 onChangeKey = 'onChange';
1000 }
1001
1002 var _this$getState6 = _this.getState(),
1003 inputValue = _this$getState6.inputValue,
1004 isOpen = _this$getState6.isOpen,
1005 highlightedIndex = _this$getState6.highlightedIndex;
1006
1007 if (!rest.disabled) {
1008 var _eventHandlers;
1009
1010 eventHandlers = (_eventHandlers = {}, _eventHandlers[onChangeKey] = callAllEventHandlers(onChange, onInput, _this.inputHandleChange), _eventHandlers.onKeyDown = callAllEventHandlers(onKeyDown, _this.inputHandleKeyDown), _eventHandlers.onBlur = callAllEventHandlers(onBlur, _this.inputHandleBlur), _eventHandlers);
1011 }
1012
1013 return _extends({
1014 'aria-autocomplete': 'list',
1015 'aria-activedescendant': isOpen && typeof highlightedIndex === 'number' && highlightedIndex >= 0 ? _this.getItemId(highlightedIndex) : null,
1016 'aria-controls': isOpen ? _this.menuId : null,
1017 'aria-labelledby': _this.labelId,
1018 // https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion
1019 // revert back since autocomplete="nope" is ignored on latest Chrome and Opera
1020 autoComplete: 'off',
1021 value: inputValue,
1022 id: _this.inputId
1023 }, eventHandlers, rest);
1024 };
1025
1026 _this.inputHandleKeyDown = function (event) {
1027 var key = normalizeArrowKey(event);
1028
1029 if (key && _this.inputKeyDownHandlers[key]) {
1030 _this.inputKeyDownHandlers[key].call(_assertThisInitialized(_this), event);
1031 }
1032 };
1033
1034 _this.inputHandleChange = function (event) {
1035 _this.internalSetState({
1036 type: changeInput,
1037 isOpen: true,
1038 inputValue: event.target.value,
1039 highlightedIndex: _this.props.defaultHighlightedIndex
1040 });
1041 };
1042
1043 _this.inputHandleBlur = function () {
1044 // Need setTimeout, so that when the user presses Tab, the activeElement is the next focused element, not the body element
1045 _this.internalSetTimeout(function () {
1046 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);
1047
1048 if (!_this.isMouseDown && !downshiftButtonIsActive) {
1049 _this.reset({
1050 type: blurInput
1051 });
1052 }
1053 });
1054 };
1055
1056 _this.menuRef = function (node) {
1057 _this._menuNode = node;
1058 };
1059
1060 _this.getMenuProps = function (_temp5, _temp6) {
1061 var _extends3;
1062
1063 var _ref5 = _temp5 === void 0 ? {} : _temp5,
1064 _ref5$refKey = _ref5.refKey,
1065 refKey = _ref5$refKey === void 0 ? 'ref' : _ref5$refKey,
1066 ref = _ref5.ref,
1067 props = _objectWithoutPropertiesLoose(_ref5, ["refKey", "ref"]);
1068
1069 var _ref6 = _temp6 === void 0 ? {} : _temp6,
1070 _ref6$suppressRefErro = _ref6.suppressRefError,
1071 suppressRefError = _ref6$suppressRefErro === void 0 ? false : _ref6$suppressRefErro;
1072
1073 _this.getMenuProps.called = true;
1074 _this.getMenuProps.refKey = refKey;
1075 _this.getMenuProps.suppressRefError = suppressRefError;
1076 return _extends((_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);
1077 };
1078
1079 _this.getItemProps = function (_temp7) {
1080 var _enabledEventHandlers;
1081
1082 var _ref7 = _temp7 === void 0 ? {} : _temp7,
1083 onMouseMove = _ref7.onMouseMove,
1084 onMouseDown = _ref7.onMouseDown,
1085 onClick = _ref7.onClick,
1086 onPress = _ref7.onPress,
1087 index = _ref7.index,
1088 _ref7$item = _ref7.item,
1089 item = _ref7$item === void 0 ? process.env.NODE_ENV === 'production' ?
1090 /* istanbul ignore next */
1091 undefined : requiredProp('getItemProps', 'item') : _ref7$item,
1092 rest = _objectWithoutPropertiesLoose(_ref7, ["onMouseMove", "onMouseDown", "onClick", "onPress", "index", "item"]);
1093
1094 if (index === undefined) {
1095 _this.items.push(item);
1096
1097 index = _this.items.indexOf(item);
1098 } else {
1099 _this.items[index] = item;
1100 }
1101
1102 var onSelectKey = 'onClick';
1103 var customClickHandler = onClick;
1104 var enabledEventHandlers = (_enabledEventHandlers = {
1105 // onMouseMove is used over onMouseEnter here. onMouseMove
1106 // is only triggered on actual mouse movement while onMouseEnter
1107 // can fire on DOM changes, interrupting keyboard navigation
1108 onMouseMove: callAllEventHandlers(onMouseMove, function () {
1109 if (index === _this.getState().highlightedIndex) {
1110 return;
1111 }
1112
1113 _this.setHighlightedIndex(index, {
1114 type: itemMouseEnter
1115 }); // We never want to manually scroll when changing state based
1116 // on `onMouseMove` because we will be moving the element out
1117 // from under the user which is currently scrolling/moving the
1118 // cursor
1119
1120
1121 _this.avoidScrolling = true;
1122
1123 _this.internalSetTimeout(function () {
1124 return _this.avoidScrolling = false;
1125 }, 250);
1126 }),
1127 onMouseDown: callAllEventHandlers(onMouseDown, function (event) {
1128 // This prevents the activeElement from being changed
1129 // to the item so it can remain with the current activeElement
1130 // which is a more common use case.
1131 event.preventDefault();
1132 })
1133 }, _enabledEventHandlers[onSelectKey] = callAllEventHandlers(customClickHandler, function () {
1134 _this.selectItemAtIndex(index, {
1135 type: clickItem
1136 });
1137 }), _enabledEventHandlers); // Passing down the onMouseDown handler to prevent redirect
1138 // of the activeElement if clicking on disabled items
1139
1140 var eventHandlers = rest.disabled ? {
1141 onMouseDown: enabledEventHandlers.onMouseDown
1142 } : enabledEventHandlers;
1143 return _extends({
1144 id: _this.getItemId(index),
1145 role: 'option',
1146 'aria-selected': _this.getState().highlightedIndex === index
1147 }, eventHandlers, rest);
1148 };
1149
1150 _this.clearItems = function () {
1151 _this.items = [];
1152 };
1153
1154 _this.reset = function (otherStateToSet, cb) {
1155 if (otherStateToSet === void 0) {
1156 otherStateToSet = {};
1157 }
1158
1159 otherStateToSet = pickState(otherStateToSet);
1160
1161 _this.internalSetState(function (_ref8) {
1162 var selectedItem = _ref8.selectedItem;
1163 return _extends({
1164 isOpen: _this.props.defaultIsOpen,
1165 highlightedIndex: _this.props.defaultHighlightedIndex,
1166 inputValue: _this.props.itemToString(selectedItem)
1167 }, otherStateToSet);
1168 }, cb);
1169 };
1170
1171 _this.toggleMenu = function (otherStateToSet, cb) {
1172 if (otherStateToSet === void 0) {
1173 otherStateToSet = {};
1174 }
1175
1176 otherStateToSet = pickState(otherStateToSet);
1177
1178 _this.internalSetState(function (_ref9) {
1179 var isOpen = _ref9.isOpen;
1180 return _extends({
1181 isOpen: !isOpen
1182 }, isOpen && {
1183 highlightedIndex: _this.props.defaultHighlightedIndex
1184 }, otherStateToSet);
1185 }, function () {
1186 var _this$getState7 = _this.getState(),
1187 isOpen = _this$getState7.isOpen,
1188 highlightedIndex = _this$getState7.highlightedIndex;
1189
1190 if (isOpen) {
1191 if (_this.getItemCount() > 0 && typeof highlightedIndex === 'number') {
1192 _this.setHighlightedIndex(highlightedIndex, otherStateToSet);
1193 }
1194 }
1195
1196 cbToCb(cb)();
1197 });
1198 };
1199
1200 _this.openMenu = function (cb) {
1201 _this.internalSetState({
1202 isOpen: true
1203 }, cb);
1204 };
1205
1206 _this.closeMenu = function (cb) {
1207 _this.internalSetState({
1208 isOpen: false
1209 }, cb);
1210 };
1211
1212 _this.updateStatus = debounce(function () {
1213 var state = _this.getState();
1214
1215 var item = _this.items[state.highlightedIndex];
1216
1217 var resultCount = _this.getItemCount();
1218
1219 var status = _this.props.getA11yStatusMessage(_extends({
1220 itemToString: _this.props.itemToString,
1221 previousResultCount: _this.previousResultCount,
1222 resultCount: resultCount,
1223 highlightedItem: item
1224 }, state));
1225
1226 _this.previousResultCount = resultCount;
1227 setStatus(status, _this.props.environment.document);
1228 }, 200);
1229
1230 var _this$props = _this.props,
1231 defaultHighlightedIndex = _this$props.defaultHighlightedIndex,
1232 _this$props$initialHi = _this$props.initialHighlightedIndex,
1233 _highlightedIndex = _this$props$initialHi === void 0 ? defaultHighlightedIndex : _this$props$initialHi,
1234 defaultIsOpen = _this$props.defaultIsOpen,
1235 _this$props$initialIs = _this$props.initialIsOpen,
1236 _isOpen = _this$props$initialIs === void 0 ? defaultIsOpen : _this$props$initialIs,
1237 _this$props$initialIn = _this$props.initialInputValue,
1238 _inputValue = _this$props$initialIn === void 0 ? '' : _this$props$initialIn,
1239 _this$props$initialSe = _this$props.initialSelectedItem,
1240 _selectedItem = _this$props$initialSe === void 0 ? null : _this$props$initialSe;
1241
1242 var _state = _this.getState({
1243 highlightedIndex: _highlightedIndex,
1244 isOpen: _isOpen,
1245 inputValue: _inputValue,
1246 selectedItem: _selectedItem
1247 });
1248
1249 if (_state.selectedItem != null && _this.props.initialInputValue === undefined) {
1250 _state.inputValue = _this.props.itemToString(_state.selectedItem);
1251 }
1252
1253 _this.state = _state;
1254 return _this;
1255 }
1256
1257 var _proto = Downshift.prototype;
1258
1259 /**
1260 * Clear all running timeouts
1261 */
1262 _proto.internalClearTimeouts = function internalClearTimeouts() {
1263 this.timeoutIds.forEach(function (id) {
1264 clearTimeout(id);
1265 });
1266 this.timeoutIds = [];
1267 }
1268 /**
1269 * Gets the state based on internal state or props
1270 * If a state value is passed via props, then that
1271 * is the value given, otherwise it's retrieved from
1272 * stateToMerge
1273 *
1274 * @param {Object} stateToMerge defaults to this.state
1275 * @return {Object} the state
1276 */
1277 ;
1278
1279 _proto.getState = function getState$1(stateToMerge) {
1280 if (stateToMerge === void 0) {
1281 stateToMerge = this.state;
1282 }
1283
1284 return getState(stateToMerge, this.props);
1285 };
1286
1287 _proto.getItemCount = function getItemCount() {
1288 // things read better this way. They're in priority order:
1289 // 1. `this.itemCount`
1290 // 2. `this.props.itemCount`
1291 // 3. `this.items.length`
1292 var itemCount = this.items.length;
1293
1294 if (this.itemCount != null) {
1295 itemCount = this.itemCount;
1296 } else if (this.props.itemCount !== undefined) {
1297 itemCount = this.props.itemCount;
1298 }
1299
1300 return itemCount;
1301 };
1302
1303 _proto.getItemNodeFromIndex = function getItemNodeFromIndex(index) {
1304 return this.props.environment.document.getElementById(this.getItemId(index));
1305 };
1306
1307 _proto.scrollHighlightedItemIntoView = function scrollHighlightedItemIntoView() {
1308 /* istanbul ignore else (react-native) */
1309 {
1310 var node = this.getItemNodeFromIndex(this.getState().highlightedIndex);
1311 this.props.scrollIntoView(node, this._menuNode);
1312 }
1313 };
1314
1315 _proto.moveHighlightedIndex = function moveHighlightedIndex(amount, otherStateToSet) {
1316 var _this6 = this;
1317
1318 var itemCount = this.getItemCount();
1319
1320 var _this$getState8 = this.getState(),
1321 highlightedIndex = _this$getState8.highlightedIndex;
1322
1323 if (itemCount > 0) {
1324 var nextHighlightedIndex = getNextWrappingIndex(amount, highlightedIndex, itemCount, function (index) {
1325 return _this6.getItemNodeFromIndex(index);
1326 });
1327 this.setHighlightedIndex(nextHighlightedIndex, otherStateToSet);
1328 }
1329 };
1330
1331 _proto.getStateAndHelpers = function getStateAndHelpers() {
1332 var _this$getState9 = this.getState(),
1333 highlightedIndex = _this$getState9.highlightedIndex,
1334 inputValue = _this$getState9.inputValue,
1335 selectedItem = _this$getState9.selectedItem,
1336 isOpen = _this$getState9.isOpen;
1337
1338 var itemToString = this.props.itemToString;
1339 var id = this.id;
1340 var getRootProps = this.getRootProps,
1341 getToggleButtonProps = this.getToggleButtonProps,
1342 getLabelProps = this.getLabelProps,
1343 getMenuProps = this.getMenuProps,
1344 getInputProps = this.getInputProps,
1345 getItemProps = this.getItemProps,
1346 openMenu = this.openMenu,
1347 closeMenu = this.closeMenu,
1348 toggleMenu = this.toggleMenu,
1349 selectItem = this.selectItem,
1350 selectItemAtIndex = this.selectItemAtIndex,
1351 selectHighlightedItem = this.selectHighlightedItem,
1352 setHighlightedIndex = this.setHighlightedIndex,
1353 clearSelection = this.clearSelection,
1354 clearItems = this.clearItems,
1355 reset = this.reset,
1356 setItemCount = this.setItemCount,
1357 unsetItemCount = this.unsetItemCount,
1358 setState = this.internalSetState;
1359 return {
1360 // prop getters
1361 getRootProps: getRootProps,
1362 getToggleButtonProps: getToggleButtonProps,
1363 getLabelProps: getLabelProps,
1364 getMenuProps: getMenuProps,
1365 getInputProps: getInputProps,
1366 getItemProps: getItemProps,
1367 // actions
1368 reset: reset,
1369 openMenu: openMenu,
1370 closeMenu: closeMenu,
1371 toggleMenu: toggleMenu,
1372 selectItem: selectItem,
1373 selectItemAtIndex: selectItemAtIndex,
1374 selectHighlightedItem: selectHighlightedItem,
1375 setHighlightedIndex: setHighlightedIndex,
1376 clearSelection: clearSelection,
1377 clearItems: clearItems,
1378 setItemCount: setItemCount,
1379 unsetItemCount: unsetItemCount,
1380 setState: setState,
1381 // props
1382 itemToString: itemToString,
1383 // derived
1384 id: id,
1385 // state
1386 highlightedIndex: highlightedIndex,
1387 inputValue: inputValue,
1388 isOpen: isOpen,
1389 selectedItem: selectedItem
1390 };
1391 } //////////////////////////// ROOT
1392 ;
1393
1394 _proto.componentDidMount = function componentDidMount() {
1395 var _this7 = this;
1396
1397 /* istanbul ignore if (react-native) */
1398 if (process.env.NODE_ENV !== 'production' && !false && this.getMenuProps.called && !this.getMenuProps.suppressRefError) {
1399 validateGetMenuPropsCalledCorrectly(this._menuNode, this.getMenuProps);
1400 }
1401 /* istanbul ignore if (react-native) */
1402
1403
1404 {
1405 // this.isMouseDown helps us track whether the mouse is currently held down.
1406 // This is useful when the user clicks on an item in the list, but holds the mouse
1407 // down long enough for the list to disappear (because the blur event fires on the input)
1408 // this.isMouseDown is used in the blur handler on the input to determine whether the blur event should
1409 // trigger hiding the menu.
1410 var onMouseDown = function onMouseDown() {
1411 _this7.isMouseDown = true;
1412 };
1413
1414 var onMouseUp = function onMouseUp(event) {
1415 _this7.isMouseDown = false; // if the target element or the activeElement is within a downshift node
1416 // then we don't want to reset downshift
1417
1418 var contextWithinDownshift = targetWithinDownshift(event.target, [_this7._rootNode, _this7._menuNode], _this7.props.environment.document);
1419
1420 if (!contextWithinDownshift && _this7.getState().isOpen) {
1421 _this7.reset({
1422 type: mouseUp
1423 }, function () {
1424 return _this7.props.onOuterClick(_this7.getStateAndHelpers());
1425 });
1426 }
1427 }; // Touching an element in iOS gives focus and hover states, but touching out of
1428 // the element will remove hover, and persist the focus state, resulting in the
1429 // blur event not being triggered.
1430 // this.isTouchMove helps us track whether the user is tapping or swiping on a touch screen.
1431 // If the user taps outside of Downshift, the component should be reset,
1432 // but not if the user is swiping
1433
1434
1435 var onTouchStart = function onTouchStart() {
1436 _this7.isTouchMove = false;
1437 };
1438
1439 var onTouchMove = function onTouchMove() {
1440 _this7.isTouchMove = true;
1441 };
1442
1443 var onTouchEnd = function onTouchEnd(event) {
1444 var contextWithinDownshift = targetWithinDownshift(event.target, [_this7._rootNode, _this7._menuNode], _this7.props.environment.document, false);
1445
1446 if (!_this7.isTouchMove && !contextWithinDownshift && _this7.getState().isOpen) {
1447 _this7.reset({
1448 type: touchEnd
1449 }, function () {
1450 return _this7.props.onOuterClick(_this7.getStateAndHelpers());
1451 });
1452 }
1453 };
1454
1455 var environment = this.props.environment;
1456 environment.addEventListener('mousedown', onMouseDown);
1457 environment.addEventListener('mouseup', onMouseUp);
1458 environment.addEventListener('touchstart', onTouchStart);
1459 environment.addEventListener('touchmove', onTouchMove);
1460 environment.addEventListener('touchend', onTouchEnd);
1461
1462 this.cleanup = function () {
1463 _this7.internalClearTimeouts();
1464
1465 _this7.updateStatus.cancel();
1466
1467 environment.removeEventListener('mousedown', onMouseDown);
1468 environment.removeEventListener('mouseup', onMouseUp);
1469 environment.removeEventListener('touchstart', onTouchStart);
1470 environment.removeEventListener('touchmove', onTouchMove);
1471 environment.removeEventListener('touchend', onTouchEnd);
1472 };
1473 }
1474 };
1475
1476 _proto.shouldScroll = function shouldScroll(prevState, prevProps) {
1477 var _ref10 = this.props.highlightedIndex === undefined ? this.getState() : this.props,
1478 currentHighlightedIndex = _ref10.highlightedIndex;
1479
1480 var _ref11 = prevProps.highlightedIndex === undefined ? prevState : prevProps,
1481 prevHighlightedIndex = _ref11.highlightedIndex;
1482
1483 var scrollWhenOpen = currentHighlightedIndex && this.getState().isOpen && !prevState.isOpen;
1484 var scrollWhenNavigating = currentHighlightedIndex !== prevHighlightedIndex;
1485 return scrollWhenOpen || scrollWhenNavigating;
1486 };
1487
1488 _proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState) {
1489 if (process.env.NODE_ENV !== 'production') {
1490 validateControlledUnchanged(this.state, prevProps, this.props);
1491 /* istanbul ignore if (react-native) */
1492
1493 if ( this.getMenuProps.called && !this.getMenuProps.suppressRefError) {
1494 validateGetMenuPropsCalledCorrectly(this._menuNode, this.getMenuProps);
1495 }
1496 }
1497
1498 if (isControlledProp(this.props, 'selectedItem') && this.props.selectedItemChanged(prevProps.selectedItem, this.props.selectedItem)) {
1499 this.internalSetState({
1500 type: controlledPropUpdatedSelectedItem,
1501 inputValue: this.props.itemToString(this.props.selectedItem)
1502 });
1503 }
1504
1505 if (!this.avoidScrolling && this.shouldScroll(prevState, prevProps)) {
1506 this.scrollHighlightedItemIntoView();
1507 }
1508 /* istanbul ignore else (react-native) */
1509
1510
1511 {
1512 this.updateStatus();
1513 }
1514 };
1515
1516 _proto.componentWillUnmount = function componentWillUnmount() {
1517 this.cleanup(); // avoids memory leak
1518 };
1519
1520 _proto.render = function render() {
1521 var children = unwrapArray(this.props.children, noop); // because the items are rerendered every time we call the children
1522 // we clear this out each render and it will be populated again as
1523 // getItemProps is called.
1524
1525 this.clearItems(); // we reset this so we know whether the user calls getRootProps during
1526 // this render. If they do then we don't need to do anything,
1527 // if they don't then we need to clone the element they return and
1528 // apply the props for them.
1529
1530 this.getRootProps.called = false;
1531 this.getRootProps.refKey = undefined;
1532 this.getRootProps.suppressRefError = undefined; // we do something similar for getMenuProps
1533
1534 this.getMenuProps.called = false;
1535 this.getMenuProps.refKey = undefined;
1536 this.getMenuProps.suppressRefError = undefined; // we do something similar for getLabelProps
1537
1538 this.getLabelProps.called = false; // and something similar for getInputProps
1539
1540 this.getInputProps.called = false;
1541 var element = unwrapArray(children(this.getStateAndHelpers()));
1542
1543 if (!element) {
1544 return null;
1545 }
1546
1547 if (this.getRootProps.called || this.props.suppressRefError) {
1548 if (process.env.NODE_ENV !== 'production' && !this.getRootProps.suppressRefError && !this.props.suppressRefError) {
1549 validateGetRootPropsCalledCorrectly(element, this.getRootProps);
1550 }
1551
1552 return element;
1553 } else if (isDOMElement(element)) {
1554 // they didn't apply the root props, but we can clone
1555 // this and apply the props ourselves
1556 return /*#__PURE__*/cloneElement(element, this.getRootProps(getElementProps(element)));
1557 }
1558 /* istanbul ignore else */
1559
1560
1561 if (process.env.NODE_ENV !== 'production') {
1562 // they didn't apply the root props, but they need to
1563 // otherwise we can't query around the autocomplete
1564 throw new Error('downshift: If you return a non-DOM element, you must apply the getRootProps function');
1565 }
1566 /* istanbul ignore next */
1567
1568
1569 return undefined;
1570 };
1571
1572 return Downshift;
1573 }(Component);
1574
1575 Downshift.defaultProps = {
1576 defaultHighlightedIndex: null,
1577 defaultIsOpen: false,
1578 getA11yStatusMessage: getA11yStatusMessage,
1579 itemToString: function itemToString(i) {
1580 if (i == null) {
1581 return '';
1582 }
1583
1584 if (process.env.NODE_ENV !== 'production' && isPlainObject(i) && !i.hasOwnProperty('toString')) {
1585 // eslint-disable-next-line no-console
1586 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);
1587 }
1588
1589 return String(i);
1590 },
1591 onStateChange: noop,
1592 onInputValueChange: noop,
1593 onUserAction: noop,
1594 onChange: noop,
1595 onSelect: noop,
1596 onOuterClick: noop,
1597 selectedItemChanged: function selectedItemChanged(prevItem, item) {
1598 return prevItem !== item;
1599 },
1600 environment: typeof window === 'undefined'
1601 /* istanbul ignore next (ssr) */
1602 ? {} : window,
1603 stateReducer: function stateReducer(state, stateToSet) {
1604 return stateToSet;
1605 },
1606 suppressRefError: false,
1607 scrollIntoView: scrollIntoView
1608 };
1609 Downshift.stateChangeTypes = stateChangeTypes;
1610 return Downshift;
1611}();
1612
1613process.env.NODE_ENV !== "production" ? Downshift.propTypes = {
1614 children: PropTypes.func,
1615 defaultHighlightedIndex: PropTypes.number,
1616 defaultIsOpen: PropTypes.bool,
1617 initialHighlightedIndex: PropTypes.number,
1618 initialSelectedItem: PropTypes.any,
1619 initialInputValue: PropTypes.string,
1620 initialIsOpen: PropTypes.bool,
1621 getA11yStatusMessage: PropTypes.func,
1622 itemToString: PropTypes.func,
1623 onChange: PropTypes.func,
1624 onSelect: PropTypes.func,
1625 onStateChange: PropTypes.func,
1626 onInputValueChange: PropTypes.func,
1627 onUserAction: PropTypes.func,
1628 onOuterClick: PropTypes.func,
1629 selectedItemChanged: PropTypes.func,
1630 stateReducer: PropTypes.func,
1631 itemCount: PropTypes.number,
1632 id: PropTypes.string,
1633 environment: PropTypes.shape({
1634 addEventListener: PropTypes.func,
1635 removeEventListener: PropTypes.func,
1636 document: PropTypes.shape({
1637 getElementById: PropTypes.func,
1638 activeElement: PropTypes.any,
1639 body: PropTypes.any
1640 })
1641 }),
1642 suppressRefError: PropTypes.bool,
1643 scrollIntoView: PropTypes.func,
1644 // things we keep in state for uncontrolled components
1645 // but can accept as props for controlled components
1646
1647 /* eslint-disable react/no-unused-prop-types */
1648 selectedItem: PropTypes.any,
1649 isOpen: PropTypes.bool,
1650 inputValue: PropTypes.string,
1651 highlightedIndex: PropTypes.number,
1652 labelId: PropTypes.string,
1653 inputId: PropTypes.string,
1654 menuId: PropTypes.string,
1655 getItemId: PropTypes.func
1656 /* eslint-enable react/no-unused-prop-types */
1657
1658} : void 0;
1659
1660function validateGetMenuPropsCalledCorrectly(node, _ref12) {
1661 var refKey = _ref12.refKey;
1662
1663 if (!node) {
1664 // eslint-disable-next-line no-console
1665 console.error("downshift: The ref prop \"" + refKey + "\" from getMenuProps was not applied correctly on your menu element.");
1666 }
1667}
1668
1669function validateGetRootPropsCalledCorrectly(element, _ref13) {
1670 var refKey = _ref13.refKey;
1671 var refKeySpecified = refKey !== 'ref';
1672 var isComposite = !isDOMElement(element);
1673
1674 if (isComposite && !refKeySpecified && !isForwardRef(element)) {
1675 // eslint-disable-next-line no-console
1676 console.error('downshift: You returned a non-DOM element. You must specify a refKey in getRootProps');
1677 } else if (!isComposite && refKeySpecified) {
1678 // eslint-disable-next-line no-console
1679 console.error("downshift: You returned a DOM element. You should not specify a refKey in getRootProps. You specified \"" + refKey + "\"");
1680 }
1681
1682 if (!isForwardRef(element) && !getElementProps(element)[refKey]) {
1683 // eslint-disable-next-line no-console
1684 console.error("downshift: You must apply the ref prop \"" + refKey + "\" from getRootProps onto your root element.");
1685 }
1686}
1687
1688var dropdownDefaultStateValues = {
1689 highlightedIndex: -1,
1690 isOpen: false,
1691 selectedItem: null,
1692 inputValue: ''
1693};
1694
1695function callOnChangeProps(action, state, newState) {
1696 var props = action.props,
1697 type = action.type;
1698 var changes = {};
1699 Object.keys(state).forEach(function (key) {
1700 invokeOnChangeHandler(key, action, state, newState);
1701
1702 if (newState[key] !== state[key]) {
1703 changes[key] = newState[key];
1704 }
1705 });
1706
1707 if (props.onStateChange && Object.keys(changes).length) {
1708 props.onStateChange(_extends({
1709 type: type
1710 }, changes));
1711 }
1712}
1713
1714function invokeOnChangeHandler(key, action, state, newState) {
1715 var props = action.props,
1716 type = action.type;
1717 var handler = "on" + capitalizeString(key) + "Change";
1718
1719 if (props[handler] && newState[key] !== undefined && newState[key] !== state[key]) {
1720 props[handler](_extends({
1721 type: type
1722 }, newState));
1723 }
1724}
1725/**
1726 * Default state reducer that returns the changes.
1727 *
1728 * @param {Object} s state.
1729 * @param {Object} a action with changes.
1730 * @returns {Object} changes.
1731 */
1732
1733
1734function stateReducer(s, a) {
1735 return a.changes;
1736}
1737/**
1738 * Returns a message to be added to aria-live region when item is selected.
1739 *
1740 * @param {Object} selectionParameters Parameters required to build the message.
1741 * @returns {string} The a11y message.
1742 */
1743
1744
1745function getA11ySelectionMessage(selectionParameters) {
1746 var selectedItem = selectionParameters.selectedItem,
1747 itemToStringLocal = selectionParameters.itemToString;
1748 return selectedItem ? itemToStringLocal(selectedItem) + " has been selected." : '';
1749}
1750/**
1751 * Debounced call for updating the a11y message.
1752 */
1753
1754
1755var updateA11yStatus = debounce(function (getA11yMessage, document) {
1756 setStatus(getA11yMessage(), document);
1757}, 200); // istanbul ignore next
1758
1759var useIsomorphicLayoutEffect = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined' ? useLayoutEffect : useEffect;
1760function getElementIds(_ref) {
1761 var id = _ref.id,
1762 labelId = _ref.labelId,
1763 menuId = _ref.menuId,
1764 getItemId = _ref.getItemId,
1765 toggleButtonId = _ref.toggleButtonId;
1766 var uniqueId = id === undefined ? "downshift-" + generateId() : id;
1767 return {
1768 labelId: labelId || uniqueId + "-label",
1769 menuId: menuId || uniqueId + "-menu",
1770 getItemId: getItemId || function (index) {
1771 return uniqueId + "-item-" + index;
1772 },
1773 toggleButtonId: toggleButtonId || uniqueId + "-toggle-button"
1774 };
1775}
1776function getItemIndex(index, item, items) {
1777 if (index !== undefined) {
1778 return index;
1779 }
1780
1781 if (items.length === 0) {
1782 return -1;
1783 }
1784
1785 return items.indexOf(item);
1786}
1787
1788function itemToString(item) {
1789 return item ? String(item) : '';
1790}
1791
1792function getPropTypesValidator(caller, propTypes) {
1793 // istanbul ignore next
1794 return function validate(options) {
1795 if (options === void 0) {
1796 options = {};
1797 }
1798
1799 Object.keys(propTypes).forEach(function (key) {
1800 PropTypes.checkPropTypes(propTypes, options, key, caller.name);
1801 });
1802 };
1803}
1804function isAcceptedCharacterKey(key) {
1805 return /^\S{1}$/.test(key);
1806}
1807function capitalizeString(string) {
1808 return "" + string.slice(0, 1).toUpperCase() + string.slice(1);
1809}
1810function useLatestRef(val) {
1811 var ref = useRef(val); // technically this is not "concurrent mode safe" because we're manipulating
1812 // the value during render (so it's not idempotent). However, the places this
1813 // hook is used is to support memoizing callbacks which will be called
1814 // *during* render, so we need the latest values *during* render.
1815 // If not for this, then we'd probably want to use useLayoutEffect instead.
1816
1817 ref.current = val;
1818 return ref;
1819}
1820/**
1821 * Computes the controlled state using a the previous state, props,
1822 * two reducers, one from downshift and an optional one from the user.
1823 * Also calls the onChange handlers for state values that have changed.
1824 *
1825 * @param {Function} reducer Reducer function from downshift.
1826 * @param {Object} initialState Initial state of the hook.
1827 * @param {Object} props The hook props.
1828 * @returns {Array} An array with the state and an action dispatcher.
1829 */
1830
1831function useEnhancedReducer(reducer, initialState, props) {
1832 var prevStateRef = useRef();
1833 var actionRef = useRef();
1834 var enhancedReducer = useCallback(function (state, action) {
1835 actionRef.current = action;
1836 state = getState(state, action.props);
1837 var changes = reducer(state, action);
1838 var newState = action.props.stateReducer(state, _extends({}, action, {
1839 changes: changes
1840 }));
1841 return newState;
1842 }, [reducer]);
1843
1844 var _useReducer = useReducer(enhancedReducer, initialState),
1845 state = _useReducer[0],
1846 dispatch = _useReducer[1];
1847
1848 var propsRef = useLatestRef(props);
1849 var dispatchWithProps = useCallback(function (action) {
1850 return dispatch(_extends({
1851 props: propsRef.current
1852 }, action));
1853 }, [propsRef]);
1854 var action = actionRef.current;
1855 useEffect(function () {
1856 if (action && prevStateRef.current && prevStateRef.current !== state) {
1857 callOnChangeProps(action, getState(prevStateRef.current, action.props), state);
1858 }
1859
1860 prevStateRef.current = state;
1861 }, [state, props, action]);
1862 return [state, dispatchWithProps];
1863}
1864/**
1865 * Wraps the useEnhancedReducer and applies the controlled prop values before
1866 * returning the new state.
1867 *
1868 * @param {Function} reducer Reducer function from downshift.
1869 * @param {Object} initialState Initial state of the hook.
1870 * @param {Object} props The hook props.
1871 * @returns {Array} An array with the state and an action dispatcher.
1872 */
1873
1874function useControlledReducer(reducer, initialState, props) {
1875 var _useEnhancedReducer = useEnhancedReducer(reducer, initialState, props),
1876 state = _useEnhancedReducer[0],
1877 dispatch = _useEnhancedReducer[1];
1878
1879 return [getState(state, props), dispatch];
1880}
1881var defaultProps = {
1882 itemToString: itemToString,
1883 stateReducer: stateReducer,
1884 getA11ySelectionMessage: getA11ySelectionMessage,
1885 scrollIntoView: scrollIntoView,
1886 circularNavigation: false,
1887 environment: typeof window === 'undefined'
1888 /* istanbul ignore next (ssr) */
1889 ? {} : window
1890};
1891function getDefaultValue(props, propKey, defaultStateValues) {
1892 if (defaultStateValues === void 0) {
1893 defaultStateValues = dropdownDefaultStateValues;
1894 }
1895
1896 var defaultPropKey = "default" + capitalizeString(propKey);
1897
1898 if (defaultPropKey in props) {
1899 return props[defaultPropKey];
1900 }
1901
1902 return defaultStateValues[propKey];
1903}
1904function getInitialValue(props, propKey, defaultStateValues) {
1905 if (defaultStateValues === void 0) {
1906 defaultStateValues = dropdownDefaultStateValues;
1907 }
1908
1909 if (propKey in props) {
1910 return props[propKey];
1911 }
1912
1913 var initialPropKey = "initial" + capitalizeString(propKey);
1914
1915 if (initialPropKey in props) {
1916 return props[initialPropKey];
1917 }
1918
1919 return getDefaultValue(props, propKey, defaultStateValues);
1920}
1921function getInitialState(props) {
1922 var selectedItem = getInitialValue(props, 'selectedItem');
1923 var isOpen = getInitialValue(props, 'isOpen');
1924 var highlightedIndex = getInitialValue(props, 'highlightedIndex');
1925 var inputValue = getInitialValue(props, 'inputValue');
1926 return {
1927 highlightedIndex: highlightedIndex < 0 && selectedItem && isOpen ? props.items.indexOf(selectedItem) : highlightedIndex,
1928 isOpen: isOpen,
1929 selectedItem: selectedItem,
1930 inputValue: inputValue
1931 };
1932}
1933function getHighlightedIndexOnOpen(props, state, offset, getItemNodeFromIndex) {
1934 var items = props.items,
1935 initialHighlightedIndex = props.initialHighlightedIndex,
1936 defaultHighlightedIndex = props.defaultHighlightedIndex;
1937 var selectedItem = state.selectedItem,
1938 highlightedIndex = state.highlightedIndex;
1939
1940 if (items.length === 0) {
1941 return -1;
1942 } // initialHighlightedIndex will give value to highlightedIndex on initial state only.
1943
1944
1945 if (initialHighlightedIndex !== undefined && highlightedIndex === initialHighlightedIndex) {
1946 return initialHighlightedIndex;
1947 }
1948
1949 if (defaultHighlightedIndex !== undefined) {
1950 return defaultHighlightedIndex;
1951 }
1952
1953 if (selectedItem) {
1954 if (offset === 0) {
1955 return items.indexOf(selectedItem);
1956 }
1957
1958 return getNextWrappingIndex(offset, items.indexOf(selectedItem), items.length, getItemNodeFromIndex, false);
1959 }
1960
1961 if (offset === 0) {
1962 return -1;
1963 }
1964
1965 return offset < 0 ? items.length - 1 : 0;
1966}
1967/**
1968 * Reuse the movement tracking of mouse and touch events.
1969 *
1970 * @param {boolean} isOpen Whether the dropdown is open or not.
1971 * @param {Array<Object>} downshiftElementRefs Downshift element refs to track movement (toggleButton, menu etc.)
1972 * @param {Object} environment Environment where component/hook exists.
1973 * @param {Function} handleBlur Handler on blur from mouse or touch.
1974 * @returns {Object} Ref containing whether mouseDown or touchMove event is happening
1975 */
1976
1977function useMouseAndTouchTracker(isOpen, downshiftElementRefs, environment, handleBlur) {
1978 var mouseAndTouchTrackersRef = useRef({
1979 isMouseDown: false,
1980 isTouchMove: false
1981 });
1982 useEffect(function () {
1983 // The same strategy for checking if a click occurred inside or outside downsift
1984 // as in downshift.js.
1985 var onMouseDown = function onMouseDown() {
1986 mouseAndTouchTrackersRef.current.isMouseDown = true;
1987 };
1988
1989 var onMouseUp = function onMouseUp(event) {
1990 mouseAndTouchTrackersRef.current.isMouseDown = false;
1991
1992 if (isOpen && !targetWithinDownshift(event.target, downshiftElementRefs.map(function (ref) {
1993 return ref.current;
1994 }), environment.document)) {
1995 handleBlur();
1996 }
1997 };
1998
1999 var onTouchStart = function onTouchStart() {
2000 mouseAndTouchTrackersRef.current.isTouchMove = false;
2001 };
2002
2003 var onTouchMove = function onTouchMove() {
2004 mouseAndTouchTrackersRef.current.isTouchMove = true;
2005 };
2006
2007 var onTouchEnd = function onTouchEnd(event) {
2008 if (isOpen && !mouseAndTouchTrackersRef.current.isTouchMove && !targetWithinDownshift(event.target, downshiftElementRefs.map(function (ref) {
2009 return ref.current;
2010 }), environment.document, false)) {
2011 handleBlur();
2012 }
2013 };
2014
2015 environment.addEventListener('mousedown', onMouseDown);
2016 environment.addEventListener('mouseup', onMouseUp);
2017 environment.addEventListener('touchstart', onTouchStart);
2018 environment.addEventListener('touchmove', onTouchMove);
2019 environment.addEventListener('touchend', onTouchEnd);
2020 return function cleanup() {
2021 environment.removeEventListener('mousedown', onMouseDown);
2022 environment.removeEventListener('mouseup', onMouseUp);
2023 environment.removeEventListener('touchstart', onTouchStart);
2024 environment.removeEventListener('touchmove', onTouchMove);
2025 environment.removeEventListener('touchend', onTouchEnd);
2026 }; // eslint-disable-next-line react-hooks/exhaustive-deps
2027 }, [isOpen, environment]);
2028 return mouseAndTouchTrackersRef;
2029}
2030/**
2031 * Custom hook that checks if getter props are called correctly.
2032 *
2033 * @param {...any} propKeys Getter prop names to be handled.
2034 * @returns {Function} Setter function called inside getter props to set call information.
2035 */
2036
2037function useGetterPropsCalledChecker() {
2038 var isNotProduction = process.env.NODE_ENV !== 'production';
2039 var isInitialMountRef = useRef(true);
2040
2041 for (var _len = arguments.length, propKeys = new Array(_len), _key = 0; _key < _len; _key++) {
2042 propKeys[_key] = arguments[_key];
2043 }
2044
2045 var getterPropsCalledRef = useRef(propKeys.reduce(function (acc, propKey) {
2046 acc[propKey] = {};
2047 return acc;
2048 }, {}));
2049 useEffect(function () {
2050 if (!isNotProduction) {
2051 return;
2052 }
2053
2054 Object.keys(getterPropsCalledRef.current).forEach(function (propKey) {
2055 var propCallInfo = getterPropsCalledRef.current[propKey];
2056
2057 if (isInitialMountRef.current) {
2058 if (!Object.keys(propCallInfo).length) {
2059 // eslint-disable-next-line no-console
2060 console.error("downshift: You forgot to call the " + propKey + " getter function on your component / element.");
2061 return;
2062 }
2063 }
2064
2065 var suppressRefError = propCallInfo.suppressRefError,
2066 refKey = propCallInfo.refKey,
2067 elementRef = propCallInfo.elementRef;
2068
2069 if ((!elementRef || !elementRef.current) && !suppressRefError) {
2070 // eslint-disable-next-line no-console
2071 console.error("downshift: The ref prop \"" + refKey + "\" from " + propKey + " was not applied correctly on your element.");
2072 }
2073 });
2074 isInitialMountRef.current = false;
2075 });
2076 var setGetterPropCallInfo = useCallback(function (propKey, suppressRefError, refKey, elementRef) {
2077 if (process.env.NODE_ENV !== 'production') {
2078 getterPropsCalledRef.current[propKey] = {
2079 suppressRefError: suppressRefError,
2080 refKey: refKey,
2081 elementRef: elementRef
2082 };
2083 }
2084 }, []);
2085 return setGetterPropCallInfo;
2086}
2087function useA11yMessageSetter(getA11yMessage, dependencyArray, _ref2) {
2088 var isInitialMount = _ref2.isInitialMount,
2089 previousResultCount = _ref2.previousResultCount,
2090 highlightedIndex = _ref2.highlightedIndex,
2091 items = _ref2.items,
2092 environment = _ref2.environment,
2093 rest = _objectWithoutPropertiesLoose(_ref2, ["isInitialMount", "previousResultCount", "highlightedIndex", "items", "environment"]);
2094
2095 // Sets a11y status message on changes in state.
2096 useEffect(function () {
2097 if (isInitialMount) {
2098 return;
2099 }
2100
2101 updateA11yStatus(function () {
2102 return getA11yMessage(_extends({
2103 highlightedIndex: highlightedIndex,
2104 highlightedItem: items[highlightedIndex],
2105 resultCount: items.length,
2106 previousResultCount: previousResultCount
2107 }, rest));
2108 }, environment.document); // eslint-disable-next-line react-hooks/exhaustive-deps
2109 }, dependencyArray);
2110}
2111function useScrollIntoView(_ref3) {
2112 var highlightedIndex = _ref3.highlightedIndex,
2113 isOpen = _ref3.isOpen,
2114 itemRefs = _ref3.itemRefs,
2115 getItemNodeFromIndex = _ref3.getItemNodeFromIndex,
2116 menuElement = _ref3.menuElement,
2117 scrollIntoViewProp = _ref3.scrollIntoView;
2118 // used not to scroll on highlight by mouse.
2119 var shouldScrollRef = useRef(true); // Scroll on highlighted item if change comes from keyboard.
2120
2121 useIsomorphicLayoutEffect(function () {
2122 if (highlightedIndex < 0 || !isOpen || !Object.keys(itemRefs.current).length) {
2123 return;
2124 }
2125
2126 if (shouldScrollRef.current === false) {
2127 shouldScrollRef.current = true;
2128 } else {
2129 scrollIntoViewProp(getItemNodeFromIndex(highlightedIndex), menuElement);
2130 } // eslint-disable-next-line react-hooks/exhaustive-deps
2131
2132 }, [highlightedIndex]);
2133 return shouldScrollRef;
2134}
2135function useControlPropsValidator(_ref4) {
2136 var isInitialMount = _ref4.isInitialMount,
2137 props = _ref4.props,
2138 state = _ref4.state;
2139 // used for checking when props are moving from controlled to uncontrolled.
2140 var prevPropsRef = useRef(props);
2141 useEffect(function () {
2142 if (isInitialMount) {
2143 return;
2144 }
2145
2146 validateControlledUnchanged(state, prevPropsRef.current, props);
2147 prevPropsRef.current = props;
2148 }, [state, props, isInitialMount]);
2149}
2150
2151function getItemIndexByCharacterKey(keysSoFar, highlightedIndex, items, itemToStringParam, getItemNodeFromIndex) {
2152 var lowerCasedItemStrings = items.map(function (item) {
2153 return itemToStringParam(item).toLowerCase();
2154 });
2155 var lowerCasedKeysSoFar = keysSoFar.toLowerCase();
2156
2157 var isValid = function isValid(itemString, index) {
2158 var element = getItemNodeFromIndex(index);
2159 return itemString.startsWith(lowerCasedKeysSoFar) && !(element && element.hasAttribute('disabled'));
2160 };
2161
2162 for (var index = highlightedIndex + 1; index < lowerCasedItemStrings.length; index++) {
2163 var itemString = lowerCasedItemStrings[index];
2164
2165 if (isValid(itemString, index)) {
2166 return index;
2167 }
2168 }
2169
2170 for (var _index = 0; _index < highlightedIndex; _index++) {
2171 var _itemString = lowerCasedItemStrings[_index];
2172
2173 if (isValid(_itemString, _index)) {
2174 return _index;
2175 }
2176 }
2177
2178 return highlightedIndex;
2179}
2180
2181var propTypes = {
2182 items: PropTypes.array.isRequired,
2183 itemToString: PropTypes.func,
2184 getA11yStatusMessage: PropTypes.func,
2185 getA11ySelectionMessage: PropTypes.func,
2186 circularNavigation: PropTypes.bool,
2187 highlightedIndex: PropTypes.number,
2188 defaultHighlightedIndex: PropTypes.number,
2189 initialHighlightedIndex: PropTypes.number,
2190 isOpen: PropTypes.bool,
2191 defaultIsOpen: PropTypes.bool,
2192 initialIsOpen: PropTypes.bool,
2193 selectedItem: PropTypes.any,
2194 initialSelectedItem: PropTypes.any,
2195 defaultSelectedItem: PropTypes.any,
2196 id: PropTypes.string,
2197 labelId: PropTypes.string,
2198 menuId: PropTypes.string,
2199 getItemId: PropTypes.func,
2200 toggleButtonId: PropTypes.string,
2201 stateReducer: PropTypes.func,
2202 onSelectedItemChange: PropTypes.func,
2203 onHighlightedIndexChange: PropTypes.func,
2204 onStateChange: PropTypes.func,
2205 onIsOpenChange: PropTypes.func,
2206 environment: PropTypes.shape({
2207 addEventListener: PropTypes.func,
2208 removeEventListener: PropTypes.func,
2209 document: PropTypes.shape({
2210 getElementById: PropTypes.func,
2211 activeElement: PropTypes.any,
2212 body: PropTypes.any
2213 })
2214 })
2215};
2216/**
2217 * Default implementation for status message. Only added when menu is open.
2218 * Will specift if there are results in the list, and if so, how many,
2219 * and what keys are relevant.
2220 *
2221 * @param {Object} param the downshift state and other relevant properties
2222 * @return {String} the a11y status message
2223 */
2224
2225function getA11yStatusMessage$1(_ref) {
2226 var isOpen = _ref.isOpen,
2227 resultCount = _ref.resultCount,
2228 previousResultCount = _ref.previousResultCount;
2229
2230 if (!isOpen) {
2231 return '';
2232 }
2233
2234 if (!resultCount) {
2235 return 'No results are available.';
2236 }
2237
2238 if (resultCount !== previousResultCount) {
2239 return resultCount + " result" + (resultCount === 1 ? ' is' : 's are') + " available, use up and down arrow keys to navigate. Press Enter or Space Bar keys to select.";
2240 }
2241
2242 return '';
2243}
2244
2245var defaultProps$1 = _extends({}, defaultProps, {
2246 getA11yStatusMessage: getA11yStatusMessage$1
2247});
2248
2249var MenuKeyDownArrowDown = process.env.NODE_ENV !== "production" ? '__menu_keydown_arrow_down__' : 0;
2250var MenuKeyDownArrowUp = process.env.NODE_ENV !== "production" ? '__menu_keydown_arrow_up__' : 1;
2251var MenuKeyDownEscape = process.env.NODE_ENV !== "production" ? '__menu_keydown_escape__' : 2;
2252var MenuKeyDownHome = process.env.NODE_ENV !== "production" ? '__menu_keydown_home__' : 3;
2253var MenuKeyDownEnd = process.env.NODE_ENV !== "production" ? '__menu_keydown_end__' : 4;
2254var MenuKeyDownEnter = process.env.NODE_ENV !== "production" ? '__menu_keydown_enter__' : 5;
2255var MenuKeyDownSpaceButton = process.env.NODE_ENV !== "production" ? '__menu_keydown_space_button__' : 6;
2256var MenuKeyDownCharacter = process.env.NODE_ENV !== "production" ? '__menu_keydown_character__' : 7;
2257var MenuBlur = process.env.NODE_ENV !== "production" ? '__menu_blur__' : 8;
2258var MenuMouseLeave = process.env.NODE_ENV !== "production" ? '__menu_mouse_leave__' : 9;
2259var ItemMouseMove = process.env.NODE_ENV !== "production" ? '__item_mouse_move__' : 10;
2260var ItemClick = process.env.NODE_ENV !== "production" ? '__item_click__' : 11;
2261var ToggleButtonClick = process.env.NODE_ENV !== "production" ? '__togglebutton_click__' : 12;
2262var ToggleButtonKeyDownArrowDown = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_arrow_down__' : 13;
2263var ToggleButtonKeyDownArrowUp = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_arrow_up__' : 14;
2264var ToggleButtonKeyDownCharacter = process.env.NODE_ENV !== "production" ? '__togglebutton_keydown_character__' : 15;
2265var FunctionToggleMenu = process.env.NODE_ENV !== "production" ? '__function_toggle_menu__' : 16;
2266var FunctionOpenMenu = process.env.NODE_ENV !== "production" ? '__function_open_menu__' : 17;
2267var FunctionCloseMenu = process.env.NODE_ENV !== "production" ? '__function_close_menu__' : 18;
2268var FunctionSetHighlightedIndex = process.env.NODE_ENV !== "production" ? '__function_set_highlighted_index__' : 19;
2269var FunctionSelectItem = process.env.NODE_ENV !== "production" ? '__function_select_item__' : 20;
2270var FunctionSetInputValue = process.env.NODE_ENV !== "production" ? '__function_set_input_value__' : 21;
2271var FunctionReset = process.env.NODE_ENV !== "production" ? '__function_reset__' : 22;
2272
2273var stateChangeTypes$1 = /*#__PURE__*/Object.freeze({
2274 __proto__: null,
2275 MenuKeyDownArrowDown: MenuKeyDownArrowDown,
2276 MenuKeyDownArrowUp: MenuKeyDownArrowUp,
2277 MenuKeyDownEscape: MenuKeyDownEscape,
2278 MenuKeyDownHome: MenuKeyDownHome,
2279 MenuKeyDownEnd: MenuKeyDownEnd,
2280 MenuKeyDownEnter: MenuKeyDownEnter,
2281 MenuKeyDownSpaceButton: MenuKeyDownSpaceButton,
2282 MenuKeyDownCharacter: MenuKeyDownCharacter,
2283 MenuBlur: MenuBlur,
2284 MenuMouseLeave: MenuMouseLeave,
2285 ItemMouseMove: ItemMouseMove,
2286 ItemClick: ItemClick,
2287 ToggleButtonClick: ToggleButtonClick,
2288 ToggleButtonKeyDownArrowDown: ToggleButtonKeyDownArrowDown,
2289 ToggleButtonKeyDownArrowUp: ToggleButtonKeyDownArrowUp,
2290 ToggleButtonKeyDownCharacter: ToggleButtonKeyDownCharacter,
2291 FunctionToggleMenu: FunctionToggleMenu,
2292 FunctionOpenMenu: FunctionOpenMenu,
2293 FunctionCloseMenu: FunctionCloseMenu,
2294 FunctionSetHighlightedIndex: FunctionSetHighlightedIndex,
2295 FunctionSelectItem: FunctionSelectItem,
2296 FunctionSetInputValue: FunctionSetInputValue,
2297 FunctionReset: FunctionReset
2298});
2299
2300/* eslint-disable complexity */
2301
2302function downshiftSelectReducer(state, action) {
2303 var type = action.type,
2304 props = action.props,
2305 shiftKey = action.shiftKey;
2306 var changes;
2307
2308 switch (type) {
2309 case ItemMouseMove:
2310 changes = {
2311 highlightedIndex: action.index
2312 };
2313 break;
2314
2315 case ItemClick:
2316 changes = {
2317 isOpen: getDefaultValue(props, 'isOpen'),
2318 highlightedIndex: getDefaultValue(props, 'highlightedIndex'),
2319 selectedItem: props.items[action.index]
2320 };
2321 break;
2322
2323 case ToggleButtonKeyDownCharacter:
2324 {
2325 var lowercasedKey = action.key;
2326 var inputValue = "" + state.inputValue + lowercasedKey;
2327 var itemIndex = getItemIndexByCharacterKey(inputValue, state.selectedItem ? props.items.indexOf(state.selectedItem) : -1, props.items, props.itemToString, action.getItemNodeFromIndex);
2328 changes = _extends({
2329 inputValue: inputValue
2330 }, itemIndex >= 0 && {
2331 selectedItem: props.items[itemIndex]
2332 });
2333 }
2334 break;
2335
2336 case ToggleButtonKeyDownArrowDown:
2337 changes = {
2338 highlightedIndex: getHighlightedIndexOnOpen(props, state, 1, action.getItemNodeFromIndex),
2339 isOpen: true
2340 };
2341 break;
2342
2343 case ToggleButtonKeyDownArrowUp:
2344 changes = {
2345 highlightedIndex: getHighlightedIndexOnOpen(props, state, -1, action.getItemNodeFromIndex),
2346 isOpen: true
2347 };
2348 break;
2349
2350 case MenuKeyDownEnter:
2351 case MenuKeyDownSpaceButton:
2352 changes = _extends({
2353 isOpen: getDefaultValue(props, 'isOpen'),
2354 highlightedIndex: getDefaultValue(props, 'highlightedIndex')
2355 }, state.highlightedIndex >= 0 && {
2356 selectedItem: props.items[state.highlightedIndex]
2357 });
2358 break;
2359
2360 case MenuKeyDownHome:
2361 changes = {
2362 highlightedIndex: getNextNonDisabledIndex(1, 0, props.items.length, action.getItemNodeFromIndex, false)
2363 };
2364 break;
2365
2366 case MenuKeyDownEnd:
2367 changes = {
2368 highlightedIndex: getNextNonDisabledIndex(-1, props.items.length - 1, props.items.length, action.getItemNodeFromIndex, false)
2369 };
2370 break;
2371
2372 case MenuKeyDownEscape:
2373 changes = {
2374 isOpen: false,
2375 highlightedIndex: -1
2376 };
2377 break;
2378
2379 case MenuBlur:
2380 changes = {
2381 isOpen: false,
2382 highlightedIndex: -1
2383 };
2384 break;
2385
2386 case MenuKeyDownCharacter:
2387 {
2388 var _lowercasedKey = action.key;
2389
2390 var _inputValue = "" + state.inputValue + _lowercasedKey;
2391
2392 var highlightedIndex = getItemIndexByCharacterKey(_inputValue, state.highlightedIndex, props.items, props.itemToString, action.getItemNodeFromIndex);
2393 changes = _extends({
2394 inputValue: _inputValue
2395 }, highlightedIndex >= 0 && {
2396 highlightedIndex: highlightedIndex
2397 });
2398 }
2399 break;
2400
2401 case MenuKeyDownArrowDown:
2402 changes = {
2403 highlightedIndex: getNextWrappingIndex(shiftKey ? 5 : 1, state.highlightedIndex, props.items.length, action.getItemNodeFromIndex, props.circularNavigation)
2404 };
2405 break;
2406
2407 case MenuKeyDownArrowUp:
2408 changes = {
2409 highlightedIndex: getNextWrappingIndex(shiftKey ? -5 : -1, state.highlightedIndex, props.items.length, action.getItemNodeFromIndex, props.circularNavigation)
2410 };
2411 break;
2412
2413 case MenuMouseLeave:
2414 changes = {
2415 highlightedIndex: -1
2416 };
2417 break;
2418
2419 case ToggleButtonClick:
2420 case FunctionToggleMenu:
2421 changes = {
2422 isOpen: !state.isOpen,
2423 highlightedIndex: state.isOpen ? -1 : getHighlightedIndexOnOpen(props, state, 0)
2424 };
2425 break;
2426
2427 case FunctionOpenMenu:
2428 changes = {
2429 isOpen: true,
2430 highlightedIndex: getHighlightedIndexOnOpen(props, state, 0)
2431 };
2432 break;
2433
2434 case FunctionCloseMenu:
2435 changes = {
2436 isOpen: false
2437 };
2438 break;
2439
2440 case FunctionSetHighlightedIndex:
2441 changes = {
2442 highlightedIndex: action.highlightedIndex
2443 };
2444 break;
2445
2446 case FunctionSelectItem:
2447 changes = {
2448 selectedItem: action.selectedItem
2449 };
2450 break;
2451
2452 case FunctionSetInputValue:
2453 changes = {
2454 inputValue: action.inputValue
2455 };
2456 break;
2457
2458 case FunctionReset:
2459 changes = {
2460 highlightedIndex: getDefaultValue(props, 'highlightedIndex'),
2461 isOpen: getDefaultValue(props, 'isOpen'),
2462 selectedItem: getDefaultValue(props, 'selectedItem'),
2463 inputValue: getDefaultValue(props, 'inputValue')
2464 };
2465 break;
2466
2467 default:
2468 throw new Error('Reducer called without proper action type.');
2469 }
2470
2471 return _extends({}, state, changes);
2472}
2473/* eslint-enable complexity */
2474
2475var validatePropTypes = process.env.NODE_ENV === 'production' ?
2476/* istanbul ignore next */
2477null : getPropTypesValidator(useSelect, propTypes);
2478useSelect.stateChangeTypes = stateChangeTypes$1;
2479
2480function useSelect(userProps) {
2481 if (userProps === void 0) {
2482 userProps = {};
2483 }
2484
2485 /* istanbul ignore else */
2486 if (process.env.NODE_ENV !== 'production') {
2487 validatePropTypes(userProps);
2488 } // Props defaults and destructuring.
2489
2490
2491 var props = _extends({}, defaultProps$1, userProps);
2492
2493 var items = props.items,
2494 scrollIntoView = props.scrollIntoView,
2495 environment = props.environment,
2496 initialIsOpen = props.initialIsOpen,
2497 defaultIsOpen = props.defaultIsOpen,
2498 itemToString = props.itemToString,
2499 getA11ySelectionMessage = props.getA11ySelectionMessage,
2500 getA11yStatusMessage = props.getA11yStatusMessage; // Initial state depending on controlled props.
2501
2502 var initialState = getInitialState(props);
2503
2504 var _useControlledReducer = useControlledReducer(downshiftSelectReducer, initialState, props),
2505 state = _useControlledReducer[0],
2506 dispatch = _useControlledReducer[1];
2507
2508 var isOpen = state.isOpen,
2509 highlightedIndex = state.highlightedIndex,
2510 selectedItem = state.selectedItem,
2511 inputValue = state.inputValue; // Element efs.
2512
2513 var toggleButtonRef = useRef(null);
2514 var menuRef = useRef(null);
2515 var itemRefs = useRef();
2516 itemRefs.current = {}; // used not to trigger menu blur action in some scenarios.
2517
2518 var shouldBlurRef = useRef(true); // used to keep the inputValue clearTimeout object between renders.
2519
2520 var clearTimeoutRef = useRef(null); // prevent id re-generation between renders.
2521
2522 var elementIdsRef = useRef(getElementIds(props)); // used to keep track of how many items we had on previous cycle.
2523
2524 var previousResultCountRef = useRef();
2525 var isInitialMountRef = useRef(true); // utility callback to get item element.
2526
2527 var latest = useLatestRef({
2528 state: state,
2529 props: props
2530 }); // Some utils.
2531
2532 var getItemNodeFromIndex = function getItemNodeFromIndex(index) {
2533 return itemRefs.current[elementIdsRef.current.getItemId(index)];
2534 }; // Effects.
2535 // Sets a11y status message on changes in state.
2536
2537
2538 useA11yMessageSetter(getA11yStatusMessage, [isOpen, highlightedIndex, inputValue, items], _extends({
2539 isInitialMount: isInitialMountRef.current,
2540 previousResultCount: previousResultCountRef.current,
2541 items: items,
2542 environment: environment,
2543 itemToString: itemToString
2544 }, state)); // Sets a11y status message on changes in selectedItem.
2545
2546 useA11yMessageSetter(getA11ySelectionMessage, [selectedItem], _extends({
2547 isInitialMount: isInitialMountRef.current,
2548 previousResultCount: previousResultCountRef.current,
2549 items: items,
2550 environment: environment,
2551 itemToString: itemToString
2552 }, state)); // Scroll on highlighted item if change comes from keyboard.
2553
2554 var shouldScrollRef = useScrollIntoView({
2555 menuElement: menuRef.current,
2556 highlightedIndex: highlightedIndex,
2557 isOpen: isOpen,
2558 itemRefs: itemRefs,
2559 scrollIntoView: scrollIntoView,
2560 getItemNodeFromIndex: getItemNodeFromIndex
2561 }); // Sets cleanup for the keysSoFar after 500ms.
2562
2563 useEffect(function () {
2564 // init the clean function here as we need access to dispatch.
2565 if (isInitialMountRef.current) {
2566 clearTimeoutRef.current = debounce(function (outerDispatch) {
2567 outerDispatch({
2568 type: FunctionSetInputValue,
2569 inputValue: ''
2570 });
2571 }, 500);
2572 }
2573
2574 if (!inputValue) {
2575 return;
2576 }
2577
2578 clearTimeoutRef.current(dispatch);
2579 }, [dispatch, inputValue]);
2580 useControlPropsValidator({
2581 isInitialMount: isInitialMountRef.current,
2582 props: props,
2583 state: state
2584 });
2585 /* Controls the focus on the menu or the toggle button. */
2586
2587 useEffect(function () {
2588 // Don't focus menu on first render.
2589 if (isInitialMountRef.current) {
2590 // Unless it was initialised as open.
2591 if ((initialIsOpen || defaultIsOpen || isOpen) && menuRef.current) {
2592 menuRef.current.focus();
2593 }
2594
2595 return;
2596 } // Focus menu on open.
2597
2598
2599 if (isOpen) {
2600 // istanbul ignore else
2601 if (menuRef.current) {
2602 menuRef.current.focus();
2603 }
2604
2605 return;
2606 } // Focus toggleButton on close, but not if it was closed with (Shift+)Tab.
2607
2608
2609 if (environment.document.activeElement === menuRef.current) {
2610 // istanbul ignore else
2611 if (toggleButtonRef.current) {
2612 shouldBlurRef.current = false;
2613 toggleButtonRef.current.focus();
2614 }
2615 } // eslint-disable-next-line react-hooks/exhaustive-deps
2616
2617 }, [isOpen]);
2618 useEffect(function () {
2619 if (isInitialMountRef.current) {
2620 return;
2621 }
2622
2623 previousResultCountRef.current = items.length;
2624 }); // Add mouse/touch events to document.
2625
2626 var mouseAndTouchTrackersRef = useMouseAndTouchTracker(isOpen, [menuRef, toggleButtonRef], environment, function () {
2627 dispatch({
2628 type: MenuBlur
2629 });
2630 });
2631 var setGetterPropCallInfo = useGetterPropsCalledChecker('getMenuProps', 'getToggleButtonProps'); // Make initial ref false.
2632
2633 useEffect(function () {
2634 isInitialMountRef.current = false;
2635 }, []); // Event handler functions.
2636
2637 var toggleButtonKeyDownHandlers = useMemo(function () {
2638 return {
2639 ArrowDown: function ArrowDown(event) {
2640 event.preventDefault();
2641 dispatch({
2642 type: ToggleButtonKeyDownArrowDown,
2643 getItemNodeFromIndex: getItemNodeFromIndex,
2644 shiftKey: event.shiftKey
2645 });
2646 },
2647 ArrowUp: function ArrowUp(event) {
2648 event.preventDefault();
2649 dispatch({
2650 type: ToggleButtonKeyDownArrowUp,
2651 getItemNodeFromIndex: getItemNodeFromIndex,
2652 shiftKey: event.shiftKey
2653 });
2654 }
2655 };
2656 }, [dispatch]);
2657 var menuKeyDownHandlers = useMemo(function () {
2658 return {
2659 ArrowDown: function ArrowDown(event) {
2660 event.preventDefault();
2661 dispatch({
2662 type: MenuKeyDownArrowDown,
2663 getItemNodeFromIndex: getItemNodeFromIndex,
2664 shiftKey: event.shiftKey
2665 });
2666 },
2667 ArrowUp: function ArrowUp(event) {
2668 event.preventDefault();
2669 dispatch({
2670 type: MenuKeyDownArrowUp,
2671 getItemNodeFromIndex: getItemNodeFromIndex,
2672 shiftKey: event.shiftKey
2673 });
2674 },
2675 Home: function Home(event) {
2676 event.preventDefault();
2677 dispatch({
2678 type: MenuKeyDownHome,
2679 getItemNodeFromIndex: getItemNodeFromIndex
2680 });
2681 },
2682 End: function End(event) {
2683 event.preventDefault();
2684 dispatch({
2685 type: MenuKeyDownEnd,
2686 getItemNodeFromIndex: getItemNodeFromIndex
2687 });
2688 },
2689 Escape: function Escape() {
2690 dispatch({
2691 type: MenuKeyDownEscape
2692 });
2693 },
2694 Enter: function Enter(event) {
2695 event.preventDefault();
2696 dispatch({
2697 type: MenuKeyDownEnter
2698 });
2699 },
2700 ' ': function _(event) {
2701 event.preventDefault();
2702 dispatch({
2703 type: MenuKeyDownSpaceButton
2704 });
2705 }
2706 };
2707 }, [dispatch]); // Action functions.
2708
2709 var toggleMenu = useCallback(function () {
2710 dispatch({
2711 type: FunctionToggleMenu
2712 });
2713 }, [dispatch]);
2714 var closeMenu = useCallback(function () {
2715 dispatch({
2716 type: FunctionCloseMenu
2717 });
2718 }, [dispatch]);
2719 var openMenu = useCallback(function () {
2720 dispatch({
2721 type: FunctionOpenMenu
2722 });
2723 }, [dispatch]);
2724 var setHighlightedIndex = useCallback(function (newHighlightedIndex) {
2725 dispatch({
2726 type: FunctionSetHighlightedIndex,
2727 highlightedIndex: newHighlightedIndex
2728 });
2729 }, [dispatch]);
2730 var selectItem = useCallback(function (newSelectedItem) {
2731 dispatch({
2732 type: FunctionSelectItem,
2733 selectedItem: newSelectedItem
2734 });
2735 }, [dispatch]);
2736 var reset = useCallback(function () {
2737 dispatch({
2738 type: FunctionReset
2739 });
2740 }, [dispatch]);
2741 var setInputValue = useCallback(function (newInputValue) {
2742 dispatch({
2743 type: FunctionSetInputValue,
2744 inputValue: newInputValue
2745 });
2746 }, [dispatch]); // Getter functions.
2747
2748 var getLabelProps = useCallback(function (labelProps) {
2749 return _extends({
2750 id: elementIdsRef.current.labelId,
2751 htmlFor: elementIdsRef.current.toggleButtonId
2752 }, labelProps);
2753 }, []);
2754 var getMenuProps = useCallback(function (_temp, _temp2) {
2755 var _extends2;
2756
2757 var _ref = _temp === void 0 ? {} : _temp,
2758 onMouseLeave = _ref.onMouseLeave,
2759 _ref$refKey = _ref.refKey,
2760 refKey = _ref$refKey === void 0 ? 'ref' : _ref$refKey,
2761 onKeyDown = _ref.onKeyDown,
2762 onBlur = _ref.onBlur,
2763 ref = _ref.ref,
2764 rest = _objectWithoutPropertiesLoose(_ref, ["onMouseLeave", "refKey", "onKeyDown", "onBlur", "ref"]);
2765
2766 var _ref2 = _temp2 === void 0 ? {} : _temp2,
2767 _ref2$suppressRefErro = _ref2.suppressRefError,
2768 suppressRefError = _ref2$suppressRefErro === void 0 ? false : _ref2$suppressRefErro;
2769
2770 var latestState = latest.current.state;
2771
2772 var menuHandleKeyDown = function menuHandleKeyDown(event) {
2773 var key = normalizeArrowKey(event);
2774
2775 if (key && menuKeyDownHandlers[key]) {
2776 menuKeyDownHandlers[key](event);
2777 } else if (isAcceptedCharacterKey(key)) {
2778 dispatch({
2779 type: MenuKeyDownCharacter,
2780 key: key,
2781 getItemNodeFromIndex: getItemNodeFromIndex
2782 });
2783 }
2784 };
2785
2786 var menuHandleBlur = function menuHandleBlur() {
2787 // if the blur was a result of selection, we don't trigger this action.
2788 if (shouldBlurRef.current === false) {
2789 shouldBlurRef.current = true;
2790 return;
2791 }
2792
2793 var shouldBlur = !mouseAndTouchTrackersRef.current.isMouseDown;
2794 /* istanbul ignore else */
2795
2796 if (shouldBlur) {
2797 dispatch({
2798 type: MenuBlur
2799 });
2800 }
2801 };
2802
2803 var menuHandleMouseLeave = function menuHandleMouseLeave() {
2804 dispatch({
2805 type: MenuMouseLeave
2806 });
2807 };
2808
2809 setGetterPropCallInfo('getMenuProps', suppressRefError, refKey, menuRef);
2810 return _extends((_extends2 = {}, _extends2[refKey] = handleRefs(ref, function (menuNode) {
2811 menuRef.current = menuNode;
2812 }), _extends2.id = elementIdsRef.current.menuId, _extends2.role = 'listbox', _extends2['aria-labelledby'] = elementIdsRef.current.labelId, _extends2.tabIndex = -1, _extends2), latestState.isOpen && latestState.highlightedIndex > -1 && {
2813 'aria-activedescendant': elementIdsRef.current.getItemId(latestState.highlightedIndex)
2814 }, {
2815 onMouseLeave: callAllEventHandlers(onMouseLeave, menuHandleMouseLeave),
2816 onKeyDown: callAllEventHandlers(onKeyDown, menuHandleKeyDown),
2817 onBlur: callAllEventHandlers(onBlur, menuHandleBlur)
2818 }, rest);
2819 }, [dispatch, latest, menuKeyDownHandlers, mouseAndTouchTrackersRef, setGetterPropCallInfo]);
2820 var getToggleButtonProps = useCallback(function (_temp3, _temp4) {
2821 var _extends3;
2822
2823 var _ref3 = _temp3 === void 0 ? {} : _temp3,
2824 onClick = _ref3.onClick,
2825 onKeyDown = _ref3.onKeyDown,
2826 _ref3$refKey = _ref3.refKey,
2827 refKey = _ref3$refKey === void 0 ? 'ref' : _ref3$refKey,
2828 ref = _ref3.ref,
2829 rest = _objectWithoutPropertiesLoose(_ref3, ["onClick", "onKeyDown", "refKey", "ref"]);
2830
2831 var _ref4 = _temp4 === void 0 ? {} : _temp4,
2832 _ref4$suppressRefErro = _ref4.suppressRefError,
2833 suppressRefError = _ref4$suppressRefErro === void 0 ? false : _ref4$suppressRefErro;
2834
2835 var toggleButtonHandleClick = function toggleButtonHandleClick() {
2836 dispatch({
2837 type: ToggleButtonClick
2838 });
2839 };
2840
2841 var toggleButtonHandleKeyDown = function toggleButtonHandleKeyDown(event) {
2842 var key = normalizeArrowKey(event);
2843
2844 if (key && toggleButtonKeyDownHandlers[key]) {
2845 toggleButtonKeyDownHandlers[key](event);
2846 } else if (isAcceptedCharacterKey(key)) {
2847 dispatch({
2848 type: ToggleButtonKeyDownCharacter,
2849 key: key,
2850 getItemNodeFromIndex: getItemNodeFromIndex
2851 });
2852 }
2853 };
2854
2855 var toggleProps = _extends((_extends3 = {}, _extends3[refKey] = handleRefs(ref, function (toggleButtonNode) {
2856 toggleButtonRef.current = toggleButtonNode;
2857 }), _extends3.id = elementIdsRef.current.toggleButtonId, _extends3['aria-haspopup'] = 'listbox', _extends3['aria-expanded'] = latest.current.state.isOpen, _extends3['aria-labelledby'] = elementIdsRef.current.labelId + " " + elementIdsRef.current.toggleButtonId, _extends3), rest);
2858
2859 if (!rest.disabled) {
2860 toggleProps.onClick = callAllEventHandlers(onClick, toggleButtonHandleClick);
2861 toggleProps.onKeyDown = callAllEventHandlers(onKeyDown, toggleButtonHandleKeyDown);
2862 }
2863
2864 setGetterPropCallInfo('getToggleButtonProps', suppressRefError, refKey, toggleButtonRef);
2865 return toggleProps;
2866 }, [dispatch, latest, toggleButtonKeyDownHandlers, setGetterPropCallInfo]);
2867 var getItemProps = useCallback(function (_temp5) {
2868 var _extends4;
2869
2870 var _ref5 = _temp5 === void 0 ? {} : _temp5,
2871 item = _ref5.item,
2872 index = _ref5.index,
2873 onMouseMove = _ref5.onMouseMove,
2874 onClick = _ref5.onClick,
2875 _ref5$refKey = _ref5.refKey,
2876 refKey = _ref5$refKey === void 0 ? 'ref' : _ref5$refKey,
2877 ref = _ref5.ref,
2878 rest = _objectWithoutPropertiesLoose(_ref5, ["item", "index", "onMouseMove", "onClick", "refKey", "ref"]);
2879
2880 var _latest$current = latest.current,
2881 latestState = _latest$current.state,
2882 latestProps = _latest$current.props;
2883
2884 var itemHandleMouseMove = function itemHandleMouseMove() {
2885 if (index === latestState.highlightedIndex) {
2886 return;
2887 }
2888
2889 shouldScrollRef.current = false;
2890 dispatch({
2891 type: ItemMouseMove,
2892 index: index
2893 });
2894 };
2895
2896 var itemHandleClick = function itemHandleClick() {
2897 dispatch({
2898 type: ItemClick,
2899 index: index
2900 });
2901 };
2902
2903 var itemIndex = getItemIndex(index, item, latestProps.items);
2904
2905 if (itemIndex < 0) {
2906 throw new Error('Pass either item or item index in getItemProps!');
2907 }
2908
2909 var itemProps = _extends((_extends4 = {
2910 role: 'option',
2911 'aria-selected': "" + (itemIndex === latestState.highlightedIndex),
2912 id: elementIdsRef.current.getItemId(itemIndex)
2913 }, _extends4[refKey] = handleRefs(ref, function (itemNode) {
2914 if (itemNode) {
2915 itemRefs.current[elementIdsRef.current.getItemId(itemIndex)] = itemNode;
2916 }
2917 }), _extends4), rest);
2918
2919 if (!rest.disabled) {
2920 itemProps.onMouseMove = callAllEventHandlers(onMouseMove, itemHandleMouseMove);
2921 itemProps.onClick = callAllEventHandlers(onClick, itemHandleClick);
2922 }
2923
2924 return itemProps;
2925 }, [dispatch, latest, shouldScrollRef]);
2926 return {
2927 // prop getters.
2928 getToggleButtonProps: getToggleButtonProps,
2929 getLabelProps: getLabelProps,
2930 getMenuProps: getMenuProps,
2931 getItemProps: getItemProps,
2932 // actions.
2933 toggleMenu: toggleMenu,
2934 openMenu: openMenu,
2935 closeMenu: closeMenu,
2936 setHighlightedIndex: setHighlightedIndex,
2937 selectItem: selectItem,
2938 reset: reset,
2939 setInputValue: setInputValue,
2940 // state.
2941 highlightedIndex: highlightedIndex,
2942 isOpen: isOpen,
2943 selectedItem: selectedItem,
2944 inputValue: inputValue
2945 };
2946}
2947
2948var InputKeyDownArrowDown = process.env.NODE_ENV !== "production" ? '__input_keydown_arrow_down__' : 0;
2949var InputKeyDownArrowUp = process.env.NODE_ENV !== "production" ? '__input_keydown_arrow_up__' : 1;
2950var InputKeyDownEscape = process.env.NODE_ENV !== "production" ? '__input_keydown_escape__' : 2;
2951var InputKeyDownHome = process.env.NODE_ENV !== "production" ? '__input_keydown_home__' : 3;
2952var InputKeyDownEnd = process.env.NODE_ENV !== "production" ? '__input_keydown_end__' : 4;
2953var InputKeyDownEnter = process.env.NODE_ENV !== "production" ? '__input_keydown_enter__' : 5;
2954var InputChange = process.env.NODE_ENV !== "production" ? '__input_change__' : 6;
2955var InputBlur = process.env.NODE_ENV !== "production" ? '__input_blur__' : 7;
2956var MenuMouseLeave$1 = process.env.NODE_ENV !== "production" ? '__menu_mouse_leave__' : 8;
2957var ItemMouseMove$1 = process.env.NODE_ENV !== "production" ? '__item_mouse_move__' : 9;
2958var ItemClick$1 = process.env.NODE_ENV !== "production" ? '__item_click__' : 10;
2959var ToggleButtonClick$1 = process.env.NODE_ENV !== "production" ? '__togglebutton_click__' : 11;
2960var FunctionToggleMenu$1 = process.env.NODE_ENV !== "production" ? '__function_toggle_menu__' : 12;
2961var FunctionOpenMenu$1 = process.env.NODE_ENV !== "production" ? '__function_open_menu__' : 13;
2962var FunctionCloseMenu$1 = process.env.NODE_ENV !== "production" ? '__function_close_menu__' : 14;
2963var FunctionSetHighlightedIndex$1 = process.env.NODE_ENV !== "production" ? '__function_set_highlighted_index__' : 15;
2964var FunctionSelectItem$1 = process.env.NODE_ENV !== "production" ? '__function_select_item__' : 16;
2965var FunctionSetInputValue$1 = process.env.NODE_ENV !== "production" ? '__function_set_input_value__' : 17;
2966var FunctionReset$1 = process.env.NODE_ENV !== "production" ? '__function_reset__' : 18;
2967var ControlledPropUpdatedSelectedItem = process.env.NODE_ENV !== "production" ? '__controlled_prop_updated_selected_item__' : 19;
2968
2969var stateChangeTypes$2 = /*#__PURE__*/Object.freeze({
2970 __proto__: null,
2971 InputKeyDownArrowDown: InputKeyDownArrowDown,
2972 InputKeyDownArrowUp: InputKeyDownArrowUp,
2973 InputKeyDownEscape: InputKeyDownEscape,
2974 InputKeyDownHome: InputKeyDownHome,
2975 InputKeyDownEnd: InputKeyDownEnd,
2976 InputKeyDownEnter: InputKeyDownEnter,
2977 InputChange: InputChange,
2978 InputBlur: InputBlur,
2979 MenuMouseLeave: MenuMouseLeave$1,
2980 ItemMouseMove: ItemMouseMove$1,
2981 ItemClick: ItemClick$1,
2982 ToggleButtonClick: ToggleButtonClick$1,
2983 FunctionToggleMenu: FunctionToggleMenu$1,
2984 FunctionOpenMenu: FunctionOpenMenu$1,
2985 FunctionCloseMenu: FunctionCloseMenu$1,
2986 FunctionSetHighlightedIndex: FunctionSetHighlightedIndex$1,
2987 FunctionSelectItem: FunctionSelectItem$1,
2988 FunctionSetInputValue: FunctionSetInputValue$1,
2989 FunctionReset: FunctionReset$1,
2990 ControlledPropUpdatedSelectedItem: ControlledPropUpdatedSelectedItem
2991});
2992
2993function getElementIds$1(_ref) {
2994 var id = _ref.id,
2995 inputId = _ref.inputId,
2996 rest = _objectWithoutPropertiesLoose(_ref, ["id", "inputId"]);
2997
2998 var uniqueId = id === undefined ? "downshift-" + generateId() : id;
2999 return _extends({
3000 inputId: inputId || uniqueId + "-input"
3001 }, getElementIds(_extends({
3002 id: id
3003 }, rest)));
3004}
3005function getInitialState$1(props) {
3006 var initialState = getInitialState(props);
3007 var selectedItem = initialState.selectedItem;
3008 var inputValue = initialState.inputValue;
3009
3010 if (inputValue === '' && selectedItem && props.defaultInputValue === undefined && props.initialInputValue === undefined && props.inputValue === undefined) {
3011 inputValue = props.itemToString(selectedItem);
3012 }
3013
3014 return _extends({}, initialState, {
3015 inputValue: inputValue
3016 });
3017}
3018var propTypes$1 = {
3019 items: PropTypes.array.isRequired,
3020 itemToString: PropTypes.func,
3021 getA11yStatusMessage: PropTypes.func,
3022 getA11ySelectionMessage: PropTypes.func,
3023 circularNavigation: PropTypes.bool,
3024 highlightedIndex: PropTypes.number,
3025 defaultHighlightedIndex: PropTypes.number,
3026 initialHighlightedIndex: PropTypes.number,
3027 isOpen: PropTypes.bool,
3028 defaultIsOpen: PropTypes.bool,
3029 initialIsOpen: PropTypes.bool,
3030 selectedItem: PropTypes.any,
3031 initialSelectedItem: PropTypes.any,
3032 defaultSelectedItem: PropTypes.any,
3033 inputValue: PropTypes.string,
3034 defaultInputValue: PropTypes.string,
3035 initialInputValue: PropTypes.string,
3036 id: PropTypes.string,
3037 labelId: PropTypes.string,
3038 menuId: PropTypes.string,
3039 getItemId: PropTypes.func,
3040 inputId: PropTypes.string,
3041 toggleButtonId: PropTypes.string,
3042 stateReducer: PropTypes.func,
3043 onSelectedItemChange: PropTypes.func,
3044 onHighlightedIndexChange: PropTypes.func,
3045 onStateChange: PropTypes.func,
3046 onIsOpenChange: PropTypes.func,
3047 onInputValueChange: PropTypes.func,
3048 environment: PropTypes.shape({
3049 addEventListener: PropTypes.func,
3050 removeEventListener: PropTypes.func,
3051 document: PropTypes.shape({
3052 getElementById: PropTypes.func,
3053 activeElement: PropTypes.any,
3054 body: PropTypes.any
3055 })
3056 })
3057};
3058/**
3059 * The useCombobox version of useControlledReducer, which also
3060 * checks if the controlled prop selectedItem changed between
3061 * renders. If so, it will also update inputValue with its
3062 * string equivalent. It uses the common useEnhancedReducer to
3063 * compute the rest of the state.
3064 *
3065 * @param {Function} reducer Reducer function from downshift.
3066 * @param {Object} initialState Initial state of the hook.
3067 * @param {Object} props The hook props.
3068 * @returns {Array} An array with the state and an action dispatcher.
3069 */
3070
3071function useControlledReducer$1(reducer, initialState, props) {
3072 var previousSelectedItemRef = useRef();
3073
3074 var _useEnhancedReducer = useEnhancedReducer(reducer, initialState, props),
3075 state = _useEnhancedReducer[0],
3076 dispatch = _useEnhancedReducer[1]; // ToDo: if needed, make same approach as selectedItemChanged from Downshift.
3077
3078
3079 useEffect(function () {
3080 if (isControlledProp(props, 'selectedItem')) {
3081 if (previousSelectedItemRef.current !== props.selectedItem) {
3082 dispatch({
3083 type: ControlledPropUpdatedSelectedItem,
3084 inputValue: props.itemToString(props.selectedItem)
3085 });
3086 }
3087
3088 previousSelectedItemRef.current = state.selectedItem === previousSelectedItemRef.current ? props.selectedItem : state.selectedItem;
3089 }
3090 });
3091 return [getState(state, props), dispatch];
3092}
3093var defaultProps$2 = _extends({}, defaultProps, {
3094 getA11yStatusMessage: getA11yStatusMessage,
3095 circularNavigation: true
3096});
3097
3098/* eslint-disable complexity */
3099
3100function downshiftUseComboboxReducer(state, action) {
3101 var type = action.type,
3102 props = action.props,
3103 shiftKey = action.shiftKey;
3104 var changes;
3105
3106 switch (type) {
3107 case ItemMouseMove$1:
3108 changes = {
3109 highlightedIndex: action.index
3110 };
3111 break;
3112
3113 case ItemClick$1:
3114 changes = {
3115 isOpen: getDefaultValue(props, 'isOpen'),
3116 highlightedIndex: getDefaultValue(props, 'highlightedIndex'),
3117 selectedItem: props.items[action.index],
3118 inputValue: props.itemToString(props.items[action.index])
3119 };
3120 break;
3121
3122 case InputKeyDownArrowDown:
3123 if (state.isOpen) {
3124 changes = {
3125 highlightedIndex: getNextWrappingIndex(shiftKey ? 5 : 1, state.highlightedIndex, props.items.length, action.getItemNodeFromIndex, props.circularNavigation)
3126 };
3127 } else {
3128 changes = {
3129 highlightedIndex: getHighlightedIndexOnOpen(props, state, 1, action.getItemNodeFromIndex),
3130 isOpen: true
3131 };
3132 }
3133
3134 break;
3135
3136 case InputKeyDownArrowUp:
3137 if (state.isOpen) {
3138 changes = {
3139 highlightedIndex: getNextWrappingIndex(shiftKey ? -5 : -1, state.highlightedIndex, props.items.length, action.getItemNodeFromIndex, props.circularNavigation)
3140 };
3141 } else {
3142 changes = {
3143 highlightedIndex: getHighlightedIndexOnOpen(props, state, -1, action.getItemNodeFromIndex),
3144 isOpen: true
3145 };
3146 }
3147
3148 break;
3149
3150 case InputKeyDownEnter:
3151 changes = _extends({}, state.isOpen && state.highlightedIndex >= 0 && {
3152 selectedItem: props.items[state.highlightedIndex],
3153 isOpen: getDefaultValue(props, 'isOpen'),
3154 highlightedIndex: getDefaultValue(props, 'highlightedIndex'),
3155 inputValue: props.itemToString(props.items[state.highlightedIndex])
3156 });
3157 break;
3158
3159 case InputKeyDownEscape:
3160 changes = _extends({
3161 isOpen: false,
3162 highlightedIndex: -1
3163 }, !state.isOpen && {
3164 selectedItem: null,
3165 inputValue: ''
3166 });
3167 break;
3168
3169 case InputKeyDownHome:
3170 changes = _extends({}, state.isOpen && {
3171 highlightedIndex: getNextNonDisabledIndex(1, 0, props.items.length, action.getItemNodeFromIndex, false)
3172 });
3173 break;
3174
3175 case InputKeyDownEnd:
3176 changes = _extends({}, state.isOpen && {
3177 highlightedIndex: getNextNonDisabledIndex(-1, props.items.length - 1, props.items.length, action.getItemNodeFromIndex, false)
3178 });
3179 break;
3180
3181 case InputBlur:
3182 if (state.isOpen) {
3183 changes = _extends({
3184 isOpen: false,
3185 highlightedIndex: -1
3186 }, state.highlightedIndex >= 0 && action.selectItem && {
3187 selectedItem: props.items[state.highlightedIndex],
3188 inputValue: props.itemToString(props.items[state.highlightedIndex])
3189 });
3190 }
3191
3192 break;
3193
3194 case InputChange:
3195 changes = {
3196 isOpen: true,
3197 highlightedIndex: getDefaultValue(props, 'highlightedIndex'),
3198 inputValue: action.inputValue
3199 };
3200 break;
3201
3202 case MenuMouseLeave$1:
3203 changes = {
3204 highlightedIndex: -1
3205 };
3206 break;
3207
3208 case ToggleButtonClick$1:
3209 case FunctionToggleMenu$1:
3210 changes = {
3211 isOpen: !state.isOpen,
3212 highlightedIndex: state.isOpen ? -1 : getHighlightedIndexOnOpen(props, state, 0)
3213 };
3214 break;
3215
3216 case FunctionOpenMenu$1:
3217 changes = {
3218 isOpen: true,
3219 highlightedIndex: getHighlightedIndexOnOpen(props, state, 0)
3220 };
3221 break;
3222
3223 case FunctionCloseMenu$1:
3224 changes = {
3225 isOpen: false
3226 };
3227 break;
3228
3229 case FunctionSetHighlightedIndex$1:
3230 changes = {
3231 highlightedIndex: action.highlightedIndex
3232 };
3233 break;
3234
3235 case FunctionSelectItem$1:
3236 changes = {
3237 selectedItem: action.selectedItem,
3238 inputValue: props.itemToString(action.selectedItem)
3239 };
3240 break;
3241
3242 case ControlledPropUpdatedSelectedItem:
3243 case FunctionSetInputValue$1:
3244 changes = {
3245 inputValue: action.inputValue
3246 };
3247 break;
3248
3249 case FunctionReset$1:
3250 changes = {
3251 highlightedIndex: getDefaultValue(props, 'highlightedIndex'),
3252 isOpen: getDefaultValue(props, 'isOpen'),
3253 selectedItem: getDefaultValue(props, 'selectedItem'),
3254 inputValue: getDefaultValue(props, 'inputValue')
3255 };
3256 break;
3257
3258 default:
3259 throw new Error('Reducer called without proper action type.');
3260 }
3261
3262 return _extends({}, state, changes);
3263}
3264/* eslint-enable complexity */
3265
3266var validatePropTypes$1 = process.env.NODE_ENV === 'production' ?
3267/* istanbul ignore next */
3268null : getPropTypesValidator(useCombobox, propTypes$1);
3269useCombobox.stateChangeTypes = stateChangeTypes$2;
3270
3271function useCombobox(userProps) {
3272 if (userProps === void 0) {
3273 userProps = {};
3274 }
3275
3276 /* istanbul ignore else */
3277 if (process.env.NODE_ENV !== 'production') {
3278 validatePropTypes$1(userProps);
3279 } // Props defaults and destructuring.
3280
3281
3282 var props = _extends({}, defaultProps$2, userProps);
3283
3284 var initialIsOpen = props.initialIsOpen,
3285 defaultIsOpen = props.defaultIsOpen,
3286 items = props.items,
3287 scrollIntoView = props.scrollIntoView,
3288 environment = props.environment,
3289 getA11yStatusMessage = props.getA11yStatusMessage,
3290 getA11ySelectionMessage = props.getA11ySelectionMessage,
3291 itemToString = props.itemToString; // Initial state depending on controlled props.
3292
3293 var initialState = getInitialState$1(props);
3294
3295 var _useControlledReducer = useControlledReducer$1(downshiftUseComboboxReducer, initialState, props),
3296 state = _useControlledReducer[0],
3297 dispatch = _useControlledReducer[1];
3298
3299 var isOpen = state.isOpen,
3300 highlightedIndex = state.highlightedIndex,
3301 selectedItem = state.selectedItem,
3302 inputValue = state.inputValue; // Element refs.
3303
3304 var menuRef = useRef(null);
3305 var itemRefs = useRef();
3306 var inputRef = useRef(null);
3307 var toggleButtonRef = useRef(null);
3308 var comboboxRef = useRef(null);
3309 itemRefs.current = {};
3310 var isInitialMountRef = useRef(true); // prevent id re-generation between renders.
3311
3312 var elementIdsRef = useRef(getElementIds$1(props)); // used to keep track of how many items we had on previous cycle.
3313
3314 var previousResultCountRef = useRef(); // utility callback to get item element.
3315
3316 var latest = useLatestRef({
3317 state: state,
3318 props: props
3319 });
3320
3321 var getItemNodeFromIndex = function getItemNodeFromIndex(index) {
3322 return itemRefs.current[elementIdsRef.current.getItemId(index)];
3323 }; // Effects.
3324 // Sets a11y status message on changes in state.
3325
3326
3327 useA11yMessageSetter(getA11yStatusMessage, [isOpen, highlightedIndex, inputValue, items], _extends({
3328 isInitialMount: isInitialMountRef.current,
3329 previousResultCount: previousResultCountRef.current,
3330 items: items,
3331 environment: environment,
3332 itemToString: itemToString
3333 }, state)); // Sets a11y status message on changes in selectedItem.
3334
3335 useA11yMessageSetter(getA11ySelectionMessage, [selectedItem], _extends({
3336 isInitialMount: isInitialMountRef.current,
3337 previousResultCount: previousResultCountRef.current,
3338 items: items,
3339 environment: environment,
3340 itemToString: itemToString
3341 }, state)); // Scroll on highlighted item if change comes from keyboard.
3342
3343 var shouldScrollRef = useScrollIntoView({
3344 menuElement: menuRef.current,
3345 highlightedIndex: highlightedIndex,
3346 isOpen: isOpen,
3347 itemRefs: itemRefs,
3348 scrollIntoView: scrollIntoView,
3349 getItemNodeFromIndex: getItemNodeFromIndex
3350 });
3351 useControlPropsValidator({
3352 isInitialMount: isInitialMountRef.current,
3353 props: props,
3354 state: state
3355 }); // Controls the focus on the input on open.
3356
3357 useEffect(function () {
3358 // Don't focus menu on first render.
3359 if (isInitialMountRef.current) {
3360 // Unless it was initialised as open.
3361 if (initialIsOpen || defaultIsOpen || isOpen) {
3362 if (inputRef.current) {
3363 inputRef.current.focus();
3364 }
3365 }
3366 } // eslint-disable-next-line react-hooks/exhaustive-deps
3367
3368 }, [isOpen]);
3369 useEffect(function () {
3370 if (isInitialMountRef.current) {
3371 return;
3372 }
3373
3374 previousResultCountRef.current = items.length;
3375 }); // Add mouse/touch events to document.
3376
3377 var mouseAndTouchTrackersRef = useMouseAndTouchTracker(isOpen, [comboboxRef, menuRef, toggleButtonRef], environment, function () {
3378 dispatch({
3379 type: InputBlur,
3380 selectItem: false
3381 });
3382 });
3383 var setGetterPropCallInfo = useGetterPropsCalledChecker('getInputProps', 'getComboboxProps', 'getMenuProps'); // Make initial ref false.
3384
3385 useEffect(function () {
3386 isInitialMountRef.current = false;
3387 }, []);
3388 /* Event handler functions */
3389
3390 var inputKeyDownHandlers = useMemo(function () {
3391 return {
3392 ArrowDown: function ArrowDown(event) {
3393 event.preventDefault();
3394 dispatch({
3395 type: InputKeyDownArrowDown,
3396 shiftKey: event.shiftKey,
3397 getItemNodeFromIndex: getItemNodeFromIndex
3398 });
3399 },
3400 ArrowUp: function ArrowUp(event) {
3401 event.preventDefault();
3402 dispatch({
3403 type: InputKeyDownArrowUp,
3404 shiftKey: event.shiftKey,
3405 getItemNodeFromIndex: getItemNodeFromIndex
3406 });
3407 },
3408 Home: function Home(event) {
3409 event.preventDefault();
3410 dispatch({
3411 type: InputKeyDownHome,
3412 getItemNodeFromIndex: getItemNodeFromIndex
3413 });
3414 },
3415 End: function End(event) {
3416 event.preventDefault();
3417 dispatch({
3418 type: InputKeyDownEnd,
3419 getItemNodeFromIndex: getItemNodeFromIndex
3420 });
3421 },
3422 Escape: function Escape() {
3423 dispatch({
3424 type: InputKeyDownEscape
3425 });
3426 },
3427 Enter: function Enter(event) {
3428 // if IME composing, wait for next Enter keydown event.
3429 if (event.which === 229) {
3430 return;
3431 }
3432
3433 var latestState = latest.current.state;
3434
3435 if (latestState.isOpen) {
3436 event.preventDefault();
3437 }
3438
3439 dispatch({
3440 type: InputKeyDownEnter,
3441 getItemNodeFromIndex: getItemNodeFromIndex
3442 });
3443 }
3444 };
3445 }, [dispatch, latest]); // Getter props.
3446
3447 var getLabelProps = useCallback(function (labelProps) {
3448 return _extends({
3449 id: elementIdsRef.current.labelId,
3450 htmlFor: elementIdsRef.current.inputId
3451 }, labelProps);
3452 }, []);
3453 var getMenuProps = useCallback(function (_temp, _temp2) {
3454 var _extends2;
3455
3456 var _ref = _temp === void 0 ? {} : _temp,
3457 onMouseLeave = _ref.onMouseLeave,
3458 _ref$refKey = _ref.refKey,
3459 refKey = _ref$refKey === void 0 ? 'ref' : _ref$refKey,
3460 ref = _ref.ref,
3461 rest = _objectWithoutPropertiesLoose(_ref, ["onMouseLeave", "refKey", "ref"]);
3462
3463 var _ref2 = _temp2 === void 0 ? {} : _temp2,
3464 _ref2$suppressRefErro = _ref2.suppressRefError,
3465 suppressRefError = _ref2$suppressRefErro === void 0 ? false : _ref2$suppressRefErro;
3466
3467 setGetterPropCallInfo('getMenuProps', suppressRefError, refKey, menuRef);
3468 return _extends((_extends2 = {}, _extends2[refKey] = handleRefs(ref, function (menuNode) {
3469 menuRef.current = menuNode;
3470 }), _extends2.id = elementIdsRef.current.menuId, _extends2.role = 'listbox', _extends2['aria-labelledby'] = elementIdsRef.current.labelId, _extends2.onMouseLeave = callAllEventHandlers(onMouseLeave, function () {
3471 dispatch({
3472 type: MenuMouseLeave$1
3473 });
3474 }), _extends2), rest);
3475 }, [dispatch, setGetterPropCallInfo]);
3476 var getItemProps = useCallback(function (_temp3) {
3477 var _extends3, _ref4;
3478
3479 var _ref3 = _temp3 === void 0 ? {} : _temp3,
3480 item = _ref3.item,
3481 index = _ref3.index,
3482 _ref3$refKey = _ref3.refKey,
3483 refKey = _ref3$refKey === void 0 ? 'ref' : _ref3$refKey,
3484 ref = _ref3.ref,
3485 onMouseMove = _ref3.onMouseMove,
3486 onClick = _ref3.onClick,
3487 onPress = _ref3.onPress,
3488 rest = _objectWithoutPropertiesLoose(_ref3, ["item", "index", "refKey", "ref", "onMouseMove", "onClick", "onPress"]);
3489
3490 var _latest$current = latest.current,
3491 latestProps = _latest$current.props,
3492 latestState = _latest$current.state;
3493 var itemIndex = getItemIndex(index, item, latestProps.items);
3494
3495 if (itemIndex < 0) {
3496 throw new Error('Pass either item or item index in getItemProps!');
3497 }
3498
3499 var onSelectKey = 'onClick';
3500 var customClickHandler = onClick;
3501
3502 var itemHandleMouseMove = function itemHandleMouseMove() {
3503 if (index === latestState.highlightedIndex) {
3504 return;
3505 }
3506
3507 shouldScrollRef.current = false;
3508 dispatch({
3509 type: ItemMouseMove$1,
3510 index: index
3511 });
3512 };
3513
3514 var itemHandleClick = function itemHandleClick() {
3515 dispatch({
3516 type: ItemClick$1,
3517 index: index
3518 });
3519
3520 if (inputRef.current) {
3521 inputRef.current.focus();
3522 }
3523 };
3524
3525 return _extends((_extends3 = {}, _extends3[refKey] = handleRefs(ref, function (itemNode) {
3526 if (itemNode) {
3527 itemRefs.current[elementIdsRef.current.getItemId(itemIndex)] = itemNode;
3528 }
3529 }), _extends3.role = 'option', _extends3['aria-selected'] = "" + (itemIndex === latestState.highlightedIndex), _extends3.id = elementIdsRef.current.getItemId(itemIndex), _extends3), !rest.disabled && (_ref4 = {
3530 onMouseMove: callAllEventHandlers(onMouseMove, itemHandleMouseMove)
3531 }, _ref4[onSelectKey] = callAllEventHandlers(customClickHandler, itemHandleClick), _ref4), rest);
3532 }, [dispatch, latest, shouldScrollRef]);
3533 var getToggleButtonProps = useCallback(function (_temp4) {
3534 var _extends4;
3535
3536 var _ref5 = _temp4 === void 0 ? {} : _temp4,
3537 onClick = _ref5.onClick,
3538 onPress = _ref5.onPress,
3539 _ref5$refKey = _ref5.refKey,
3540 refKey = _ref5$refKey === void 0 ? 'ref' : _ref5$refKey,
3541 ref = _ref5.ref,
3542 rest = _objectWithoutPropertiesLoose(_ref5, ["onClick", "onPress", "refKey", "ref"]);
3543
3544 var toggleButtonHandleClick = function toggleButtonHandleClick() {
3545 dispatch({
3546 type: ToggleButtonClick$1
3547 });
3548
3549 if (!latest.current.state.isOpen && inputRef.current) {
3550 inputRef.current.focus();
3551 }
3552 };
3553
3554 return _extends((_extends4 = {}, _extends4[refKey] = handleRefs(ref, function (toggleButtonNode) {
3555 toggleButtonRef.current = toggleButtonNode;
3556 }), _extends4.id = elementIdsRef.current.toggleButtonId, _extends4.tabIndex = -1, _extends4), !rest.disabled && _extends({}, {
3557 onClick: callAllEventHandlers(onClick, toggleButtonHandleClick)
3558 }), rest);
3559 }, [dispatch, latest]);
3560 var getInputProps = useCallback(function (_temp5, _temp6) {
3561 var _extends5;
3562
3563 var _ref6 = _temp5 === void 0 ? {} : _temp5,
3564 onKeyDown = _ref6.onKeyDown,
3565 onChange = _ref6.onChange,
3566 onInput = _ref6.onInput,
3567 onBlur = _ref6.onBlur,
3568 onChangeText = _ref6.onChangeText,
3569 _ref6$refKey = _ref6.refKey,
3570 refKey = _ref6$refKey === void 0 ? 'ref' : _ref6$refKey,
3571 ref = _ref6.ref,
3572 rest = _objectWithoutPropertiesLoose(_ref6, ["onKeyDown", "onChange", "onInput", "onBlur", "onChangeText", "refKey", "ref"]);
3573
3574 var _ref7 = _temp6 === void 0 ? {} : _temp6,
3575 _ref7$suppressRefErro = _ref7.suppressRefError,
3576 suppressRefError = _ref7$suppressRefErro === void 0 ? false : _ref7$suppressRefErro;
3577
3578 setGetterPropCallInfo('getInputProps', suppressRefError, refKey, inputRef);
3579 var latestState = latest.current.state;
3580
3581 var inputHandleKeyDown = function inputHandleKeyDown(event) {
3582 var key = normalizeArrowKey(event);
3583
3584 if (key && inputKeyDownHandlers[key]) {
3585 inputKeyDownHandlers[key](event);
3586 }
3587 };
3588
3589 var inputHandleChange = function inputHandleChange(event) {
3590 dispatch({
3591 type: InputChange,
3592 inputValue: event.target.value
3593 });
3594 };
3595
3596 var inputHandleBlur = function inputHandleBlur() {
3597 /* istanbul ignore else */
3598 if (!mouseAndTouchTrackersRef.current.isMouseDown) {
3599 dispatch({
3600 type: InputBlur,
3601 selectItem: true
3602 });
3603 }
3604 };
3605 /* istanbul ignore next (preact) */
3606
3607
3608 var onChangeKey = 'onChange';
3609 var eventHandlers = {};
3610
3611 if (!rest.disabled) {
3612 var _eventHandlers;
3613
3614 eventHandlers = (_eventHandlers = {}, _eventHandlers[onChangeKey] = callAllEventHandlers(onChange, onInput, inputHandleChange), _eventHandlers.onKeyDown = callAllEventHandlers(onKeyDown, inputHandleKeyDown), _eventHandlers.onBlur = callAllEventHandlers(onBlur, inputHandleBlur), _eventHandlers);
3615 }
3616
3617 return _extends((_extends5 = {}, _extends5[refKey] = handleRefs(ref, function (inputNode) {
3618 inputRef.current = inputNode;
3619 }), _extends5.id = elementIdsRef.current.inputId, _extends5['aria-autocomplete'] = 'list', _extends5['aria-controls'] = elementIdsRef.current.menuId, _extends5), latestState.isOpen && latestState.highlightedIndex > -1 && {
3620 'aria-activedescendant': elementIdsRef.current.getItemId(latestState.highlightedIndex)
3621 }, {
3622 'aria-labelledby': elementIdsRef.current.labelId,
3623 // https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion
3624 // revert back since autocomplete="nope" is ignored on latest Chrome and Opera
3625 autoComplete: 'off',
3626 value: latestState.inputValue
3627 }, eventHandlers, rest);
3628 }, [dispatch, inputKeyDownHandlers, latest, mouseAndTouchTrackersRef, setGetterPropCallInfo]);
3629 var getComboboxProps = useCallback(function (_temp7, _temp8) {
3630 var _extends6;
3631
3632 var _ref8 = _temp7 === void 0 ? {} : _temp7,
3633 _ref8$refKey = _ref8.refKey,
3634 refKey = _ref8$refKey === void 0 ? 'ref' : _ref8$refKey,
3635 ref = _ref8.ref,
3636 rest = _objectWithoutPropertiesLoose(_ref8, ["refKey", "ref"]);
3637
3638 var _ref9 = _temp8 === void 0 ? {} : _temp8,
3639 _ref9$suppressRefErro = _ref9.suppressRefError,
3640 suppressRefError = _ref9$suppressRefErro === void 0 ? false : _ref9$suppressRefErro;
3641
3642 setGetterPropCallInfo('getComboboxProps', suppressRefError, refKey, comboboxRef);
3643 return _extends((_extends6 = {}, _extends6[refKey] = handleRefs(ref, function (comboboxNode) {
3644 comboboxRef.current = comboboxNode;
3645 }), _extends6.role = 'combobox', _extends6['aria-haspopup'] = 'listbox', _extends6['aria-owns'] = elementIdsRef.current.menuId, _extends6['aria-expanded'] = latest.current.state.isOpen, _extends6), rest);
3646 }, [latest, setGetterPropCallInfo]); // returns
3647
3648 var toggleMenu = useCallback(function () {
3649 dispatch({
3650 type: FunctionToggleMenu$1
3651 });
3652 }, [dispatch]);
3653 var closeMenu = useCallback(function () {
3654 dispatch({
3655 type: FunctionCloseMenu$1
3656 });
3657 }, [dispatch]);
3658 var openMenu = useCallback(function () {
3659 dispatch({
3660 type: FunctionOpenMenu$1
3661 });
3662 }, [dispatch]);
3663 var setHighlightedIndex = useCallback(function (newHighlightedIndex) {
3664 dispatch({
3665 type: FunctionSetHighlightedIndex$1,
3666 highlightedIndex: newHighlightedIndex
3667 });
3668 }, [dispatch]);
3669 var selectItem = useCallback(function (newSelectedItem) {
3670 dispatch({
3671 type: FunctionSelectItem$1,
3672 selectedItem: newSelectedItem
3673 });
3674 }, [dispatch]);
3675 var setInputValue = useCallback(function (newInputValue) {
3676 dispatch({
3677 type: FunctionSetInputValue$1,
3678 inputValue: newInputValue
3679 });
3680 }, [dispatch]);
3681 var reset = useCallback(function () {
3682 dispatch({
3683 type: FunctionReset$1
3684 });
3685 }, [dispatch]);
3686 return {
3687 // prop getters.
3688 getItemProps: getItemProps,
3689 getLabelProps: getLabelProps,
3690 getMenuProps: getMenuProps,
3691 getInputProps: getInputProps,
3692 getComboboxProps: getComboboxProps,
3693 getToggleButtonProps: getToggleButtonProps,
3694 // actions.
3695 toggleMenu: toggleMenu,
3696 openMenu: openMenu,
3697 closeMenu: closeMenu,
3698 setHighlightedIndex: setHighlightedIndex,
3699 setInputValue: setInputValue,
3700 selectItem: selectItem,
3701 reset: reset,
3702 // state.
3703 highlightedIndex: highlightedIndex,
3704 isOpen: isOpen,
3705 selectedItem: selectedItem,
3706 inputValue: inputValue
3707 };
3708}
3709
3710var defaultStateValues = {
3711 activeIndex: -1,
3712 selectedItems: []
3713};
3714/**
3715 * Returns the initial value for a state key in the following order:
3716 * 1. controlled prop, 2. initial prop, 3. default prop, 4. default
3717 * value from Downshift.
3718 *
3719 * @param {Object} props Props passed to the hook.
3720 * @param {string} propKey Props key to generate the value for.
3721 * @returns {any} The initial value for that prop.
3722 */
3723
3724function getInitialValue$1(props, propKey) {
3725 return getInitialValue(props, propKey, defaultStateValues);
3726}
3727/**
3728 * Returns the default value for a state key in the following order:
3729 * 1. controlled prop, 2. default prop, 3. default value from Downshift.
3730 *
3731 * @param {Object} props Props passed to the hook.
3732 * @param {string} propKey Props key to generate the value for.
3733 * @returns {any} The initial value for that prop.
3734 */
3735
3736
3737function getDefaultValue$1(props, propKey) {
3738 return getDefaultValue(props, propKey, defaultStateValues);
3739}
3740/**
3741 * Gets the initial state based on the provided props. It uses initial, default
3742 * and controlled props related to state in order to compute the initial value.
3743 *
3744 * @param {Object} props Props passed to the hook.
3745 * @returns {Object} The initial state.
3746 */
3747
3748function getInitialState$2(props) {
3749 var activeIndex = getInitialValue$1(props, 'activeIndex');
3750 var selectedItems = getInitialValue$1(props, 'selectedItems');
3751 return {
3752 activeIndex: activeIndex,
3753 selectedItems: selectedItems
3754 };
3755}
3756/**
3757 * Returns true if dropdown keydown operation is permitted. Should not be
3758 * allowed on keydown with modifier keys (ctrl, alt, shift, meta), on
3759 * input element with text content that is either highlighted or selection
3760 * cursor is not at the starting position.
3761 *
3762 * @param {KeyboardEvent} event The event from keydown.
3763 * @returns {boolean} Whether the operation is allowed.
3764 */
3765
3766function isKeyDownOperationPermitted(event) {
3767 if (event.shiftKey || event.metaKey || event.ctrlKey || event.altKey) {
3768 return false;
3769 }
3770
3771 var element = event.target;
3772
3773 if (element instanceof HTMLInputElement && // if element is a text input
3774 element.value !== '' && ( // and we have text in it
3775 // and cursor is either not at the start or is currently highlighting text.
3776 element.selectionStart !== 0 || element.selectionEnd !== 0)) {
3777 return false;
3778 }
3779
3780 return true;
3781}
3782/**
3783 * Returns a message to be added to aria-live region when item is removed.
3784 *
3785 * @param {Object} selectionParameters Parameters required to build the message.
3786 * @returns {string} The a11y message.
3787 */
3788
3789function getA11yRemovalMessage(selectionParameters) {
3790 var removedSelectedItem = selectionParameters.removedSelectedItem,
3791 itemToStringLocal = selectionParameters.itemToString;
3792 return itemToStringLocal(removedSelectedItem) + " has been removed.";
3793}
3794
3795var propTypes$2 = {
3796 selectedItems: PropTypes.array,
3797 initialSelectedItems: PropTypes.array,
3798 defaultSelectedItems: PropTypes.array,
3799 itemToString: PropTypes.func,
3800 getA11yRemovalMessage: PropTypes.func,
3801 stateReducer: PropTypes.func,
3802 activeIndex: PropTypes.number,
3803 initialActiveIndex: PropTypes.number,
3804 defaultActiveIndex: PropTypes.number,
3805 onActiveIndexChange: PropTypes.func,
3806 onSelectedItemsChange: PropTypes.func,
3807 keyNavigationNext: PropTypes.string,
3808 keyNavigationPrevious: PropTypes.string,
3809 environment: PropTypes.shape({
3810 addEventListener: PropTypes.func,
3811 removeEventListener: PropTypes.func,
3812 document: PropTypes.shape({
3813 getElementById: PropTypes.func,
3814 activeElement: PropTypes.any,
3815 body: PropTypes.any
3816 })
3817 })
3818};
3819var defaultProps$3 = {
3820 itemToString: defaultProps.itemToString,
3821 stateReducer: defaultProps.stateReducer,
3822 environment: defaultProps.environment,
3823 getA11yRemovalMessage: getA11yRemovalMessage,
3824 keyNavigationNext: 'ArrowRight',
3825 keyNavigationPrevious: 'ArrowLeft'
3826};
3827
3828var SelectedItemClick = process.env.NODE_ENV !== "production" ? '__selected_item_click__' : 0;
3829var SelectedItemKeyDownDelete = process.env.NODE_ENV !== "production" ? '__selected_item_keydown_delete__' : 1;
3830var SelectedItemKeyDownBackspace = process.env.NODE_ENV !== "production" ? '__selected_item_keydown_backspace__' : 2;
3831var SelectedItemKeyDownNavigationNext = process.env.NODE_ENV !== "production" ? '__selected_item_keydown_navigation_next__' : 3;
3832var SelectedItemKeyDownNavigationPrevious = process.env.NODE_ENV !== "production" ? '__selected_item_keydown_navigation_previous__' : 4;
3833var DropdownKeyDownNavigationPrevious = process.env.NODE_ENV !== "production" ? '__dropdown_keydown_navigation_previous__' : 5;
3834var DropdownKeyDownBackspace = process.env.NODE_ENV !== "production" ? '__dropdown_keydown_backspace__' : 6;
3835var DropdownClick = process.env.NODE_ENV !== "production" ? '__dropdown_click__' : 7;
3836var FunctionAddSelectedItem = process.env.NODE_ENV !== "production" ? '__function_add_selected_item__' : 8;
3837var FunctionRemoveSelectedItem = process.env.NODE_ENV !== "production" ? '__function_remove_selected_item__' : 9;
3838var FunctionSetSelectedItems = process.env.NODE_ENV !== "production" ? '__function_set_selected_items__' : 10;
3839var FunctionSetActiveIndex = process.env.NODE_ENV !== "production" ? '__function_set_active_index__' : 11;
3840var FunctionReset$2 = process.env.NODE_ENV !== "production" ? '__function_reset__' : 12;
3841
3842var stateChangeTypes$3 = /*#__PURE__*/Object.freeze({
3843 __proto__: null,
3844 SelectedItemClick: SelectedItemClick,
3845 SelectedItemKeyDownDelete: SelectedItemKeyDownDelete,
3846 SelectedItemKeyDownBackspace: SelectedItemKeyDownBackspace,
3847 SelectedItemKeyDownNavigationNext: SelectedItemKeyDownNavigationNext,
3848 SelectedItemKeyDownNavigationPrevious: SelectedItemKeyDownNavigationPrevious,
3849 DropdownKeyDownNavigationPrevious: DropdownKeyDownNavigationPrevious,
3850 DropdownKeyDownBackspace: DropdownKeyDownBackspace,
3851 DropdownClick: DropdownClick,
3852 FunctionAddSelectedItem: FunctionAddSelectedItem,
3853 FunctionRemoveSelectedItem: FunctionRemoveSelectedItem,
3854 FunctionSetSelectedItems: FunctionSetSelectedItems,
3855 FunctionSetActiveIndex: FunctionSetActiveIndex,
3856 FunctionReset: FunctionReset$2
3857});
3858
3859/* eslint-disable complexity */
3860
3861function downshiftMultipleSelectionReducer(state, action) {
3862 var type = action.type,
3863 index = action.index,
3864 props = action.props,
3865 selectedItem = action.selectedItem;
3866 var activeIndex = state.activeIndex,
3867 selectedItems = state.selectedItems;
3868 var changes;
3869
3870 switch (type) {
3871 case SelectedItemClick:
3872 changes = {
3873 activeIndex: index
3874 };
3875 break;
3876
3877 case SelectedItemKeyDownNavigationPrevious:
3878 changes = {
3879 activeIndex: activeIndex - 1 < 0 ? 0 : activeIndex - 1
3880 };
3881 break;
3882
3883 case SelectedItemKeyDownNavigationNext:
3884 changes = {
3885 activeIndex: activeIndex + 1 >= selectedItems.length ? -1 : activeIndex + 1
3886 };
3887 break;
3888
3889 case SelectedItemKeyDownBackspace:
3890 case SelectedItemKeyDownDelete:
3891 {
3892 var newActiveIndex = activeIndex;
3893
3894 if (selectedItems.length === 1) {
3895 newActiveIndex = -1;
3896 } else if (activeIndex === selectedItems.length - 1) {
3897 newActiveIndex = selectedItems.length - 2;
3898 }
3899
3900 changes = _extends({
3901 selectedItems: [].concat(selectedItems.slice(0, activeIndex), selectedItems.slice(activeIndex + 1))
3902 }, {
3903 activeIndex: newActiveIndex
3904 });
3905 break;
3906 }
3907
3908 case DropdownKeyDownNavigationPrevious:
3909 changes = {
3910 activeIndex: selectedItems.length - 1
3911 };
3912 break;
3913
3914 case DropdownKeyDownBackspace:
3915 changes = {
3916 selectedItems: selectedItems.slice(0, selectedItems.length - 1)
3917 };
3918 break;
3919
3920 case FunctionAddSelectedItem:
3921 changes = {
3922 selectedItems: [].concat(selectedItems, [selectedItem])
3923 };
3924 break;
3925
3926 case DropdownClick:
3927 changes = {
3928 activeIndex: -1
3929 };
3930 break;
3931
3932 case FunctionRemoveSelectedItem:
3933 {
3934 var _newActiveIndex = activeIndex;
3935 var selectedItemIndex = selectedItems.indexOf(selectedItem);
3936
3937 if (selectedItems.length === 1) {
3938 _newActiveIndex = -1;
3939 } else if (selectedItemIndex === selectedItems.length - 1) {
3940 _newActiveIndex = selectedItems.length - 2;
3941 }
3942
3943 changes = _extends({
3944 selectedItems: [].concat(selectedItems.slice(0, selectedItemIndex), selectedItems.slice(selectedItemIndex + 1))
3945 }, {
3946 activeIndex: _newActiveIndex
3947 });
3948 break;
3949 }
3950
3951 case FunctionSetSelectedItems:
3952 {
3953 var newSelectedItems = action.selectedItems;
3954 changes = {
3955 selectedItems: newSelectedItems
3956 };
3957 break;
3958 }
3959
3960 case FunctionSetActiveIndex:
3961 {
3962 var _newActiveIndex2 = action.activeIndex;
3963 changes = {
3964 activeIndex: _newActiveIndex2
3965 };
3966 break;
3967 }
3968
3969 case FunctionReset$2:
3970 changes = {
3971 activeIndex: getDefaultValue$1(props, 'activeIndex'),
3972 selectedItems: getDefaultValue$1(props, 'selectedItems')
3973 };
3974 break;
3975
3976 default:
3977 throw new Error('Reducer called without proper action type.');
3978 }
3979
3980 return _extends({}, state, changes);
3981}
3982
3983useMultipleSelection.stateChangeTypes = stateChangeTypes$3;
3984
3985function useMultipleSelection(userProps) {
3986 if (userProps === void 0) {
3987 userProps = {};
3988 }
3989
3990 // Props defaults and destructuring.
3991 var props = _extends({}, defaultProps$3, userProps);
3992
3993 var getA11yRemovalMessage = props.getA11yRemovalMessage,
3994 itemToString = props.itemToString,
3995 environment = props.environment,
3996 keyNavigationNext = props.keyNavigationNext,
3997 keyNavigationPrevious = props.keyNavigationPrevious; // Reducer init.
3998
3999 var _useControlledReducer = useControlledReducer(downshiftMultipleSelectionReducer, getInitialState$2(props), props),
4000 state = _useControlledReducer[0],
4001 dispatch = _useControlledReducer[1];
4002
4003 var activeIndex = state.activeIndex,
4004 selectedItems = state.selectedItems; // Refs.
4005
4006 var isInitialMountRef = useRef(true);
4007 var dropdownRef = useRef(null);
4008 var previousSelectedItemsRef = useRef(selectedItems);
4009 var selectedItemRefs = useRef();
4010 selectedItemRefs.current = [];
4011 var latest = useLatestRef({
4012 state: state,
4013 props: props
4014 }); // Effects.
4015
4016 /* Sets a11y status message on changes in selectedItem. */
4017
4018 useEffect(function () {
4019 if (isInitialMountRef.current) {
4020 return;
4021 }
4022
4023 if (selectedItems.length < previousSelectedItemsRef.current.length) {
4024 var removedSelectedItem = previousSelectedItemsRef.current.find(function (item) {
4025 return selectedItems.indexOf(item) < 0;
4026 });
4027 setStatus(getA11yRemovalMessage({
4028 itemToString: itemToString,
4029 resultCount: selectedItems.length,
4030 removedSelectedItem: removedSelectedItem,
4031 activeIndex: activeIndex,
4032 activeSelectedItem: selectedItems[activeIndex]
4033 }), environment.document);
4034 }
4035
4036 previousSelectedItemsRef.current = selectedItems; // eslint-disable-next-line react-hooks/exhaustive-deps
4037 }, [selectedItems.length]); // Sets focus on active item.
4038
4039 useEffect(function () {
4040 if (isInitialMountRef.current) {
4041 return;
4042 }
4043
4044 if (activeIndex === -1 && dropdownRef.current) {
4045 dropdownRef.current.focus();
4046 } else if (selectedItemRefs.current[activeIndex]) {
4047 selectedItemRefs.current[activeIndex].focus();
4048 }
4049 }, [activeIndex]);
4050 useControlPropsValidator({
4051 isInitialMount: isInitialMountRef.current,
4052 props: props,
4053 state: state
4054 });
4055 var setGetterPropCallInfo = useGetterPropsCalledChecker('getDropdownProps'); // Make initial ref false.
4056
4057 useEffect(function () {
4058 isInitialMountRef.current = false;
4059 }, []); // Event handler functions.
4060
4061 var selectedItemKeyDownHandlers = useMemo(function () {
4062 var _ref;
4063
4064 return _ref = {}, _ref[keyNavigationPrevious] = function () {
4065 dispatch({
4066 type: SelectedItemKeyDownNavigationPrevious
4067 });
4068 }, _ref[keyNavigationNext] = function () {
4069 dispatch({
4070 type: SelectedItemKeyDownNavigationNext
4071 });
4072 }, _ref.Delete = function Delete() {
4073 dispatch({
4074 type: SelectedItemKeyDownDelete
4075 });
4076 }, _ref.Backspace = function Backspace() {
4077 dispatch({
4078 type: SelectedItemKeyDownBackspace
4079 });
4080 }, _ref;
4081 }, [dispatch, keyNavigationNext, keyNavigationPrevious]);
4082 var dropdownKeyDownHandlers = useMemo(function () {
4083 var _ref2;
4084
4085 return _ref2 = {}, _ref2[keyNavigationPrevious] = function (event) {
4086 if (isKeyDownOperationPermitted(event)) {
4087 dispatch({
4088 type: DropdownKeyDownNavigationPrevious
4089 });
4090 }
4091 }, _ref2.Backspace = function Backspace(event) {
4092 if (isKeyDownOperationPermitted(event)) {
4093 dispatch({
4094 type: DropdownKeyDownBackspace
4095 });
4096 }
4097 }, _ref2;
4098 }, [dispatch, keyNavigationPrevious]); // Getter props.
4099
4100 var getSelectedItemProps = useCallback(function (_temp) {
4101 var _extends2;
4102
4103 var _ref3 = _temp === void 0 ? {} : _temp,
4104 _ref3$refKey = _ref3.refKey,
4105 refKey = _ref3$refKey === void 0 ? 'ref' : _ref3$refKey,
4106 ref = _ref3.ref,
4107 onClick = _ref3.onClick,
4108 onKeyDown = _ref3.onKeyDown,
4109 selectedItem = _ref3.selectedItem,
4110 index = _ref3.index,
4111 rest = _objectWithoutPropertiesLoose(_ref3, ["refKey", "ref", "onClick", "onKeyDown", "selectedItem", "index"]);
4112
4113 var latestState = latest.current.state;
4114 var itemIndex = getItemIndex(index, selectedItem, latestState.selectedItems);
4115
4116 if (itemIndex < 0) {
4117 throw new Error('Pass either selectedItem or index in getSelectedItemProps!');
4118 }
4119
4120 var selectedItemHandleClick = function selectedItemHandleClick() {
4121 dispatch({
4122 type: SelectedItemClick,
4123 index: index
4124 });
4125 };
4126
4127 var selectedItemHandleKeyDown = function selectedItemHandleKeyDown(event) {
4128 var key = normalizeArrowKey(event);
4129
4130 if (key && selectedItemKeyDownHandlers[key]) {
4131 selectedItemKeyDownHandlers[key](event);
4132 }
4133 };
4134
4135 return _extends((_extends2 = {}, _extends2[refKey] = handleRefs(ref, function (selectedItemNode) {
4136 if (selectedItemNode) {
4137 selectedItemRefs.current.push(selectedItemNode);
4138 }
4139 }), _extends2.tabIndex = index === latestState.activeIndex ? 0 : -1, _extends2.onClick = callAllEventHandlers(onClick, selectedItemHandleClick), _extends2.onKeyDown = callAllEventHandlers(onKeyDown, selectedItemHandleKeyDown), _extends2), rest);
4140 }, [dispatch, latest, selectedItemKeyDownHandlers]);
4141 var getDropdownProps = useCallback(function (_temp2, _temp3) {
4142 var _extends3;
4143
4144 var _ref4 = _temp2 === void 0 ? {} : _temp2,
4145 _ref4$refKey = _ref4.refKey,
4146 refKey = _ref4$refKey === void 0 ? 'ref' : _ref4$refKey,
4147 ref = _ref4.ref,
4148 onKeyDown = _ref4.onKeyDown,
4149 onClick = _ref4.onClick,
4150 _ref4$preventKeyActio = _ref4.preventKeyAction,
4151 preventKeyAction = _ref4$preventKeyActio === void 0 ? false : _ref4$preventKeyActio,
4152 rest = _objectWithoutPropertiesLoose(_ref4, ["refKey", "ref", "onKeyDown", "onClick", "preventKeyAction"]);
4153
4154 var _ref5 = _temp3 === void 0 ? {} : _temp3,
4155 _ref5$suppressRefErro = _ref5.suppressRefError,
4156 suppressRefError = _ref5$suppressRefErro === void 0 ? false : _ref5$suppressRefErro;
4157
4158 setGetterPropCallInfo('getDropdownProps', suppressRefError, refKey, dropdownRef);
4159
4160 var dropdownHandleKeyDown = function dropdownHandleKeyDown(event) {
4161 var key = normalizeArrowKey(event);
4162
4163 if (key && dropdownKeyDownHandlers[key]) {
4164 dropdownKeyDownHandlers[key](event);
4165 }
4166 };
4167
4168 var dropdownHandleClick = function dropdownHandleClick() {
4169 dispatch({
4170 type: DropdownClick
4171 });
4172 };
4173
4174 return _extends((_extends3 = {}, _extends3[refKey] = handleRefs(ref, function (dropdownNode) {
4175 if (dropdownNode) {
4176 dropdownRef.current = dropdownNode;
4177 }
4178 }), _extends3), !preventKeyAction && {
4179 onKeyDown: callAllEventHandlers(onKeyDown, dropdownHandleKeyDown),
4180 onClick: callAllEventHandlers(onClick, dropdownHandleClick)
4181 }, rest);
4182 }, [dispatch, dropdownKeyDownHandlers, setGetterPropCallInfo]); // returns
4183
4184 var addSelectedItem = useCallback(function (selectedItem) {
4185 dispatch({
4186 type: FunctionAddSelectedItem,
4187 selectedItem: selectedItem
4188 });
4189 }, [dispatch]);
4190 var removeSelectedItem = useCallback(function (selectedItem) {
4191 dispatch({
4192 type: FunctionRemoveSelectedItem,
4193 selectedItem: selectedItem
4194 });
4195 }, [dispatch]);
4196 var setSelectedItems = useCallback(function (newSelectedItems) {
4197 dispatch({
4198 type: FunctionSetSelectedItems,
4199 selectedItems: newSelectedItems
4200 });
4201 }, [dispatch]);
4202 var setActiveIndex = useCallback(function (newActiveIndex) {
4203 dispatch({
4204 type: FunctionSetActiveIndex,
4205 activeIndex: newActiveIndex
4206 });
4207 }, [dispatch]);
4208 var reset = useCallback(function () {
4209 dispatch({
4210 type: FunctionReset$2
4211 });
4212 }, [dispatch]);
4213 return {
4214 getSelectedItemProps: getSelectedItemProps,
4215 getDropdownProps: getDropdownProps,
4216 addSelectedItem: addSelectedItem,
4217 removeSelectedItem: removeSelectedItem,
4218 setSelectedItems: setSelectedItems,
4219 setActiveIndex: setActiveIndex,
4220 reset: reset,
4221 selectedItems: selectedItems,
4222 activeIndex: activeIndex
4223 };
4224}
4225
4226export default Downshift;
4227export { resetIdCounter, useCombobox, useMultipleSelection, useSelect };