UNPKG

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