@instructure/ui-select 11.7.2-snapshot-47 → 11.7.2-snapshot-49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +12 -2
  2. package/es/Select/v2/Group/index.js +47 -0
  3. package/es/Select/v2/Group/props.js +26 -0
  4. package/es/Select/v2/Option/index.js +51 -0
  5. package/es/Select/v2/Option/props.js +26 -0
  6. package/es/Select/v2/index.js +704 -0
  7. package/es/Select/v2/props.js +35 -0
  8. package/es/Select/v2/styles.js +41 -0
  9. package/es/exports/b.js +26 -0
  10. package/lib/Select/v2/Group/index.js +53 -0
  11. package/lib/Select/v2/Group/props.js +31 -0
  12. package/lib/Select/v2/Option/index.js +57 -0
  13. package/lib/Select/v2/Option/props.js +31 -0
  14. package/lib/Select/v2/index.js +714 -0
  15. package/lib/Select/v2/props.js +40 -0
  16. package/lib/Select/v2/styles.js +47 -0
  17. package/lib/exports/b.js +26 -0
  18. package/package.json +29 -29
  19. package/src/Select/v2/Group/index.tsx +52 -0
  20. package/src/Select/v2/Group/props.ts +48 -0
  21. package/src/Select/v2/Option/index.tsx +56 -0
  22. package/src/Select/v2/Option/props.ts +82 -0
  23. package/src/Select/v2/README.md +1342 -0
  24. package/src/Select/v2/index.tsx +897 -0
  25. package/src/Select/v2/props.ts +333 -0
  26. package/src/Select/v2/styles.ts +48 -0
  27. package/src/exports/b.ts +31 -0
  28. package/tsconfig.build.tsbuildinfo +1 -1
  29. package/types/Select/v2/Group/index.d.ts +21 -0
  30. package/types/Select/v2/Group/index.d.ts.map +1 -0
  31. package/types/Select/v2/Group/props.d.ts +19 -0
  32. package/types/Select/v2/Group/props.d.ts.map +1 -0
  33. package/types/Select/v2/Option/index.d.ts +28 -0
  34. package/types/Select/v2/Option/index.d.ts.map +1 -0
  35. package/types/Select/v2/Option/props.d.ts +43 -0
  36. package/types/Select/v2/Option/props.d.ts.map +1 -0
  37. package/types/Select/v2/index.d.ts +138 -0
  38. package/types/Select/v2/index.d.ts.map +1 -0
  39. package/types/Select/v2/props.d.ts +206 -0
  40. package/types/Select/v2/props.d.ts.map +1 -0
  41. package/types/Select/v2/styles.d.ts +12 -0
  42. package/types/Select/v2/styles.d.ts.map +1 -0
  43. package/types/exports/b.d.ts +7 -0
  44. package/types/exports/b.d.ts.map +1 -0
@@ -0,0 +1,704 @@
1
+ import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
2
+ const _excluded = ["id", "renderLabel", "children"],
3
+ _excluded2 = ["renderLabel", "inputValue", "placeholder", "isRequired", "shouldNotWrap", "size", "isInline", "width", "htmlSize", "messages", "renderBeforeInput", "renderAfterInput", "onFocus", "onBlur", "onInputChange", "onRequestHideOptions", "layout"],
4
+ _excluded3 = ["ref"];
5
+ var _dec, _dec2, _class, _Select, _Options$Separator, _Options$Separator2;
6
+ /*
7
+ * The MIT License (MIT)
8
+ *
9
+ * Copyright (c) 2015 - present Instructure, Inc.
10
+ *
11
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ * of this software and associated documentation files (the "Software"), to deal
13
+ * in the Software without restriction, including without limitation the rights
14
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ * copies of the Software, and to permit persons to whom the Software is
16
+ * furnished to do so, subject to the following conditions:
17
+ *
18
+ * The above copyright notice and this permission notice shall be included in all
19
+ * copies or substantial portions of the Software.
20
+ *
21
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ * SOFTWARE.
28
+ */
29
+
30
+ import { Children, Component, memo } from 'react';
31
+ import * as utils from '@instructure/ui-utils';
32
+ import { combineDataCid } from '@instructure/ui-utils';
33
+ import { matchComponentTypes, omitProps, getInteraction, withDeterministicId } from '@instructure/ui-react-utils';
34
+ import { getBoundingClientRect, isActiveElement } from '@instructure/ui-dom-utils';
35
+ import { View } from '@instructure/ui-view/latest';
36
+ import { Selectable } from '@instructure/ui-selectable';
37
+ import { Popover } from '@instructure/ui-popover/latest';
38
+ import { TextInput } from '@instructure/ui-text-input/latest';
39
+ import { Options } from '@instructure/ui-options/latest';
40
+ import { ChevronDownInstUIIcon, ChevronUpInstUIIcon, CheckInstUIIcon } from '@instructure/ui-icons';
41
+ import { withStyle } from '@instructure/emotion';
42
+ import generateStyle from "./styles.js";
43
+ import { Group } from "./Group/index.js";
44
+ import { Option } from "./Option/index.js";
45
+ import { allowedProps } from "./props.js";
46
+ import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
47
+ const selectSizeToIconSize = {
48
+ small: 'sm',
49
+ medium: 'md',
50
+ large: 'lg'
51
+ };
52
+ // This memoed Option component is used to prevent unnecessary re-renders of
53
+ // Options.Item when the Select component is re-rendered. This is necessary
54
+ // because the Select component is re-rendered on every prop change of the <Select.Option>
55
+ // and with a large amount of options, this can cause a lot of unnecessary re-renders.
56
+ const MemoedOption = /*#__PURE__*/memo(function Opt(props) {
57
+ const optionsItemProps = props.optionsItemProps,
58
+ children = props.children;
59
+ return (
60
+ // The main <Options> that renders this is always an "ul"
61
+ _jsx(Options.Item, {
62
+ as: "li",
63
+ ...optionsItemProps,
64
+ children: children
65
+ })
66
+ );
67
+ },
68
+ // This is a custom equality function that checks if the props of the
69
+ // <Select.Option> have changed. If they haven't, then the Options.Item
70
+ // doesn't need to be re-rendered.
71
+ (prevProps, nextProps) => {
72
+ return prevProps.selectOption.props.isHighlighted === nextProps.selectOption.props.isHighlighted && prevProps.selectOption.props.isSelected === nextProps.selectOption.props.isSelected && prevProps.selectOption.props.isDisabled === nextProps.selectOption.props.isDisabled && prevProps.selectOption.props.children === nextProps.selectOption.props.children && prevProps.selectOption.props.id === nextProps.selectOption.props.id && prevProps.selectOption.props.renderBeforeLabel === nextProps.selectOption.props.renderBeforeLabel && prevProps.selectOption.props.renderAfterLabel === nextProps.selectOption.props.renderAfterLabel && prevProps.children === nextProps.children;
73
+ });
74
+ // This is needed so the propTypes in <Options> check are correct
75
+ MemoedOption.displayName = 'Item';
76
+
77
+ /**
78
+ ---
79
+ category: components
80
+ tags: autocomplete, typeahead, combobox, dropdown, search, form
81
+ ---
82
+ **/
83
+ let Select = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle), _dec(_class = _dec2(_class = (_Select = class Select extends Component {
84
+ constructor(...args) {
85
+ super(...args);
86
+ this.SCROLL_TOLERANCE = 0.5;
87
+ this.state = {
88
+ hasInputRef: false
89
+ };
90
+ this.ref = null;
91
+ this._input = null;
92
+ this._defaultId = this.props.deterministicId();
93
+ this._inputContainer = null;
94
+ this._listView = null;
95
+ // temporarily stores actionable options
96
+ this._optionIds = [];
97
+ // best guess for first calculation of list height
98
+ this._optionHeight = 36;
99
+ this.handleInputRef = node => {
100
+ var _this$props$inputRef, _this$props;
101
+ // ensures list is positioned with respect to input if list is open on mount
102
+ if (!this.state.hasInputRef) {
103
+ this.setState({
104
+ hasInputRef: true
105
+ });
106
+ }
107
+ this._input = node;
108
+ (_this$props$inputRef = (_this$props = this.props).inputRef) === null || _this$props$inputRef === void 0 ? void 0 : _this$props$inputRef.call(_this$props, node);
109
+ };
110
+ this.handleListRef = node => {
111
+ var _this$props$listRef, _this$props2;
112
+ (_this$props$listRef = (_this$props2 = this.props).listRef) === null || _this$props$listRef === void 0 ? void 0 : _this$props$listRef.call(_this$props2, node);
113
+
114
+ // store option height to calculate list maxHeight
115
+ if (node && node.querySelector('[role="option"]')) {
116
+ this._optionHeight = node.querySelector('[role="option"]').offsetHeight;
117
+ }
118
+ };
119
+ this.handleInputContainerRef = node => {
120
+ this._inputContainer = node;
121
+ };
122
+ }
123
+ componentDidMount() {
124
+ var _this$props$makeStyle, _this$props3;
125
+ (_this$props$makeStyle = (_this$props3 = this.props).makeStyles) === null || _this$props$makeStyle === void 0 ? void 0 : _this$props$makeStyle.call(_this$props3);
126
+ }
127
+ componentDidUpdate() {
128
+ var _this$props$makeStyle2, _this$props4;
129
+ (_this$props$makeStyle2 = (_this$props4 = this.props).makeStyles) === null || _this$props$makeStyle2 === void 0 ? void 0 : _this$props$makeStyle2.call(_this$props4);
130
+ if (this.props.scrollToHighlightedOption) {
131
+ // scroll option into view if needed
132
+ requestAnimationFrame(() => this.scrollToOption(this.highlightedOptionId));
133
+ }
134
+ }
135
+ focus() {
136
+ this._input && this._input.focus();
137
+ }
138
+ blur() {
139
+ this._input && this._input.blur();
140
+ }
141
+ get childrenArray() {
142
+ return Children.toArray(this.props.children);
143
+ }
144
+ getGroupChildrenArray(group) {
145
+ return Children.toArray(group.props.children);
146
+ }
147
+ get focused() {
148
+ return this._input ? isActiveElement(this._input) : false;
149
+ }
150
+ get id() {
151
+ return this.props.id || this._defaultId;
152
+ }
153
+ get width() {
154
+ return this._inputContainer ? this._inputContainer.offsetWidth : void 0;
155
+ }
156
+ get interaction() {
157
+ return getInteraction({
158
+ props: this.props
159
+ });
160
+ }
161
+ get highlightedOptionId() {
162
+ let highlightedOptionId;
163
+ this.childrenArray.forEach(child => {
164
+ if (matchComponentTypes(child, [Group])) {
165
+ // group found
166
+ this.getGroupChildrenArray(child).forEach(option => {
167
+ // check options in group
168
+ if (option.props.isHighlighted) {
169
+ highlightedOptionId = option.props.id;
170
+ }
171
+ });
172
+ } else {
173
+ // ungrouped option found
174
+ if (child.props.isHighlighted) {
175
+ highlightedOptionId = child.props.id;
176
+ }
177
+ }
178
+ });
179
+ return highlightedOptionId;
180
+ }
181
+ get selectedOptionId() {
182
+ const selectedOptionId = [];
183
+ this.childrenArray.forEach(child => {
184
+ if (matchComponentTypes(child, [Group])) {
185
+ // group found
186
+ this.getGroupChildrenArray(child).forEach(option => {
187
+ // check options in group
188
+ if (option.props.isSelected) {
189
+ selectedOptionId.push(option.props.id);
190
+ }
191
+ });
192
+ } else {
193
+ // ungrouped option found
194
+ if (child.props.isSelected) {
195
+ selectedOptionId.push(child.props.id);
196
+ }
197
+ }
198
+ });
199
+ if (selectedOptionId.length === 1) {
200
+ return selectedOptionId[0];
201
+ }
202
+ if (selectedOptionId.length === 0) {
203
+ return void 0;
204
+ }
205
+ return selectedOptionId;
206
+ }
207
+ scrollToOption(id) {
208
+ if (!this._listView || !id) return;
209
+ const option = this._listView.querySelector(`[id="${CSS.escape(id)}"]`);
210
+ if (!option) return;
211
+ const listItem = option.parentNode;
212
+ const parentTop = getBoundingClientRect(this._listView).top;
213
+ const elemTop = getBoundingClientRect(listItem).top;
214
+ const parentBottom = parentTop + this._listView.clientHeight;
215
+ const elemBottom = elemTop + (listItem ? listItem.clientHeight : 0);
216
+ if (elemBottom > parentBottom) {
217
+ this._listView.scrollTop += elemBottom - parentBottom;
218
+ } else if (elemTop < parentTop) {
219
+ this._listView.scrollTop -= parentTop - elemTop;
220
+ }
221
+ }
222
+ highlightOption(event, id) {
223
+ const onRequestHighlightOption = this.props.onRequestHighlightOption;
224
+ if (id) {
225
+ onRequestHighlightOption === null || onRequestHighlightOption === void 0 ? void 0 : onRequestHighlightOption(event, {
226
+ id
227
+ });
228
+ }
229
+ }
230
+ getEventHandlers() {
231
+ const _this$props5 = this.props,
232
+ isShowingOptions = _this$props5.isShowingOptions,
233
+ onRequestShowOptions = _this$props5.onRequestShowOptions,
234
+ onRequestHideOptions = _this$props5.onRequestHideOptions,
235
+ onRequestSelectOption = _this$props5.onRequestSelectOption;
236
+ return this.interaction === 'enabled' ? {
237
+ onRequestShowOptions: event => {
238
+ onRequestShowOptions === null || onRequestShowOptions === void 0 ? void 0 : onRequestShowOptions(event);
239
+ const selectedOptionId = this.selectedOptionId;
240
+ if (selectedOptionId && !Array.isArray(selectedOptionId)) {
241
+ // highlight selected option on show
242
+ this.highlightOption(event, selectedOptionId);
243
+ }
244
+ },
245
+ onRequestHideOptions: event => {
246
+ onRequestHideOptions === null || onRequestHideOptions === void 0 ? void 0 : onRequestHideOptions(event);
247
+ },
248
+ onRequestHighlightOption: (event, {
249
+ id,
250
+ direction
251
+ }) => {
252
+ if (!isShowingOptions) return;
253
+ const highlightedOptionId = this.highlightedOptionId;
254
+ // if id exists, use that
255
+ let highlightId = this._optionIds.indexOf(id) > -1 ? id : void 0;
256
+ if (!highlightId) {
257
+ if (!highlightedOptionId) {
258
+ // nothing highlighted yet, highlight first option
259
+ highlightId = this._optionIds[0];
260
+ } else {
261
+ // find next id based on direction
262
+ const index = this._optionIds.indexOf(highlightedOptionId);
263
+ highlightId = index > -1 ? this._optionIds[index + direction] : void 0;
264
+ }
265
+ }
266
+ if (highlightId) {
267
+ // only highlight if id exists as a valid option
268
+ this.highlightOption(event, highlightId);
269
+ }
270
+ },
271
+ onRequestHighlightFirstOption: event => {
272
+ this.highlightOption(event, this._optionIds[0]);
273
+ },
274
+ onRequestHighlightLastOption: event => {
275
+ this.highlightOption(event, this._optionIds[this._optionIds.length - 1]);
276
+ },
277
+ onRequestSelectOption: (event, {
278
+ id
279
+ }) => {
280
+ if (id && this._optionIds.indexOf(id) !== -1) {
281
+ // only select if id exists as a valid option
282
+ onRequestSelectOption === null || onRequestSelectOption === void 0 ? void 0 : onRequestSelectOption(event, {
283
+ id
284
+ });
285
+ }
286
+ }
287
+ } : {};
288
+ }
289
+ renderOption(option, data) {
290
+ const getOptionProps = data.getOptionProps,
291
+ getDisabledOptionProps = data.getDisabledOptionProps;
292
+ const _option$props = option.props,
293
+ id = _option$props.id,
294
+ isDisabled = _option$props.isDisabled,
295
+ isHighlighted = _option$props.isHighlighted,
296
+ isSelected = _option$props.isSelected,
297
+ renderBeforeLabel = _option$props.renderBeforeLabel,
298
+ renderAfterLabel = _option$props.renderAfterLabel,
299
+ children = _option$props.children;
300
+ const getRenderOptionLabel = renderOptionLabel => {
301
+ var _renderOptionLabel$pr;
302
+ return typeof renderOptionLabel === 'function' && !(renderOptionLabel !== null && renderOptionLabel !== void 0 && (_renderOptionLabel$pr = renderOptionLabel.prototype) !== null && _renderOptionLabel$pr !== void 0 && _renderOptionLabel$pr.isReactComponent) ? renderOptionLabel.bind(null, {
303
+ id,
304
+ isDisabled,
305
+ isSelected,
306
+ isHighlighted,
307
+ children
308
+ }) : renderOptionLabel;
309
+ };
310
+ const _this$props6 = this.props,
311
+ isOptionContentAppliedToInput = _this$props6.isOptionContentAppliedToInput,
312
+ _this$props6$size = _this$props6.size,
313
+ size = _this$props6$size === void 0 ? 'medium' : _this$props6$size;
314
+ const iconSize = selectSizeToIconSize[size];
315
+ const checkIcon = isSelected && !isOptionContentAppliedToInput ? _jsx(CheckInstUIIcon, {
316
+ inline: false,
317
+ size: iconSize,
318
+ color: "inverseColor"
319
+ }) : null;
320
+ let optionProps = {
321
+ // passthrough props
322
+ ...omitProps(option.props, [...Option.allowedProps, ...Options.Item.allowedProps]),
323
+ // props from selectable
324
+ ...getOptionProps({
325
+ id
326
+ }),
327
+ // Options.Item props
328
+ renderBeforeLabel: getRenderOptionLabel(renderBeforeLabel),
329
+ renderAfterLabel: checkIcon !== null && checkIcon !== void 0 ? checkIcon : getRenderOptionLabel(renderAfterLabel)
330
+ };
331
+ // should option be treated as highlighted or selected
332
+ if (isSelected && isHighlighted) {
333
+ optionProps.variant = 'selected-highlighted';
334
+ optionProps.isSelected = true;
335
+ } else if (isSelected) {
336
+ optionProps.variant = 'selected';
337
+ optionProps.isSelected = true;
338
+ } else if (isHighlighted) {
339
+ optionProps.variant = 'highlighted';
340
+ }
341
+ // should option be treated as disabled
342
+ if (isDisabled) {
343
+ optionProps.variant = 'disabled';
344
+ optionProps = {
345
+ ...optionProps,
346
+ ...getDisabledOptionProps()
347
+ };
348
+ } else {
349
+ // track as valid option if not disabled
350
+ this._optionIds.push(id);
351
+ }
352
+ return _jsx(MemoedOption, {
353
+ optionsItemProps: optionProps,
354
+ selectOption: option,
355
+ children: children
356
+ });
357
+ }
358
+ renderGroup(group, data) {
359
+ const getOptionProps = data.getOptionProps,
360
+ getDisabledOptionProps = data.getDisabledOptionProps,
361
+ isFirstChild = data.isFirstChild,
362
+ isLastChild = data.isLastChild,
363
+ afterGroup = data.afterGroup;
364
+ const _group$props = group.props,
365
+ id = _group$props.id,
366
+ renderLabel = _group$props.renderLabel,
367
+ children = _group$props.children,
368
+ rest = _objectWithoutProperties(_group$props, _excluded);
369
+ const groupChildren = [];
370
+ // add a separator above
371
+ if (!isFirstChild && !afterGroup) {
372
+ groupChildren.push(_Options$Separator || (_Options$Separator = _jsx(Options.Separator, {})));
373
+ }
374
+ // create a sublist as a group
375
+ // a wrapping listitem will be created by Options
376
+ groupChildren.push(_jsx(Options, {
377
+ id: id,
378
+ as: "ul",
379
+ role: "group",
380
+ renderLabel: renderLabel,
381
+ ...omitProps(rest, [...Options.allowedProps, ...Group.allowedProps]),
382
+ children: Children.map(children, child => {
383
+ return this.renderOption(child, {
384
+ getOptionProps,
385
+ getDisabledOptionProps
386
+ });
387
+ })
388
+ }));
389
+ // add a separator below
390
+ if (!isLastChild) {
391
+ groupChildren.push(_Options$Separator2 || (_Options$Separator2 = _jsx(Options.Separator, {})));
392
+ }
393
+ return groupChildren;
394
+ }
395
+ renderList(data) {
396
+ const getListProps = data.getListProps,
397
+ getOptionProps = data.getOptionProps,
398
+ getDisabledOptionProps = data.getDisabledOptionProps;
399
+ const _this$props7 = this.props,
400
+ isShowingOptions = _this$props7.isShowingOptions,
401
+ optionsMaxWidth = _this$props7.optionsMaxWidth,
402
+ optionsMaxHeight = _this$props7.optionsMaxHeight,
403
+ visibleOptionsCount = _this$props7.visibleOptionsCount,
404
+ children = _this$props7.children;
405
+ let lastWasGroup = false;
406
+ const viewProps = isShowingOptions ? {
407
+ display: 'block',
408
+ overflowY: 'auto',
409
+ maxHeight: optionsMaxHeight || this._optionHeight * visibleOptionsCount - (
410
+ // in Chrome, we need to prevent scrolling when the bottom area of last item is hovered
411
+ utils.isChromium() ? this.SCROLL_TOLERANCE : 0),
412
+ maxWidth: optionsMaxWidth || this.width,
413
+ background: 'primary',
414
+ elementRef: node => this._listView = node,
415
+ borderRadius: 'inherit'
416
+ } : {
417
+ maxHeight: 0
418
+ };
419
+ return _jsx(View, {
420
+ ...viewProps,
421
+ children: _jsx(Options, {
422
+ ...getListProps({
423
+ as: 'ul',
424
+ elementRef: this.handleListRef
425
+ }),
426
+ children: isShowingOptions ? Children.map(children, (child, index) => {
427
+ if (!child || !matchComponentTypes(child, [Group, Option])) {
428
+ return; // ignore invalid children
429
+ }
430
+ if (matchComponentTypes(child, [Option])) {
431
+ lastWasGroup = false;
432
+ return this.renderOption(child, {
433
+ getOptionProps,
434
+ getDisabledOptionProps
435
+ });
436
+ }
437
+ if (matchComponentTypes(child, [Group])) {
438
+ const afterGroup = lastWasGroup;
439
+ lastWasGroup = true;
440
+ return this.renderGroup(child, {
441
+ getOptionProps,
442
+ getDisabledOptionProps,
443
+ // for rendering separators appropriately
444
+ isFirstChild: index === 0,
445
+ isLastChild: index === Children.count(children) - 1,
446
+ afterGroup
447
+ });
448
+ }
449
+ return;
450
+ }) : null
451
+ })
452
+ });
453
+ }
454
+ renderIcon() {
455
+ const _this$props8 = this.props,
456
+ isShowingOptions = _this$props8.isShowingOptions,
457
+ _this$props8$size = _this$props8.size,
458
+ size = _this$props8$size === void 0 ? 'medium' : _this$props8$size;
459
+ const iconSize = selectSizeToIconSize[size];
460
+ return _jsx("span", {
461
+ children: isShowingOptions ? _jsx(ChevronUpInstUIIcon, {
462
+ inline: false,
463
+ size: iconSize,
464
+ color: "baseColor"
465
+ }) : _jsx(ChevronDownInstUIIcon, {
466
+ inline: false,
467
+ size: iconSize,
468
+ color: "baseColor"
469
+ })
470
+ });
471
+ }
472
+ renderContentBeforeOrAfterInput(position) {
473
+ for (const child of this.childrenArray) {
474
+ if (matchComponentTypes(child, [Group])) {
475
+ // Group found
476
+ const options = this.getGroupChildrenArray(child);
477
+ for (const option of options) {
478
+ if (option.props.isSelected) {
479
+ return position === 'before' ? option.props.renderBeforeLabel : option.props.renderAfterLabel ? option.props.renderAfterLabel : this.renderIcon();
480
+ }
481
+ }
482
+ } else {
483
+ // Ungrouped option found
484
+ if (child.props.isSelected) {
485
+ return position === 'before' ? child.props.renderBeforeLabel : child.props.renderAfterLabel ? child.props.renderAfterLabel : this.renderIcon();
486
+ }
487
+ }
488
+ }
489
+ // if no option with isSelected is found
490
+ if (position === 'after') {
491
+ return this.renderIcon();
492
+ }
493
+ return void 0;
494
+ }
495
+ handleInputContentRender(renderLabelInput, inputValue, isOptionContentAppliedToInput, position, defaultReturn) {
496
+ const isInputValueEmpty = !inputValue || inputValue === '';
497
+ if (renderLabelInput && isOptionContentAppliedToInput) {
498
+ if (!isInputValueEmpty) {
499
+ return this.renderContentBeforeOrAfterInput(position);
500
+ }
501
+ return renderLabelInput;
502
+ }
503
+ if (isOptionContentAppliedToInput) {
504
+ if (isInputValueEmpty) {
505
+ return defaultReturn;
506
+ }
507
+ return this.renderContentBeforeOrAfterInput(position);
508
+ }
509
+ if (renderLabelInput) {
510
+ return renderLabelInput;
511
+ }
512
+ return defaultReturn;
513
+ }
514
+ handleRenderBeforeInput() {
515
+ const _this$props9 = this.props,
516
+ renderBeforeInput = _this$props9.renderBeforeInput,
517
+ inputValue = _this$props9.inputValue,
518
+ isOptionContentAppliedToInput = _this$props9.isOptionContentAppliedToInput;
519
+ return this.handleInputContentRender(renderBeforeInput, inputValue, isOptionContentAppliedToInput, 'before', null // default for before
520
+ );
521
+ }
522
+ handleRenderAfterInput() {
523
+ const _this$props0 = this.props,
524
+ renderAfterInput = _this$props0.renderAfterInput,
525
+ inputValue = _this$props0.inputValue,
526
+ isOptionContentAppliedToInput = _this$props0.isOptionContentAppliedToInput;
527
+ return this.handleInputContentRender(renderAfterInput, inputValue, isOptionContentAppliedToInput, 'after', this.renderIcon() // default for after
528
+ );
529
+ }
530
+ renderInput(data) {
531
+ const getInputProps = data.getInputProps,
532
+ getTriggerProps = data.getTriggerProps;
533
+ const _this$props1 = this.props,
534
+ renderLabel = _this$props1.renderLabel,
535
+ inputValue = _this$props1.inputValue,
536
+ placeholder = _this$props1.placeholder,
537
+ isRequired = _this$props1.isRequired,
538
+ shouldNotWrap = _this$props1.shouldNotWrap,
539
+ size = _this$props1.size,
540
+ isInline = _this$props1.isInline,
541
+ width = _this$props1.width,
542
+ htmlSize = _this$props1.htmlSize,
543
+ messages = _this$props1.messages,
544
+ renderBeforeInput = _this$props1.renderBeforeInput,
545
+ renderAfterInput = _this$props1.renderAfterInput,
546
+ onFocus = _this$props1.onFocus,
547
+ onBlur = _this$props1.onBlur,
548
+ onInputChange = _this$props1.onInputChange,
549
+ onRequestHideOptions = _this$props1.onRequestHideOptions,
550
+ layout = _this$props1.layout,
551
+ rest = _objectWithoutProperties(_this$props1, _excluded2);
552
+ const interaction = this.interaction;
553
+ const passthroughProps = omitProps(rest, Select.allowedProps);
554
+ const _getTriggerProps = getTriggerProps({
555
+ ...passthroughProps
556
+ }),
557
+ ref = _getTriggerProps.ref,
558
+ triggerProps = _objectWithoutProperties(_getTriggerProps, _excluded3);
559
+ const isEditable = typeof onInputChange !== 'undefined';
560
+
561
+ // props to ensure screen readers treat uneditable selects as accessible
562
+ // popup buttons rather than comboboxes.
563
+ const overrideProps = !isEditable ? {
564
+ // We need role="combobox" for the 'open list' button shortcut to work
565
+ // with desktop screenreaders.
566
+ // But desktop Safari with Voiceover does not support proper combobox
567
+ // handling, a 'button' role is set as a workaround.
568
+ // See https://bugs.webkit.org/show_bug.cgi?id=236881
569
+ // Also on iOS Chrome with role='combobox' it announces unnecessarily
570
+ // that its 'read-only' and that this is a 'textfield', see INSTUI-4500
571
+ role: utils.isSafari() || utils.isAndroidOrIOS() || interaction === 'disabled' && utils.isChromium() ? 'button' : 'combobox',
572
+ title: inputValue,
573
+ 'aria-autocomplete': void 0,
574
+ 'aria-readonly': true
575
+ } : interaction === 'disabled' && utils.isChromium() ? {
576
+ role: 'button'
577
+ } : {};
578
+
579
+ // backdoor to autocomplete attr to work around chrome autofill issues
580
+ if (passthroughProps['autoComplete']) {
581
+ overrideProps.autoComplete = passthroughProps['autoComplete'];
582
+ }
583
+ const inputProps = {
584
+ id: this.id,
585
+ renderLabel,
586
+ placeholder,
587
+ size,
588
+ width,
589
+ htmlSize,
590
+ messages,
591
+ value: inputValue,
592
+ inputRef: utils.createChainedFunction(ref, this.handleInputRef),
593
+ inputContainerRef: this.handleInputContainerRef,
594
+ interaction: interaction === 'enabled' && !isEditable ? 'readonly' // prevent keyboard cursor
595
+ : interaction,
596
+ isRequired,
597
+ shouldNotWrap,
598
+ layout,
599
+ display: isInline ? 'inline-block' : 'block',
600
+ renderBeforeInput: this.handleRenderBeforeInput(),
601
+ // On iOS VoiceOver, if there is a custom element instead of the changing up and down arrow button
602
+ // the listbox closes on a swipe, so a DOM change is enforced by the key change
603
+ // that seems to inform VoiceOver to behave the correct way
604
+ renderAfterInput: utils.isAndroidOrIOS() && renderAfterInput !== void 0 ? _jsx("span", {
605
+ children: this.handleRenderAfterInput()
606
+ }, this.props.isShowingOptions ? 'open' : 'closed') : this.handleRenderAfterInput(),
607
+ // If `inputValue` is provided, we need to pass a default onChange handler,
608
+ // because TextInput `value` is a controlled prop,
609
+ // and onChange is not required for Select
610
+ // (before it was handled by TextInput's defaultProp)
611
+ onChange: typeof onInputChange === 'function' ? onInputChange : inputValue ? () => {} : void 0,
612
+ onFocus,
613
+ onBlur: utils.createChainedFunction(onBlur, onRequestHideOptions),
614
+ ...overrideProps
615
+ };
616
+ // suppressHydrationWarning is needed because `role` depends on the browser type
617
+ return _jsx(TextInput, {
618
+ ...triggerProps,
619
+ ...getInputProps(inputProps),
620
+ suppressHydrationWarning: true,
621
+ ...(interaction === 'enabled' && !isEditable && {
622
+ themeOverride: componentTheme => ({
623
+ backgroundReadonlyColor: componentTheme.backgroundColor
624
+ })
625
+ })
626
+ });
627
+ }
628
+ render() {
629
+ const _this$props10 = this.props,
630
+ constrain = _this$props10.constrain,
631
+ placement = _this$props10.placement,
632
+ mountNode = _this$props10.mountNode,
633
+ assistiveText = _this$props10.assistiveText,
634
+ isShowingOptions = _this$props10.isShowingOptions,
635
+ styles = _this$props10.styles;
636
+ // clear temporary option store
637
+ this._optionIds = [];
638
+ const highlightedOptionId = this.highlightedOptionId;
639
+ const selectedOptionId = this.selectedOptionId;
640
+ return _jsx(Selectable, {
641
+ highlightedOptionId: highlightedOptionId,
642
+ isShowingOptions: isShowingOptions,
643
+ selectedOptionId: selectedOptionId,
644
+ ...this.getEventHandlers(),
645
+ children: ({
646
+ getRootProps,
647
+ getInputProps,
648
+ getTriggerProps,
649
+ getListProps,
650
+ getOptionProps,
651
+ getDisabledOptionProps,
652
+ getDescriptionProps
653
+ }) => _jsxs("span", {
654
+ ...getRootProps(),
655
+ ref: el => {
656
+ this.ref = el;
657
+ },
658
+ "data-cid": combineDataCid('Select', this.props),
659
+ children: [this.renderInput({
660
+ getInputProps,
661
+ getTriggerProps
662
+ }), _jsx("span", {
663
+ ...getDescriptionProps(),
664
+ css: styles === null || styles === void 0 ? void 0 : styles.assistiveText,
665
+ children: assistiveText
666
+ }), _jsx(Popover, {
667
+ constrain: constrain,
668
+ placement: placement
669
+ // On iOS VoiceOver, the Popover is mounted right after the input
670
+ // in order to be able to navigate through the list items with a swipe.
671
+ // The swipe would result in closing the listbox if mounted elsewhere.
672
+ ,
673
+ mountNode: mountNode !== void 0 ? mountNode : utils.isAndroidOrIOS() ? this.ref : void 0,
674
+ positionTarget: this._inputContainer,
675
+ isShowingContent: isShowingOptions,
676
+ shouldReturnFocus: false,
677
+ withArrow: false,
678
+ borderWidth: styles === null || styles === void 0 ? void 0 : styles.popoverBorderWidth,
679
+ children: this.renderList({
680
+ getListProps,
681
+ getOptionProps,
682
+ getDisabledOptionProps
683
+ })
684
+ })]
685
+ })
686
+ });
687
+ }
688
+ }, _Select.displayName = "Select", _Select.componentId = 'Select', _Select.allowedProps = allowedProps, _Select.defaultProps = {
689
+ inputValue: '',
690
+ isShowingOptions: false,
691
+ size: 'medium',
692
+ // Leave interaction default undefined so that `disabled` and `readOnly` can also be supplied
693
+ interaction: void 0,
694
+ isRequired: false,
695
+ isInline: false,
696
+ visibleOptionsCount: 8,
697
+ placement: 'bottom stretch',
698
+ constrain: 'window',
699
+ shouldNotWrap: false,
700
+ scrollToHighlightedOption: true,
701
+ isOptionContentAppliedToInput: false
702
+ }, _Select.Option = Option, _Select.Group = Group, _Select)) || _class) || _class);
703
+ export default Select;
704
+ export { Select };