UNPKG

44.6 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.isInteractive = isInteractive;
7exports.default = void 0;
8
9var React = _interopRequireWildcard(require("react"));
10
11var _overrides = require("../helpers/overrides.js");
12
13var _deleteAlt = _interopRequireDefault(require("../icon/delete-alt.js"));
14
15var _triangleDown = _interopRequireDefault(require("../icon/triangle-down.js"));
16
17var _search = _interopRequireDefault(require("../icon/search.js"));
18
19var _index = require("../locale/index.js");
20
21var _index2 = require("../popover/index.js");
22
23var _index3 = require("../spinner/index.js");
24
25var _getBuiId = _interopRequireDefault(require("../utils/get-bui-id.js"));
26
27var _autosizeInput = _interopRequireDefault(require("./autosize-input.js"));
28
29var _constants = require("./constants.js");
30
31var _defaultProps = _interopRequireDefault(require("./default-props.js"));
32
33var _dropdown = _interopRequireDefault(require("./dropdown.js"));
34
35var _styledComponents = require("./styled-components.js");
36
37var _index4 = require("./utils/index.js");
38
39function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
40
41function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
42
43function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
44
45function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
46
47function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
48
49function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
50
51function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
52
53function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { return; } var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
54
55function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
56
57function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
58
59function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
60
61function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
62
63function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
64
65function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
66
67function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
68
69function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
70
71function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
72
73function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
74
75function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
76
77function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
78
79function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
80
81function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
82
83function Noop() {
84 return null;
85}
86
87var isClick = function isClick(event) {
88 return event.type === 'click';
89};
90
91var isLeftClick = function isLeftClick(event) {
92 return event.button !== null && event.button !== undefined && event.button === 0;
93};
94
95var containsNode = function containsNode(parent, child) {
96 if (typeof document !== 'undefined') {
97 // eslint-disable-next-line flowtype/no-weak-types
98 return child && parent && parent.contains(child);
99 }
100};
101
102function isInteractive(rootTarget, rootElement) {
103 if (rootTarget instanceof Element) {
104 var target = rootTarget;
105
106 while (target && target !== rootElement) {
107 var role = target.getAttribute('role');
108
109 if (role === 'button' || role === 'link') {
110 return true;
111 }
112
113 if (target.tagName) target = target.parentElement;
114 }
115 }
116
117 return false;
118} // eslint-disable-next-line flowtype/no-weak-types
119
120
121var Select =
122/*#__PURE__*/
123function (_React$Component) {
124 _inherits(Select, _React$Component);
125
126 // anchor is a ref that refers to the outermost element rendered when the dropdown menu is not
127 // open. This is required so that we can check if clicks are on/off the anchor element.
128 // dropdown is a ref that refers to the popover element. This is required so that we can check if
129 // clicks are on/off the dropdown element.
130 // dragging is a flag to track whether a mobile device is currently scrolling versus clicking.
131 // focusAfterClear is a flag to indicate that the dropdowm menu should open after a selected
132 // option has been cleared.
133 // openAfterFocus is a flag to indicate that the dropdown menu should open when the component is
134 // focused. Developers have the option to disable initial clicks opening the dropdown menu. If not
135 // disabled, clicks will set this flag to true. Upon focusing, look to this to see if the menu should
136 // be opened, or only focus.
137 // When an item is selected, it also triggers handleClickOutside and since the selected item is
138 // already out of the menu (DOM), it will not recognize it as a subnode and triggers handleBlur
139 // that sets isOpen to false. That's a faulty logic causing visible problems when
140 // closeOnSelect is false. This flag helps to detect that selection was just made.
141 // the select components can accept an array of options or an object where properties are optgroups
142 // and values are arrays of options. this class property is constructed and updated in a normalized
143 // shape where optgroup titles are stored on the option in the __optgroup field.
144 // id generated for the listbox. used by screenreaders to associate the input with the menu it controls
145 function Select(props) {
146 var _this;
147
148 _classCallCheck(this, Select);
149
150 _this = _possibleConstructorReturn(this, _getPrototypeOf(Select).call(this, props));
151
152 _defineProperty(_assertThisInitialized(_this), "anchor", React.createRef());
153
154 _defineProperty(_assertThisInitialized(_this), "dropdown", React.createRef());
155
156 _defineProperty(_assertThisInitialized(_this), "input", void 0);
157
158 _defineProperty(_assertThisInitialized(_this), "dragging", void 0);
159
160 _defineProperty(_assertThisInitialized(_this), "focusAfterClear", void 0);
161
162 _defineProperty(_assertThisInitialized(_this), "openAfterFocus", void 0);
163
164 _defineProperty(_assertThisInitialized(_this), "justSelected", void 0);
165
166 _defineProperty(_assertThisInitialized(_this), "options", []);
167
168 _defineProperty(_assertThisInitialized(_this), "listboxId", (0, _getBuiId.default)());
169
170 _defineProperty(_assertThisInitialized(_this), "state", {
171 activeDescendant: null,
172 inputValue: '',
173 isFocused: false,
174 isOpen: _this.props.startOpen,
175 isPseudoFocused: false
176 });
177
178 _defineProperty(_assertThisInitialized(_this), "isMounted", false);
179
180 _defineProperty(_assertThisInitialized(_this), "handleTouchOutside", function (event) {
181 if (containsNode(_this.dropdown.current, event.target)) return;
182
183 if (!containsNode(_this.anchor.current, event.target)) {
184 _this.closeMenu();
185 }
186 });
187
188 _defineProperty(_assertThisInitialized(_this), "handleTouchMove", function () {
189 return _this.dragging = true;
190 });
191
192 _defineProperty(_assertThisInitialized(_this), "handleTouchStart", function () {
193 return _this.dragging = false;
194 });
195
196 _defineProperty(_assertThisInitialized(_this), "handleTouchEnd", function (event) {
197 if (_this.dragging) return;
198
199 _this.handleClick(event);
200 });
201
202 _defineProperty(_assertThisInitialized(_this), "handleTouchEndClearValue", function (event) {
203 if (_this.dragging) return;
204
205 _this.clearValue(event);
206 });
207
208 _defineProperty(_assertThisInitialized(_this), "handleClick", function (event) {
209 if (_this.props.disabled || !isClick(event) && !isLeftClick(event)) {
210 return;
211 } // Case comes up when text has been typed into the input field. If no text provided,
212 // the 'input' element will have essentially 0 width therefore will not be clickable.
213 // When click outside does not reset input, text provided will stay rendered after clicks away
214 // from the select component. Upon subsequent clicks on the provided text, open the dropdown
215 // menu, in addition to text edit operations.
216
217
218 if (event.target === _this.input) {
219 // CHASE: not sure why this condition is here. I cannot replicate a situation where clicks
220 // on provided text break into here.
221 if (!_this.state.isFocused) {
222 _this.openAfterFocus = _this.props.openOnClick;
223
224 _this.focus();
225
226 return;
227 }
228
229 if (!_this.state.isOpen) {
230 _this.setState({
231 isOpen: true,
232 isPseudoFocused: false
233 });
234
235 return;
236 }
237 } // Ensures that interactive elements within the Select component do not trigger the outer click
238 // handler. For example, after an option is selected clicks on the 'clear' icon call here. We
239 // should ignore those events. This comes after case where click is on input element, so that
240 // those are handled on their own.
241
242
243 if (_this.input && isInteractive(event.target, _this.input)) {
244 return;
245 } // For the simple case where clicking on the Select does not allow for providing
246 // text input to filter the dropdown options.
247
248
249 if (!_this.props.searchable) {
250 _this.focus();
251
252 _this.setState(function (prev) {
253 return {
254 isOpen: !prev.isOpen
255 };
256 });
257
258 return;
259 } // Cases below only apply to searchable Select component.
260
261
262 if (_this.state.isFocused) {
263 // iOS ignores programmatic calls to input.focus() that were not triggered by a click event.
264 // This component can get into a state where isFocused is true, but the DOM node is not
265 // focused. Call focus here again to ensure.
266 _this.focus(); // Case comes up when click outside does not reset input - once text has been provided to
267 // the input, and the user closes the dropdown menu the provided text is maintained. After
268 // this, if the user focuses back into the select component then clicks on the component,
269 // the provided text highlights rather than position's the cursor at the end of the input.
270
271
272 if (_this.input) _this.input.value = '';
273
274 _this.setState(function (prev) {
275 return {
276 isOpen: !_this.focusAfterClear && !prev.isOpen,
277 isPseudoFocused: false
278 };
279 });
280
281 _this.focusAfterClear = false;
282 } else {
283 _this.openAfterFocus = _this.props.openOnClick;
284
285 _this.focus();
286 }
287 });
288
289 _defineProperty(_assertThisInitialized(_this), "handleInputFocus", function (event) {
290 if (_this.props.disabled) return;
291 if (_this.props.onFocus) _this.props.onFocus(event);
292 var toOpen = _this.state.isOpen || _this.openAfterFocus; // if focus happens after clear values, don't open dropdown yet.
293
294 toOpen = !_this.focusAfterClear && toOpen;
295
296 _this.setState({
297 isFocused: true,
298 isOpen: !!toOpen
299 });
300
301 _this.focusAfterClear = false;
302 _this.openAfterFocus = false;
303 });
304
305 _defineProperty(_assertThisInitialized(_this), "handleBlur", function (event) {
306 if (event.relatedTarget) {
307 if (containsNode(_this.anchor.current, event.relatedTarget) || containsNode(_this.dropdown.current, event.relatedTarget)) {
308 return;
309 }
310 } else if (containsNode(_this.anchor.current, event.target)) {
311 return;
312 }
313
314 if (_this.props.onBlur) {
315 _this.props.onBlur(event);
316 }
317
318 if (_this.isMounted) {
319 _this.setState({
320 isFocused: false,
321 isOpen: false,
322 isPseudoFocused: false,
323 inputValue: _this.props.onBlurResetsInput ? '' : _this.state.inputValue
324 });
325 }
326 });
327
328 _defineProperty(_assertThisInitialized(_this), "handleClickOutside", function (event) {
329 if (_this.justSelected) {
330 _this.justSelected = false;
331 return;
332 }
333
334 if (containsNode(_this.dropdown.current, event.target)) return;
335 var isFocused = _this.state.isFocused || _this.state.isPseudoFocused;
336
337 if (isFocused && !containsNode(_this.anchor.current, event.target)) {
338 _this.handleBlur(event);
339 }
340 });
341
342 _defineProperty(_assertThisInitialized(_this), "handleInputChange", function (event) {
343 var newInputValue = event.target.value;
344
345 _this.setState({
346 inputValue: newInputValue,
347 isOpen: true,
348 isPseudoFocused: false
349 });
350
351 if (_this.props.onInputChange) {
352 _this.props.onInputChange(event);
353 }
354 });
355
356 _defineProperty(_assertThisInitialized(_this), "handleKeyDown", function (event) {
357 if (_this.props.disabled) return;
358
359 switch (event.keyCode) {
360 case 8:
361 // backspace
362 if (!_this.state.inputValue && _this.props.backspaceRemoves) {
363 event.preventDefault();
364
365 _this.backspaceValue();
366 }
367
368 break;
369
370 case 9:
371 // tab
372 _this.setState(function (prevState) {
373 return {
374 isPseudoFocused: false,
375 isFocused: false,
376 isOpen: false,
377 inputValue: !_this.props.onCloseResetsInput || !_this.props.onBlurResetsInput ? prevState.inputValue : ''
378 };
379 });
380
381 break;
382
383 case 27:
384 // escape
385 if (!_this.state.isOpen && _this.props.clearable && _this.props.escapeClearsValue) {
386 _this.clearValue(event);
387
388 _this.setState({
389 isFocused: false,
390 isPseudoFocused: false
391 });
392 }
393
394 break;
395
396 case 32:
397 // space
398 if (_this.props.searchable) {
399 break;
400 }
401
402 event.preventDefault();
403
404 if (!_this.state.isOpen) {
405 _this.setState({
406 isOpen: true
407 });
408 }
409
410 break;
411
412 case 38:
413 // up
414 event.preventDefault();
415
416 if (!_this.state.isOpen) {
417 _this.setState({
418 isOpen: true
419 });
420 }
421
422 break;
423
424 case 40:
425 // down
426 event.preventDefault();
427
428 if (!_this.state.isOpen) {
429 _this.setState({
430 isOpen: true
431 });
432 }
433
434 break;
435
436 case 33:
437 // page up
438 event.preventDefault();
439
440 if (!_this.state.isOpen) {
441 _this.setState({
442 isOpen: true
443 });
444 }
445
446 break;
447
448 case 34:
449 // page down
450 event.preventDefault();
451
452 if (!_this.state.isOpen) {
453 _this.setState({
454 isOpen: true
455 });
456 }
457
458 break;
459
460 case 35:
461 // end key
462 if (event.shiftKey) {
463 break;
464 }
465
466 event.preventDefault();
467
468 if (!_this.state.isOpen) {
469 _this.setState({
470 isOpen: true
471 });
472 }
473
474 break;
475
476 case 36:
477 // home key
478 if (event.shiftKey) {
479 break;
480 }
481
482 event.preventDefault();
483
484 if (!_this.state.isOpen) {
485 _this.setState({
486 isOpen: true
487 });
488 }
489
490 break;
491
492 case 46:
493 // delete
494 if (!_this.state.inputValue && _this.props.deleteRemoves) {
495 event.preventDefault();
496
497 _this.popValue();
498 }
499
500 break;
501 }
502 });
503
504 _defineProperty(_assertThisInitialized(_this), "getOptionLabel", function (locale, _ref) {
505 var option = _ref.option;
506 return option.isCreatable ? "".concat(locale.select.create, " \u201C").concat(option[_this.props.labelKey], "\u201D") : option[_this.props.labelKey];
507 });
508
509 _defineProperty(_assertThisInitialized(_this), "getValueLabel", function (_ref2) {
510 var option = _ref2.option;
511 return option[_this.props.labelKey];
512 });
513
514 _defineProperty(_assertThisInitialized(_this), "handleActiveDescendantChange", function (id) {
515 if (id) {
516 _this.setState({
517 activeDescendant: id
518 });
519 } else {
520 _this.setState({
521 activeDescendant: null
522 });
523 }
524 });
525
526 _defineProperty(_assertThisInitialized(_this), "handleInputRef", function (input) {
527 _this.input = input;
528
529 if (_this.props.controlRef) {
530 if (typeof _this.props.controlRef === 'function') {
531 _this.props.controlRef(input);
532 } else {
533 _this.props.controlRef.current = input;
534 }
535 }
536 });
537
538 _defineProperty(_assertThisInitialized(_this), "selectValue", function (_ref3) {
539 var item = _ref3.item;
540
541 if (item.disabled) {
542 return;
543 }
544
545 _this.justSelected = true; // NOTE: we add/set the value in a callback to make sure the
546 // input value is empty to avoid styling issues in Chrome
547
548 var updatedValue = _this.props.onSelectResetsInput ? '' : _this.state.inputValue;
549
550 if (_this.props.multi) {
551 _this.setState({
552 inputValue: updatedValue,
553 isOpen: !_this.props.closeOnSelect
554 }, function () {
555 var valueArray = _this.props.value;
556
557 if (valueArray.some(function (i) {
558 return i[_this.props.valueKey] === item[_this.props.valueKey];
559 })) {
560 _this.removeValue(item);
561 } else {
562 _this.addValue(item);
563 }
564 });
565 } else {
566 _this.focus();
567
568 _this.setState({
569 inputValue: updatedValue,
570 isOpen: !_this.props.closeOnSelect,
571 isFocused: true,
572 isPseudoFocused: false
573 }, function () {
574 _this.setValue([item], item, _constants.STATE_CHANGE_TYPE.select);
575 });
576 }
577 });
578
579 _defineProperty(_assertThisInitialized(_this), "addValue", function (item) {
580 var valueArray = _toConsumableArray(_this.props.value);
581
582 _this.setValue(valueArray.concat(item), item, _constants.STATE_CHANGE_TYPE.select);
583 });
584
585 _defineProperty(_assertThisInitialized(_this), "backspaceValue", function () {
586 var item = _this.popValue();
587
588 if (!item) {
589 return;
590 }
591
592 var valueLength = _this.props.value.length;
593 var renderLabel = _this.props.getValueLabel || _this.getValueLabel;
594 var labelForInput = renderLabel({
595 option: item,
596 index: valueLength - 1
597 }); // label might not be a string, it might be a Node of another kind.
598
599 if (!_this.props.backspaceClearsInputValue && typeof labelForInput === 'string') {
600 var remainingInput = labelForInput.slice(0, -1);
601
602 _this.setState({
603 inputValue: remainingInput,
604 isOpen: true
605 });
606 }
607 });
608
609 _defineProperty(_assertThisInitialized(_this), "popValue", function () {
610 var valueArray = _toConsumableArray(_this.props.value);
611
612 var valueLength = valueArray.length;
613 if (!valueLength) return;
614 if (valueArray[valueLength - 1].clearableValue === false) return;
615 var item = valueArray.pop();
616
617 _this.setValue(valueArray, item, _constants.STATE_CHANGE_TYPE.remove);
618
619 return item;
620 });
621
622 _defineProperty(_assertThisInitialized(_this), "removeValue", function (item) {
623 var valueArray = _toConsumableArray(_this.props.value);
624
625 _this.setValue(valueArray.filter(function (i) {
626 return i[_this.props.valueKey] !== item[_this.props.valueKey];
627 }), item, _constants.STATE_CHANGE_TYPE.remove);
628
629 _this.focus();
630 });
631
632 _defineProperty(_assertThisInitialized(_this), "clearValue", function (event) {
633 if (isClick(event) && !isLeftClick(event)) return;
634
635 if (_this.props.value) {
636 var resetValue = _this.props.value.filter(function (item) {
637 return item.clearableValue === false;
638 });
639
640 _this.setValue(resetValue, null, _constants.STATE_CHANGE_TYPE.clear);
641 }
642
643 _this.setState({
644 inputValue: '',
645 isOpen: false
646 });
647
648 _this.focus();
649
650 _this.focusAfterClear = true;
651 });
652
653 _defineProperty(_assertThisInitialized(_this), "shouldShowPlaceholder", function () {
654 return !(_this.state.inputValue || _this.props.value && _this.props.value.length);
655 });
656
657 _defineProperty(_assertThisInitialized(_this), "shouldShowValue", function () {
658 return !_this.state.inputValue;
659 });
660
661 _this.options = (0, _index4.normalizeOptions)(props.options);
662 return _this;
663 }
664
665 _createClass(Select, [{
666 key: "componentDidMount",
667 value: function componentDidMount() {
668 if (this.props.autoFocus) {
669 this.focus();
670 }
671
672 this.isMounted = true;
673 }
674 }, {
675 key: "componentDidUpdate",
676 value: function componentDidUpdate(prevProps, prevState) {
677 if (typeof document !== 'undefined') {
678 if (prevState.isOpen !== this.state.isOpen) {
679 if (this.state.isOpen) {
680 this.props.onOpen && this.props.onOpen();
681 document.addEventListener('touchstart', this.handleTouchOutside);
682 } else {
683 this.props.onClose && this.props.onClose();
684 document.removeEventListener('touchstart', this.handleTouchOutside);
685 }
686 }
687
688 if (!prevState.isFocused && this.state.isFocused) {
689 document.addEventListener('click', this.handleClickOutside);
690 }
691 }
692 }
693 }, {
694 key: "componentWillUnmount",
695 value: function componentWillUnmount() {
696 if (typeof document !== 'undefined') {
697 document.removeEventListener('touchstart', this.handleTouchOutside);
698 document.removeEventListener('click', this.handleClickOutside);
699 }
700
701 this.isMounted = false;
702 }
703 }, {
704 key: "focus",
705 value: function focus() {
706 if (!this.input) return;
707 this.input.focus();
708 } // Handle touch outside on mobile to dismiss menu, ensures that the
709 // touch target is not within the anchor DOM node.
710
711 }, {
712 key: "closeMenu",
713 value: function closeMenu() {
714 if (this.props.onCloseResetsInput) {
715 this.setState({
716 inputValue: '',
717 isOpen: false,
718 isPseudoFocused: this.state.isFocused && !this.props.multi
719 });
720 } else {
721 this.setState({
722 isOpen: false,
723 isPseudoFocused: this.state.isFocused && !this.props.multi
724 });
725 }
726 }
727 }, {
728 key: "getValueArray",
729
730 /**
731 * Extends the value into an array from the given options
732 */
733 value: function getValueArray(value) {
734 var _this2 = this;
735
736 if (!Array.isArray(value)) {
737 if (value === null || value === undefined) return [];
738 value = [value];
739 }
740
741 return value.map(function (value) {
742 return (0, _index4.expandValue)(value, _this2.props);
743 });
744 }
745 }, {
746 key: "setValue",
747 value: function setValue(value, option, type) {
748 if (this.props.onChange) {
749 this.props.onChange({
750 value: value,
751 option: option,
752 type: type
753 });
754 }
755 }
756 }, {
757 key: "renderLoading",
758 value: function renderLoading() {
759 if (!this.props.isLoading) return;
760 var sharedProps = this.getSharedProps();
761 var _this$props$overrides = this.props.overrides,
762 overrides = _this$props$overrides === void 0 ? {} : _this$props$overrides;
763
764 var _getOverrides = (0, _overrides.getOverrides)(overrides.LoadingIndicator, _index3.Spinner),
765 _getOverrides2 = _slicedToArray(_getOverrides, 2),
766 LoadingIndicator = _getOverrides2[0],
767 loadingIndicatorProps = _getOverrides2[1];
768
769 return React.createElement(LoadingIndicator, _extends({
770 size: 16,
771 overrides: {
772 Svg: {
773 style: _styledComponents.getLoadingIconStyles
774 }
775 },
776 $silenceV11DeprecationWarning: true
777 }, sharedProps, loadingIndicatorProps));
778 }
779 }, {
780 key: "renderValue",
781 value: function renderValue(valueArray, isOpen, locale) {
782 var _this3 = this;
783
784 var _this$props$overrides2 = this.props.overrides,
785 overrides = _this$props$overrides2 === void 0 ? {} : _this$props$overrides2;
786 var sharedProps = this.getSharedProps();
787 var renderLabel = this.props.getValueLabel || this.getValueLabel;
788 var Value = this.props.valueComponent || Noop;
789
790 if (!valueArray.length) {
791 return null;
792 }
793
794 if (this.props.multi) {
795 return valueArray.map(function (value, i) {
796 var disabled = sharedProps.$disabled || value.clearableValue === false;
797 return React.createElement(Value, _extends({
798 value: value,
799 key: "value-".concat(i, "-").concat(value[_this3.props.valueKey]),
800 removeValue: function removeValue() {
801 return _this3.removeValue(value);
802 },
803 disabled: disabled,
804 overrides: {
805 Tag: overrides.Tag,
806 MultiValue: overrides.MultiValue
807 }
808 }, sharedProps, {
809 $disabled: disabled
810 }), renderLabel({
811 option: value,
812 index: i
813 }));
814 });
815 } else if (this.shouldShowValue()) {
816 return React.createElement(Value, _extends({
817 value: valueArray[0][this.props.valueKey],
818 disabled: this.props.disabled,
819 overrides: {
820 SingleValue: overrides.SingleValue
821 }
822 }, sharedProps), renderLabel({
823 option: valueArray[0]
824 }));
825 }
826 }
827 }, {
828 key: "renderInput",
829 value: function renderInput() {
830 var _this4 = this;
831
832 var _this$props$overrides3 = this.props.overrides,
833 overrides = _this$props$overrides3 === void 0 ? {} : _this$props$overrides3;
834
835 var _getOverrides3 = (0, _overrides.getOverrides)(overrides.InputContainer, _styledComponents.StyledInputContainer),
836 _getOverrides4 = _slicedToArray(_getOverrides3, 2),
837 InputContainer = _getOverrides4[0],
838 inputContainerProps = _getOverrides4[1];
839
840 var sharedProps = this.getSharedProps();
841 var isOpen = this.state.isOpen;
842 var selected = this.getValueArray(this.props.value).map(function (v) {
843 return v[_this4.props.labelKey];
844 }).join(', ');
845 var selectedLabel = selected.length ? "Selected ".concat(selected, ". ") : '';
846 var label = "".concat(selectedLabel).concat(this.props['aria-label'] || '');
847
848 if (!this.props.searchable) {
849 return React.createElement(InputContainer, _extends({
850 "aria-activedescendant": this.state.activeDescendant,
851 "aria-expanded": isOpen,
852 "aria-disabled": this.props.disabled,
853 "aria-label": label,
854 "aria-labelledby": this.props['aria-labelledby'],
855 "aria-owns": this.state.isOpen ? this.listboxId : null,
856 "aria-required": this.props.required || null,
857 onFocus: this.handleInputFocus,
858 ref: this.handleInputRef,
859 tabIndex: 0
860 }, sharedProps, inputContainerProps));
861 }
862
863 return React.createElement(InputContainer, _extends({}, sharedProps, inputContainerProps), React.createElement(_autosizeInput.default, _extends({
864 "aria-activedescendant": this.state.activeDescendant,
865 "aria-autocomplete": "list",
866 "aria-controls": this.state.isOpen ? this.listboxId : null,
867 "aria-describedby": this.props['aria-describedby'],
868 "aria-errormessage": this.props['aria-errormessage'],
869 "aria-disabled": this.props.disabled || null,
870 "aria-expanded": isOpen,
871 "aria-haspopup": "listbox",
872 "aria-label": label,
873 "aria-labelledby": this.props['aria-labelledby'],
874 "aria-required": this.props.required || null,
875 disabled: this.props.disabled || null,
876 id: this.props.id || null,
877 inputRef: this.handleInputRef,
878 onChange: this.handleInputChange,
879 onFocus: this.handleInputFocus,
880 overrides: {
881 Input: overrides.Input
882 },
883 required: this.props.required && !this.props.value.length || null,
884 role: "combobox",
885 value: this.state.inputValue,
886 tabIndex: 0
887 }, sharedProps)));
888 }
889 }, {
890 key: "renderClear",
891 value: function renderClear() {
892 var isValueEntered = Boolean(this.props.value && this.props.value.length || this.state.inputValue);
893
894 if (!this.props.clearable || this.props.disabled || this.props.isLoading || !isValueEntered) {
895 return;
896 }
897
898 var sharedProps = this.getSharedProps();
899 var _this$props$overrides4 = this.props.overrides,
900 overrides = _this$props$overrides4 === void 0 ? {} : _this$props$overrides4;
901
902 var _getOverrides5 = (0, _overrides.getOverrides)(overrides.ClearIcon, _deleteAlt.default),
903 _getOverrides6 = _slicedToArray(_getOverrides5, 2),
904 ClearIcon = _getOverrides6[0],
905 clearIconProps = _getOverrides6[1];
906
907 var ariaLabel = this.props.multi ? 'Clear all' : 'Clear value';
908 return React.createElement(ClearIcon, _extends({
909 size: 16,
910 title: ariaLabel,
911 "aria-label": ariaLabel,
912 onClick: this.clearValue,
913 onTouchEnd: this.handleTouchEndClearValue,
914 onTouchMove: this.handleTouchMove,
915 onTouchStart: this.handleTouchStart,
916 role: "button",
917 overrides: {
918 Svg: {
919 component: _styledComponents.StyledClearIcon,
920 props: overrides.ClearIcon && overrides.ClearIcon.props ? overrides.ClearIcon.props : {},
921 style: overrides.ClearIcon && overrides.ClearIcon.style ? overrides.ClearIcon.style : {}
922 }
923 }
924 }, sharedProps, clearIconProps));
925 }
926 }, {
927 key: "renderArrow",
928 value: function renderArrow() {
929 if (this.props.type !== _constants.TYPE.select) {
930 return null;
931 }
932
933 var _this$props$overrides5 = this.props.overrides,
934 overrides = _this$props$overrides5 === void 0 ? {} : _this$props$overrides5;
935
936 var _getOverrides7 = (0, _overrides.getOverrides)(overrides.SelectArrow, _triangleDown.default),
937 _getOverrides8 = _slicedToArray(_getOverrides7, 2),
938 SelectArrow = _getOverrides8[0],
939 selectArrowProps = _getOverrides8[1];
940
941 var sharedProps = this.getSharedProps();
942 return React.createElement(SelectArrow, _extends({
943 size: 16,
944 title: 'open',
945 overrides: {
946 Svg: {
947 component: _styledComponents.StyledSelectArrow,
948 props: overrides.SelectArrow && overrides.SelectArrow.props ? overrides.SelectArrow.props : {},
949 style: overrides.SelectArrow && overrides.SelectArrow.style ? overrides.SelectArrow.style : {}
950 }
951 }
952 }, sharedProps, selectArrowProps));
953 }
954 }, {
955 key: "renderSearch",
956 value: function renderSearch() {
957 if (this.props.type !== _constants.TYPE.search) {
958 return null;
959 }
960
961 var _this$props$overrides6 = this.props.overrides,
962 overrides = _this$props$overrides6 === void 0 ? {} : _this$props$overrides6;
963
964 var _getOverrides9 = (0, _overrides.getOverrides)(overrides.SearchIconContainer, _styledComponents.StyledSearchIconContainer),
965 _getOverrides10 = _slicedToArray(_getOverrides9, 2),
966 SearchIconContainer = _getOverrides10[0],
967 searchIconContainerProps = _getOverrides10[1];
968
969 var _getOverrides11 = (0, _overrides.getOverrides)(overrides.SearchIcon, _search.default),
970 _getOverrides12 = _slicedToArray(_getOverrides11, 2),
971 SearchIcon = _getOverrides12[0],
972 searchIconProps = _getOverrides12[1];
973
974 var sharedProps = this.getSharedProps();
975 return (// TODO(v11): remove searchIconProps from SearchIconContainer
976 React.createElement(SearchIconContainer, _extends({}, sharedProps, searchIconProps, searchIconContainerProps), React.createElement(SearchIcon, _extends({
977 size: 16,
978 title: 'search'
979 }, searchIconProps)))
980 );
981 }
982 }, {
983 key: "filterOptions",
984 value: function filterOptions(excludeOptions) {
985 var _this5 = this;
986
987 var filterValue = this.state.inputValue; // apply filter function
988
989 if (this.props.filterOptions) {
990 this.options = this.props.filterOptions(this.options, filterValue, excludeOptions, {
991 valueKey: this.props.valueKey,
992 labelKey: this.props.labelKey
993 });
994 } // can user create a new option + there's no exact match already
995
996
997 if (filterValue && this.props.creatable && this.options.concat(this.props.value).every(function (opt) {
998 return opt[_this5.props.labelKey].toLowerCase() !== filterValue.toLowerCase().trim();
999 })) {
1000 var _this$options$push;
1001
1002 // $FlowFixMe - this.options is typed as a read-only array
1003 this.options.push((_this$options$push = {
1004 id: filterValue
1005 }, _defineProperty(_this$options$push, this.props.labelKey, filterValue), _defineProperty(_this$options$push, this.props.valueKey, filterValue), _defineProperty(_this$options$push, "isCreatable", true), _this$options$push));
1006 }
1007
1008 return this.options;
1009 }
1010 }, {
1011 key: "getSharedProps",
1012 value: function getSharedProps() {
1013 var _this$props = this.props,
1014 clearable = _this$props.clearable,
1015 creatable = _this$props.creatable,
1016 disabled = _this$props.disabled,
1017 error = _this$props.error,
1018 positive = _this$props.positive,
1019 isLoading = _this$props.isLoading,
1020 multi = _this$props.multi,
1021 required = _this$props.required,
1022 size = _this$props.size,
1023 searchable = _this$props.searchable,
1024 type = _this$props.type,
1025 value = _this$props.value;
1026 var _this$state = this.state,
1027 isOpen = _this$state.isOpen,
1028 isFocused = _this$state.isFocused,
1029 isPseudoFocused = _this$state.isPseudoFocused;
1030 return {
1031 $clearable: clearable,
1032 $creatable: creatable,
1033 $disabled: disabled,
1034 $error: error,
1035 $positive: positive,
1036 $isFocused: isFocused,
1037 $isLoading: isLoading,
1038 $isOpen: isOpen,
1039 $isPseudoFocused: isPseudoFocused,
1040 $multi: multi,
1041 $required: required,
1042 $searchable: searchable,
1043 $size: size,
1044 $type: type,
1045 $isEmpty: !this.getValueArray(value).length
1046 };
1047 }
1048 }, {
1049 key: "render",
1050 value: function render() {
1051 var _this6 = this;
1052
1053 this.options = (0, _index4.normalizeOptions)(this.props.options);
1054 var _this$props2 = this.props,
1055 _this$props2$override = _this$props2.overrides,
1056 overrides = _this$props2$override === void 0 ? {} : _this$props2$override,
1057 type = _this$props2.type,
1058 multi = _this$props2.multi,
1059 noResultsMsg = _this$props2.noResultsMsg,
1060 value = _this$props2.value,
1061 filterOutSelected = _this$props2.filterOutSelected;
1062
1063 if (process.env.NODE_ENV !== "production") {
1064 // value may be nullish, only warn if value is defined
1065 if (value && !Array.isArray(value)) {
1066 console.warn('The Select component expects an array as the value prop. For more information, please visit the docs at https://baseweb.design/components/select/');
1067 }
1068 }
1069
1070 var _getOverrides13 = (0, _overrides.getOverrides)(overrides.Root, _styledComponents.StyledRoot),
1071 _getOverrides14 = _slicedToArray(_getOverrides13, 2),
1072 Root = _getOverrides14[0],
1073 rootProps = _getOverrides14[1];
1074
1075 var _getOverrides15 = (0, _overrides.getOverrides)(overrides.ControlContainer, _styledComponents.StyledControlContainer),
1076 _getOverrides16 = _slicedToArray(_getOverrides15, 2),
1077 ControlContainer = _getOverrides16[0],
1078 controlContainerProps = _getOverrides16[1];
1079
1080 var _getOverrides17 = (0, _overrides.getOverrides)(overrides.ValueContainer, _styledComponents.StyledValueContainer),
1081 _getOverrides18 = _slicedToArray(_getOverrides17, 2),
1082 ValueContainer = _getOverrides18[0],
1083 valueContainerProps = _getOverrides18[1];
1084
1085 var _getOverrides19 = (0, _overrides.getOverrides)(overrides.IconsContainer, _styledComponents.StyledIconsContainer),
1086 _getOverrides20 = _slicedToArray(_getOverrides19, 2),
1087 IconsContainer = _getOverrides20[0],
1088 iconsContainerProps = _getOverrides20[1];
1089
1090 var _getOverrides21 = (0, _overrides.getOverrides)(overrides.Popover, _index2.Popover),
1091 _getOverrides22 = _slicedToArray(_getOverrides21, 2),
1092 PopoverOverride = _getOverrides22[0],
1093 popoverProps = _getOverrides22[1];
1094
1095 var _getOverrides23 = (0, _overrides.getOverrides)(overrides.Placeholder, _styledComponents.StyledPlaceholder),
1096 _getOverrides24 = _slicedToArray(_getOverrides23, 2),
1097 Placeholder = _getOverrides24[0],
1098 placeholderProps = _getOverrides24[1];
1099
1100 var sharedProps = this.getSharedProps();
1101 var valueArray = this.getValueArray(value);
1102 var options = this.filterOptions(multi && filterOutSelected ? valueArray : null);
1103 var isOpen = this.state.isOpen;
1104 sharedProps.$isOpen = isOpen;
1105
1106 if (process.env.NODE_ENV !== "production") {
1107 if (this.props.error && this.props.positive) {
1108 // eslint-disable-next-line no-console
1109 console.warn("[Select] `error` and `positive` are both set to `true`. `error` will take precedence but this may not be what you want.");
1110 }
1111 }
1112
1113 return React.createElement(_index.LocaleContext.Consumer, null, function (locale) {
1114 return React.createElement(PopoverOverride // Popover does not provide ability to forward refs through, and if we were to simply
1115 // apply the ref to the Root component below it would be overwritten before the popover
1116 // renders it. Using this strategy, we will get a ref to the popover, then reuse its
1117 // anchorRef so we can check if clicks are on the select component or not.
1118 // eslint-disable-next-line flowtype/no-weak-types
1119 , _extends({
1120 ref: function ref(_ref4) {
1121 if (!_ref4) return;
1122 _this6.anchor = _ref4.anchorRef;
1123 },
1124 focusLock: false,
1125 mountNode: _this6.props.mountNode,
1126 onEsc: function onEsc() {
1127 return _this6.closeMenu();
1128 },
1129 isOpen: isOpen,
1130 popoverMargin: 0,
1131 content: function content() {
1132 var dropdownProps = {
1133 error: _this6.props.error,
1134 positive: _this6.props.positive,
1135 getOptionLabel: _this6.props.getOptionLabel || _this6.getOptionLabel.bind(_this6, locale),
1136 id: _this6.listboxId,
1137 isLoading: _this6.props.isLoading,
1138 labelKey: _this6.props.labelKey,
1139 maxDropdownHeight: _this6.props.maxDropdownHeight,
1140 multi: multi,
1141 noResultsMsg: noResultsMsg,
1142 onActiveDescendantChange: _this6.handleActiveDescendantChange,
1143 onItemSelect: _this6.selectValue,
1144 options: options,
1145 overrides: overrides,
1146 required: _this6.props.required,
1147 searchable: _this6.props.searchable,
1148 size: _this6.props.size,
1149 type: type,
1150 value: valueArray,
1151 valueKey: _this6.props.valueKey,
1152 width: _this6.anchor.current ? _this6.anchor.current.clientWidth : null,
1153 keyboardControlNode: _this6.anchor
1154 };
1155 return React.createElement(_dropdown.default, _extends({
1156 innerRef: _this6.dropdown
1157 }, dropdownProps));
1158 },
1159 placement: _index2.PLACEMENT.bottom
1160 }, popoverProps), React.createElement(Root, _extends({
1161 onBlur: _this6.handleBlur,
1162 "data-baseweb": "select"
1163 }, sharedProps, rootProps), React.createElement(ControlContainer, _extends({
1164 onKeyDown: _this6.handleKeyDown,
1165 onClick: _this6.handleClick,
1166 onTouchEnd: _this6.handleTouchEnd,
1167 onTouchMove: _this6.handleTouchMove,
1168 onTouchStart: _this6.handleTouchStart
1169 }, sharedProps, controlContainerProps), type === _constants.TYPE.search ? _this6.renderSearch() : null, React.createElement(ValueContainer, _extends({}, sharedProps, valueContainerProps), _this6.renderValue(valueArray, isOpen, locale), _this6.renderInput(), _this6.shouldShowPlaceholder() ? React.createElement(Placeholder, _extends({}, sharedProps, placeholderProps), typeof _this6.props.placeholder !== 'undefined' ? _this6.props.placeholder : locale.select.placeholder) : null), React.createElement(IconsContainer, _extends({}, sharedProps, iconsContainerProps), _this6.renderLoading(), _this6.renderClear(), type === _constants.TYPE.select ? _this6.renderArrow() : null))));
1170 });
1171 }
1172 }]);
1173
1174 return Select;
1175}(React.Component);
1176
1177_defineProperty(Select, "defaultProps", _defaultProps.default);
1178
1179var _default = Select;
1180exports.default = _default;
\No newline at end of file