UNPKG

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