UNPKG

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