@khanacademy/wonder-blocks-dropdown 2.6.8 → 2.7.0

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.
package/dist/es/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import _extends from '@babel/runtime/helpers/extends';
2
2
  import * as React from 'react';
3
- import { StyleSheet, css } from 'aphrodite';
3
+ import { StyleSheet } from 'aphrodite';
4
4
  import { Link } from 'react-router-dom';
5
5
  import { __RouterContext } from 'react-router';
6
6
  import Color, { mix, fade, SemanticColor } from '@khanacademy/wonder-blocks-color';
7
7
  import Spacing from '@khanacademy/wonder-blocks-spacing';
8
- import { LabelMedium, styles as styles$a, LabelLarge } from '@khanacademy/wonder-blocks-typography';
8
+ import { LabelMedium, LabelLarge } from '@khanacademy/wonder-blocks-typography';
9
9
  import { getClickableBehavior, isClientSideUrl, ClickableBehavior } from '@khanacademy/wonder-blocks-clickable';
10
10
  import { addStyle, View } from '@khanacademy/wonder-blocks-core';
11
11
  import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/objectWithoutPropertiesLoose';
@@ -13,7 +13,7 @@ import Icon, { icons } from '@khanacademy/wonder-blocks-icon';
13
13
  import ReactDOM from 'react-dom';
14
14
  import { VariableSizeList } from 'react-window';
15
15
  import { withActionScheduler } from '@khanacademy/wonder-blocks-timing';
16
- import IconButton from '@khanacademy/wonder-blocks-icon-button';
16
+ import SearchField from '@khanacademy/wonder-blocks-search-field';
17
17
  import { Popper } from 'react-popper';
18
18
  import { maybeGetPortalMountedModalHostElement } from '@khanacademy/wonder-blocks-modal';
19
19
  import { Strut } from '@khanacademy/wonder-blocks-layout';
@@ -29,22 +29,18 @@ const keyCodes = {
29
29
  const selectDropdownStyle = {
30
30
  marginTop: Spacing.xSmall_8,
31
31
  marginBottom: Spacing.xSmall_8
32
- }; // Filterable dropdown has minimum dimensions requested from Design.
33
- // Note that these can be overridden by the provided style if needed.
34
-
32
+ };
35
33
  const filterableDropdownStyle = {
36
- minHeight: 100,
37
- maxHeight: 384
34
+ minHeight: 100
38
35
  };
39
36
  const searchInputStyle = {
40
37
  margin: Spacing.xSmall_8,
41
38
  marginTop: Spacing.xxxSmall_4
42
- }; // The default item height
43
-
39
+ };
44
40
  const DROPDOWN_ITEM_HEIGHT = 40;
41
+ const MAX_VISIBLE_ITEMS = 9;
45
42
  const SEPARATOR_ITEM_HEIGHT = 9;
46
- const SEARCH_ITEM_HEIGHT = DROPDOWN_ITEM_HEIGHT + searchInputStyle.margin + searchInputStyle.marginTop; // The default labels that will be used by different components
47
-
43
+ const SEARCH_ITEM_HEIGHT = DROPDOWN_ITEM_HEIGHT + searchInputStyle.margin + searchInputStyle.marginTop;
48
44
  const defaultLabels = {
49
45
  clearSearch: "Clear search",
50
46
  filter: "Filter",
@@ -65,12 +61,6 @@ const {
65
61
  const StyledAnchor = addStyle("a");
66
62
  const StyledButton$2 = addStyle("button");
67
63
  const StyledLink = addStyle(Link);
68
- /**
69
- * The action item trigger actions, such as navigating to a different page or
70
- * opening a modal. Supply the href and/or onClick props. Used as a child of
71
- * ActionMenu.
72
- */
73
-
74
64
  class ActionItem extends React.Component {
75
65
  static isClassOf(instance) {
76
66
  return instance && instance.type && instance.type.__IS_ACTION_ITEM__;
@@ -91,7 +81,7 @@ class ActionItem extends React.Component {
91
81
  testId
92
82
  } = this.props;
93
83
  const ClickableBehavior = getClickableBehavior(href, skipClientNav, router);
94
- return /*#__PURE__*/React.createElement(ClickableBehavior, {
84
+ return React.createElement(ClickableBehavior, {
95
85
  disabled: disabled,
96
86
  onClick: onClick,
97
87
  href: href,
@@ -103,8 +93,7 @@ class ActionItem extends React.Component {
103
93
  hovered,
104
94
  focused
105
95
  } = state;
106
- const defaultStyle = [styles$9.shared, disabled && styles$9.disabled, !disabled && (pressed ? styles$9.active : (hovered || focused) && styles$9.focus), // pass optional styles from react-window (if applies)
107
- style];
96
+ const defaultStyle = [styles$8.shared, disabled && styles$8.disabled, !disabled && (pressed ? styles$8.active : (hovered || focused) && styles$8.focus), style];
108
97
 
109
98
  const props = _extends({
110
99
  "data-test-id": testId,
@@ -113,20 +102,20 @@ class ActionItem extends React.Component {
113
102
  style: [defaultStyle]
114
103
  }, childrenProps);
115
104
 
116
- const children = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(LabelMedium, {
105
+ const children = React.createElement(React.Fragment, null, React.createElement(LabelMedium, {
117
106
  lang: lang,
118
- style: [indent && styles$9.indent, styles$9.label]
107
+ style: [indent && styles$8.indent, styles$8.label]
119
108
  }, label));
120
109
 
121
110
  if (href && !disabled) {
122
- return router && !skipClientNav && isClientSideUrl(href) ? /*#__PURE__*/React.createElement(StyledLink, _extends({}, props, {
111
+ return router && !skipClientNav && isClientSideUrl(href) ? React.createElement(StyledLink, _extends({}, props, {
123
112
  to: href
124
- }), children) : /*#__PURE__*/React.createElement(StyledAnchor, _extends({}, props, {
113
+ }), children) : React.createElement(StyledAnchor, _extends({}, props, {
125
114
  href: href,
126
115
  target: target
127
116
  }), children);
128
117
  } else {
129
- return /*#__PURE__*/React.createElement(StyledButton$2, _extends({
118
+ return React.createElement(StyledButton$2, _extends({
130
119
  type: "button"
131
120
  }, props, {
132
121
  disabled: disabled
@@ -136,7 +125,7 @@ class ActionItem extends React.Component {
136
125
  }
137
126
 
138
127
  render() {
139
- return /*#__PURE__*/React.createElement(__RouterContext.Consumer, null, router => this.renderClickableBehavior(router));
128
+ return React.createElement(__RouterContext.Consumer, null, router => this.renderClickableBehavior(router));
140
129
  }
141
130
 
142
131
  }
@@ -146,7 +135,7 @@ ActionItem.defaultProps = {
146
135
  role: "menuitem"
147
136
  };
148
137
  ActionItem.__IS_ACTION_ITEM__ = true;
149
- const styles$9 = StyleSheet.create({
138
+ const styles$8 = StyleSheet.create({
150
139
  shared: {
151
140
  background: white$4,
152
141
  color: offBlack$3,
@@ -160,8 +149,6 @@ const styles$9 = StyleSheet.create({
160
149
  minHeight: DROPDOWN_ITEM_HEIGHT,
161
150
  paddingLeft: Spacing.medium_16,
162
151
  paddingRight: Spacing.medium_16,
163
- // This removes the 300ms click delay on mobile browsers by indicating that
164
- // "double-tap to zoom" shouldn't be used on this element.
165
152
  touchAction: "manipulation"
166
153
  },
167
154
  label: {
@@ -171,17 +158,14 @@ const styles$9 = StyleSheet.create({
171
158
  indent: {
172
159
  marginLeft: Spacing.medium_16
173
160
  },
174
- // hover and focus states
175
161
  focus: {
176
162
  color: white$4,
177
163
  background: blue$3
178
164
  },
179
- // active and pressed states
180
165
  active: {
181
166
  color: mix(fade(blue$3, 0.32), white$4),
182
167
  background: mix(offBlack32$4, blue$3)
183
168
  },
184
- // disabled state
185
169
  disabled: {
186
170
  color: offBlack32$4,
187
171
  cursor: "default"
@@ -193,14 +177,6 @@ const {
193
177
  offBlack32: offBlack32$3,
194
178
  white: white$3
195
179
  } = Color;
196
- /**
197
- * Props describing the state of the OptionItem, shared by the checkbox
198
- * component,
199
- */
200
-
201
- /**
202
- * The check component used by OptionItem.
203
- */
204
180
  function Check(props) {
205
181
  const {
206
182
  disabled,
@@ -209,16 +185,15 @@ function Check(props) {
209
185
  hovered,
210
186
  focused
211
187
  } = props;
212
- return /*#__PURE__*/React.createElement(Icon, {
188
+ return React.createElement(Icon, {
213
189
  icon: icons.check,
214
190
  size: "small",
215
191
  color: disabled ? offBlack32$3 : pressed || hovered || focused ? white$3 : offBlack$2,
216
- style: [styles$8.bounds, !selected && styles$8.hide]
192
+ style: [styles$7.bounds, !selected && styles$7.hide]
217
193
  });
218
194
  }
219
- const styles$8 = StyleSheet.create({
195
+ const styles$7 = StyleSheet.create({
220
196
  bounds: {
221
- // Semantically, this are the constants for a small-sized icon
222
197
  minHeight: 16,
223
198
  minWidth: 16
224
199
  },
@@ -227,10 +202,6 @@ const styles$8 = StyleSheet.create({
227
202
  }
228
203
  });
229
204
 
230
- // NOTE(sophie): This is a smaller check specifically for use in checkboxes.
231
- // Please don't copy it automatically and check with designers before using.
232
- // If the intended icon is a check without a checkbox, you should be using
233
- // icons.check from the Wonder Blocks Icon package.
234
205
  const checkboxCheck = {
235
206
  small: "M11.263 4.324a1 1 0 1 1 1.474 1.352l-5.5 6a1 1 0 0 1-1.505-.036l-2.5-3a1 1 0 1 1 1.536-1.28L6.536 9.48l4.727-5.157z"
236
207
  };
@@ -242,14 +213,6 @@ const {
242
213
  offBlack50,
243
214
  offWhite
244
215
  } = Color;
245
- /**
246
- * Props describing the state of the OptionItem, shared by the check
247
- * component,
248
- */
249
-
250
- /**
251
- * The checkbox component used by OptionItem.
252
- */
253
216
  function Checkbox(props) {
254
217
  const {
255
218
  disabled,
@@ -262,20 +225,19 @@ function Checkbox(props) {
262
225
  const clickInteraction = pressed || hovered || focused;
263
226
  const bgColor = disabled ? offWhite : selected && !clickInteraction ? blue$2 : white$2;
264
227
  const checkColor = disabled ? offBlack32$2 : clickInteraction ? pressed ? activeBlue : blue$2 : white$2;
265
- return /*#__PURE__*/React.createElement(View, {
266
- style: [styles$7.checkbox, (clickInteraction || selected && !disabled) && styles$7.noBorder, disabled && styles$7.disabledCheckbox, {
228
+ return React.createElement(View, {
229
+ style: [styles$6.checkbox, (clickInteraction || selected && !disabled) && styles$6.noBorder, disabled && styles$6.disabledCheckbox, {
267
230
  backgroundColor: bgColor
268
231
  }]
269
- }, selected && /*#__PURE__*/React.createElement(Icon, {
232
+ }, selected && React.createElement(Icon, {
270
233
  icon: checkboxCheck,
271
234
  size: "small",
272
235
  color: checkColor,
273
- style: [disabled && selected && styles$7.disabledCheckFormatting]
236
+ style: [disabled && selected && styles$6.disabledCheckFormatting]
274
237
  }));
275
238
  }
276
- const styles$7 = StyleSheet.create({
239
+ const styles$6 = StyleSheet.create({
277
240
  checkbox: {
278
- // Semantically, this are the constants for a small-sized icon
279
241
  minHeight: 16,
280
242
  minWidth: 16,
281
243
  borderRadius: 3,
@@ -290,8 +252,6 @@ const styles$7 = StyleSheet.create({
290
252
  borderColor: offBlack16$1,
291
253
  backgroundColor: offWhite
292
254
  },
293
- // The border of 1px on the selected, disabled checkbox pushes the check out
294
- // of place. Move it back.
295
255
  disabledCheckFormatting: {
296
256
  position: "absolute",
297
257
  top: -1,
@@ -300,12 +260,6 @@ const styles$7 = StyleSheet.create({
300
260
  });
301
261
 
302
262
  const _excluded$5 = ["disabled", "label", "role", "selected", "testId", "style", "value", "onClick", "onToggle", "variant"];
303
-
304
- /**
305
- * For option items that can be selected in a dropdown, selection denoted either
306
- * with a check ✔️ or a checkbox ☑️. Use as children in SingleSelect or
307
- * MultiSelect.
308
- */
309
263
  class OptionItem extends React.Component {
310
264
  constructor(...args) {
311
265
  super(...args);
@@ -350,7 +304,7 @@ class OptionItem extends React.Component {
350
304
 
351
305
  const ClickableBehavior = getClickableBehavior();
352
306
  const CheckComponent = this.getCheckComponent();
353
- return /*#__PURE__*/React.createElement(ClickableBehavior, {
307
+ return React.createElement(ClickableBehavior, {
354
308
  disabled: disabled,
355
309
  onClick: this.handleClick,
356
310
  role: role
@@ -360,21 +314,20 @@ class OptionItem extends React.Component {
360
314
  hovered,
361
315
  focused
362
316
  } = state;
363
- const defaultStyle = [styles$6.itemContainer, pressed ? styles$6.active : (hovered || focused) && styles$6.focus, disabled && styles$6.disabled, // pass optional styles from react-window (if applies)
364
- style];
365
- return /*#__PURE__*/React.createElement(View, _extends({}, sharedProps, {
317
+ const defaultStyle = [styles$5.itemContainer, pressed ? styles$5.active : (hovered || focused) && styles$5.focus, disabled && styles$5.disabled, style];
318
+ return React.createElement(View, _extends({}, sharedProps, {
366
319
  testId: testId,
367
320
  style: defaultStyle,
368
321
  "aria-selected": selected ? "true" : "false",
369
322
  role: role
370
- }, childrenProps), /*#__PURE__*/React.createElement(CheckComponent, {
323
+ }, childrenProps), React.createElement(CheckComponent, {
371
324
  disabled: disabled,
372
325
  selected: selected,
373
326
  pressed: pressed,
374
327
  hovered: hovered,
375
328
  focused: focused
376
- }), /*#__PURE__*/React.createElement(LabelMedium, {
377
- style: styles$6.label
329
+ }), React.createElement(LabelMedium, {
330
+ style: styles$5.label
378
331
  }, label));
379
332
  });
380
333
  }
@@ -393,7 +346,7 @@ const {
393
346
  offBlack: offBlack$1,
394
347
  offBlack32: offBlack32$1
395
348
  } = Color;
396
- const styles$6 = StyleSheet.create({
349
+ const styles$5 = StyleSheet.create({
397
350
  itemContainer: {
398
351
  flexDirection: "row",
399
352
  background: white$1,
@@ -424,7 +377,6 @@ const styles$6 = StyleSheet.create({
424
377
  whiteSpace: "nowrap",
425
378
  userSelect: "none",
426
379
  marginLeft: Spacing.xSmall_8,
427
- // added to truncate strings that are longer than expected
428
380
  overflow: "hidden",
429
381
  textOverflow: "ellipsis"
430
382
  },
@@ -433,30 +385,21 @@ const styles$6 = StyleSheet.create({
433
385
  }
434
386
  });
435
387
 
436
- // Separator item in a dropdown, used to denote a semantic break.
437
-
438
- /**
439
- * A separator used in a dropdown menu.
440
- */
441
388
  class SeparatorItem extends React.Component {
442
389
  static isClassOf(instance) {
443
390
  return instance && instance.type && instance.type.__IS_SEPARATOR_ITEM__;
444
391
  }
445
392
 
446
393
  render() {
447
- return (
448
- /*#__PURE__*/
449
- // pass optional styles from react-window (if applies)
450
- React.createElement(View, {
451
- style: [styles$5.separator, this.props.style],
452
- "aria-hidden": "true"
453
- })
454
- );
394
+ return React.createElement(View, {
395
+ style: [styles$4.separator, this.props.style],
396
+ "aria-hidden": "true"
397
+ });
455
398
  }
456
399
 
457
400
  }
458
401
  SeparatorItem.__IS_SEPARATOR_ITEM__ = true;
459
- const styles$5 = StyleSheet.create({
402
+ const styles$4 = StyleSheet.create({
460
403
  separator: {
461
404
  boxShadow: `0 -1px ${Color.offBlack16}`,
462
405
  height: 1,
@@ -486,23 +429,18 @@ class DropdownOpener extends React.Component {
486
429
  }));
487
430
  const childrenProps = renderedChildren.props;
488
431
  const childrenTestId = this.getTestIdFromProps(childrenProps);
489
- return /*#__PURE__*/React.cloneElement(renderedChildren, _extends({}, clickableChildrenProps, {
432
+ return React.cloneElement(renderedChildren, _extends({}, clickableChildrenProps, {
490
433
  disabled,
491
434
  onClick: childrenProps.onClick ? e => {
492
- // This is done to avoid overriding a
493
- // custom onClick handler inside the
494
- // children node
495
435
  childrenProps.onClick(e);
496
436
  clickableChildrenProps.onClick(e);
497
437
  } : clickableChildrenProps.onClick,
498
- // try to get the testId from the child element
499
- // If it's not set, try to fallback to the parent's testId
500
438
  "data-test-id": childrenTestId || testId
501
439
  }));
502
440
  }
503
441
 
504
442
  render() {
505
- return /*#__PURE__*/React.createElement(ClickableBehavior, {
443
+ return React.createElement(ClickableBehavior, {
506
444
  onClick: this.props.onClick,
507
445
  disabled: this.props.disabled
508
446
  }, (eventState, handlers) => this.renderAnchorChildren(eventState, handlers));
@@ -514,11 +452,6 @@ DropdownOpener.defaultProps = {
514
452
  disabled: false
515
453
  };
516
454
 
517
- /**
518
- * A virtualized list item - It's created by decorating the DropdownItem
519
- * (ActionItem, OptionItem, SeparatorItem) with custom styles to let
520
- * react-window make its own calculations.
521
- */
522
455
  class DropdownVirtualizedItem extends React.Component {
523
456
  render() {
524
457
  const {
@@ -529,9 +462,7 @@ class DropdownVirtualizedItem extends React.Component {
529
462
  const item = data[index];
530
463
 
531
464
  if (SeparatorItem.isClassOf(item.component)) {
532
- // add react-window style to the separator to preserve the correct
533
- // position
534
- return /*#__PURE__*/React.cloneElement(item.component, {
465
+ return React.cloneElement(item.component, {
535
466
  style
536
467
  });
537
468
  } else {
@@ -542,7 +473,7 @@ class DropdownVirtualizedItem extends React.Component {
542
473
  role,
543
474
  ref
544
475
  } = item;
545
- return /*#__PURE__*/React.cloneElement(component, _extends({
476
+ return React.cloneElement(component, _extends({
546
477
  style
547
478
  }, populatedProps, {
548
479
  key: index,
@@ -556,112 +487,30 @@ class DropdownVirtualizedItem extends React.Component {
556
487
  }
557
488
 
558
489
  class SearchTextInput extends React.Component {
559
- constructor(...args) {
560
- super(...args);
561
- this.state = {
562
- focused: false,
563
- labels: _extends({
564
- clearSearch: defaultLabels.clearSearch,
565
- filter: defaultLabels.filter
566
- }, this.props.labels)
567
- };
568
-
569
- this.handleChange = e => {
570
- e.preventDefault();
571
- this.props.onChange(e.target.value);
572
- };
573
-
574
- this.handleDismiss = () => {
575
- const {
576
- onClick,
577
- onChange
578
- } = this.props; // Empty the search text and focus the SearchTextInput
579
-
580
- onChange("");
581
-
582
- if (onClick) {
583
- onClick();
584
- }
585
- };
586
-
587
- this.handleBlur = e => {
588
- this.setState({
589
- focused: false
590
- });
591
- };
592
-
593
- this.handleFocus = e => {
594
- this.setState({
595
- focused: true
596
- });
597
- };
598
- }
599
-
600
490
  static isClassOf(instance) {
601
491
  return instance && instance.type && instance.type.__IS_SEARCH_TEXT_INPUT__;
602
492
  }
603
493
 
604
- componentDidUpdate(prevProps) {
605
- if (this.props.labels !== prevProps.labels) {
606
- // eslint-disable-next-line react/no-did-update-set-state
607
- this.setState({
608
- labels: _extends({}, this.state.labels, this.props.labels)
609
- });
610
- }
611
- }
612
-
613
- maybeRenderDismissIconButton() {
614
- const {
615
- searchText
616
- } = this.props;
617
- const {
618
- clearSearch
619
- } = this.state.labels;
620
-
621
- if (searchText.length > 0) {
622
- return /*#__PURE__*/React.createElement(IconButton, {
623
- icon: icons.dismiss,
624
- kind: "tertiary",
625
- onClick: this.handleDismiss,
626
- style: styles$4.dismissIcon,
627
- "aria-label": clearSearch
628
- });
629
- }
630
-
631
- return null;
632
- }
633
-
634
494
  render() {
635
495
  const {
496
+ labels,
497
+ onChange,
636
498
  onClick,
637
499
  itemRef,
638
500
  searchText,
639
501
  style,
640
502
  testId
641
503
  } = this.props;
642
- const {
643
- filter
644
- } = this.state.labels;
645
- return /*#__PURE__*/React.createElement(View, {
504
+ return React.createElement(SearchField, {
505
+ clearAriaLabel: labels.clearSearch,
506
+ onChange: onChange,
646
507
  onClick: onClick,
647
- style: [styles$4.inputContainer, this.state.focused && styles$4.focused, style]
648
- }, /*#__PURE__*/React.createElement(Icon, {
649
- icon: icons.search,
650
- size: "medium",
651
- color: Color.offBlack64,
652
- style: styles$4.searchIcon,
653
- "aria-hidden": "true"
654
- }), /*#__PURE__*/React.createElement("input", {
655
- type: "text",
656
- onChange: this.handleChange,
657
- onFocus: this.handleFocus,
658
- onBlur: this.handleBlur,
508
+ placeholder: labels.filter,
659
509
  ref: itemRef,
660
- placeholder: filter,
661
- value: searchText,
662
- className: css(styles$4.inputStyleReset, styles$a.LabelMedium),
663
- "data-test-id": testId
664
- }), this.maybeRenderDismissIconButton());
510
+ style: style,
511
+ testId: testId,
512
+ value: searchText
513
+ });
665
514
  }
666
515
 
667
516
  }
@@ -672,89 +521,54 @@ SearchTextInput.defaultProps = {
672
521
  }
673
522
  };
674
523
  SearchTextInput.__IS_SEARCH_TEXT_INPUT__ = true;
675
- const styles$4 = StyleSheet.create({
676
- inputContainer: {
677
- flexDirection: "row",
678
- border: `1px solid ${Color.offBlack16}`,
679
- borderRadius: Spacing.xxxSmall_4,
680
- alignItems: "center",
681
- // The height of the text input is 40 in design spec and we need to
682
- // specify the height as well as minHeight to make sure the search text
683
- // input takes enough height to render. (otherwise, it will get
684
- // squashed)
685
- height: DROPDOWN_ITEM_HEIGHT,
686
- minHeight: DROPDOWN_ITEM_HEIGHT
687
- },
688
- focused: {
689
- border: `1px solid ${Color.blue}`
690
- },
691
- searchIcon: {
692
- marginLeft: Spacing.xSmall_8,
693
- marginRight: Spacing.xSmall_8
694
- },
695
- dismissIcon: {
696
- margin: 0,
697
- ":hover": {
698
- border: "none"
699
- }
700
- },
701
- inputStyleReset: {
702
- display: "flex",
703
- flex: 1,
704
- background: "inherit",
705
- border: "none",
706
- outline: "none",
707
- "::placeholder": {
708
- color: Color.offBlack64
709
- },
710
- width: "100%",
711
- color: "inherit"
712
- }
713
- });
714
524
 
715
- /**
716
- * Maximum visible items inside the dropdown list.
717
- * Based on the defined height that we're using, this is the maximium
718
- * number of items that can fit into the visible porition of the
719
- * dropdowns list box.
720
- */
721
- const MAX_VISIBLE_ITEMS = 9;
722
- /**
723
- * A react-window's List wrapper that instantiates the virtualized list and
724
- * dynamically calculates the item height depending on the type
725
- */
525
+ function getDropdownMenuHeight(items, initialHeight = 0) {
526
+ return items.slice(0, MAX_VISIBLE_ITEMS).reduce((sum, item) => {
527
+ if (SeparatorItem.isClassOf(item.component)) {
528
+ return sum + SEPARATOR_ITEM_HEIGHT;
529
+ } else if (SearchTextInput.isClassOf(item.component)) {
530
+ return sum + SEARCH_ITEM_HEIGHT;
531
+ } else {
532
+ return sum + DROPDOWN_ITEM_HEIGHT;
533
+ }
534
+ }, initialHeight);
535
+ }
536
+ function generateDropdownMenuStyles(minWidth, maxHeight) {
537
+ const styles = StyleSheet.create({
538
+ dropdownMenu: {
539
+ minWidth,
540
+ maxHeight
541
+ }
542
+ });
543
+ return styles.dropdownMenu;
544
+ }
726
545
 
727
546
  class DropdownCoreVirtualized extends React.Component {
728
- constructor(...args) {
729
- super(...args);
730
- this.state = {
731
- height: this.getHeight(),
732
- width: this.props.width
733
- };
547
+ constructor(props) {
548
+ super(props);
734
549
 
735
550
  this.getItemSize = index => {
736
- // get the current item in the list
737
551
  const item = this.props.data[index];
738
552
 
739
553
  if (SeparatorItem.isClassOf(item.component)) {
740
- // this is the separator's height (1px) + vertical margin (8px)
741
554
  return SEPARATOR_ITEM_HEIGHT;
742
555
  } else if (SearchTextInput.isClassOf(item.component)) {
743
- // search text input height
744
556
  return SEARCH_ITEM_HEIGHT;
745
557
  } else {
746
- // default dropdown item height
747
558
  return DROPDOWN_ITEM_HEIGHT;
748
559
  }
749
560
  };
561
+
562
+ this.state = {
563
+ height: getDropdownMenuHeight(props.data),
564
+ width: props.width
565
+ };
750
566
  }
751
567
 
752
568
  componentDidMount() {
753
569
  const {
754
570
  schedule
755
- } = this.props; // Wait for styles to be applied. This way, we can get a more precise
756
- // value of the container dimensions.
757
-
571
+ } = this.props;
758
572
  schedule.animationFrame(() => {
759
573
  this.setWidth();
760
574
  });
@@ -764,27 +578,20 @@ class DropdownCoreVirtualized extends React.Component {
764
578
  const {
765
579
  data,
766
580
  listRef
767
- } = this.props; // if the items size has changed, then recalculate each item position
581
+ } = this.props;
768
582
 
769
583
  if (prevProps.data.length !== data.length) {
770
584
  this.setHeight();
771
585
 
772
586
  if (listRef && listRef.current) {
773
- // the ref can't associate this instance method
774
- // $FlowIgnore
775
587
  listRef.current.resetAfterIndex(1);
776
588
  }
777
589
  }
778
590
  }
779
- /**
780
- * Update container width
781
- */
782
-
783
591
 
784
592
  setWidth() {
785
593
  const rootNode = ReactDOM.findDOMNode(this);
786
- const parentNode = rootNode == null ? void 0 : rootNode.parentElement; // after the non-virtualized items are rendered, we get the container
787
- // width to pass it to react-window's List
594
+ const parentNode = rootNode == null ? void 0 : rootNode.parentElement;
788
595
 
789
596
  if (parentNode) {
790
597
  const width = parentNode.getBoundingClientRect().width;
@@ -793,67 +600,27 @@ class DropdownCoreVirtualized extends React.Component {
793
600
  });
794
601
  }
795
602
  }
796
- /**
797
- * Update container height
798
- */
799
-
800
603
 
801
604
  setHeight() {
802
- // calculate dropdown's height depending on the type of items
803
- const height = this.getHeight();
605
+ const height = getDropdownMenuHeight(this.props.data);
804
606
  this.setState({
805
607
  height
806
608
  });
807
609
  }
808
- /**
809
- * The list height that is automatically calculated depending on the
810
- * component's type of each item (e.g. Separator, Option, Search, etc)
811
- */
812
-
813
610
 
814
- getHeight() {
815
- // calculate using the first 10 items on the array as we want to display
816
- // this number of elements in the visible area
817
- return this.props.data.slice(0, MAX_VISIBLE_ITEMS).reduce((sum, item) => {
818
- if (SeparatorItem.isClassOf(item.component)) {
819
- return sum + SEPARATOR_ITEM_HEIGHT;
820
- } else if (SearchTextInput.isClassOf(item.component)) {
821
- // search text input height
822
- return sum + SEARCH_ITEM_HEIGHT;
823
- } else {
824
- return sum + DROPDOWN_ITEM_HEIGHT;
825
- }
826
- }, 0);
827
- }
828
- /**
829
- * Calculates item height
830
- */
831
-
832
-
833
- /**
834
- * render non virtualized items to calculate the container max-width that
835
- * will be used by DropdownCoreVirtualized
836
- */
837
611
  renderInitialItems() {
838
612
  const {
839
613
  data
840
614
  } = this.props;
841
- const allComponents = data.map(e => e.component); // 1. get the children opaque data structure to sort each item by its
842
- // label length
843
-
615
+ const allComponents = data.map(e => e.component);
844
616
  const longestItems = React.Children.toArray(allComponents).filter(Boolean).sort((a, b) => {
845
- // 2. only sort elements that contain a `label` prop
846
617
  if (b.props.label && a.props.label) {
847
618
  return b.props.label.length - a.props.label.length;
848
619
  }
849
620
 
850
621
  return -1;
851
- }) // 3. only render the possible visible items to minimize layout
852
- // jumps
853
- .slice(0, MAX_VISIBLE_ITEMS); // Append longest items to calculate the container width.
854
- // We need to hide these sorted elements to avoid any FOUC.
855
-
856
- return longestItems.map(item => /*#__PURE__*/React.cloneElement(item, {
622
+ }).slice(0, MAX_VISIBLE_ITEMS);
623
+ return longestItems.map(item => React.cloneElement(item, {
857
624
  style: {
858
625
  visibility: "hidden"
859
626
  }
@@ -869,38 +636,24 @@ class DropdownCoreVirtualized extends React.Component {
869
636
  height,
870
637
  width
871
638
  } = this.state;
872
- return (
873
- /*#__PURE__*/
874
- // react-window has some issues for typing lists when passing refs
875
- // $FlowIgnore
876
- React.createElement(VariableSizeList // react-window doesn't accept maybe numbers. It wants numbers
877
- // or strings.
878
- // $FlowFixMe
879
- , {
880
- height: height,
881
- itemCount: data.length,
882
- itemSize: this.getItemSize,
883
- itemData: data,
884
- style: {
885
- overflowX: "hidden"
886
- } // react-window doesn't accept maybe numbers. It wants numbers
887
- // or strings.
888
- // $FlowFixMe
889
- ,
890
- width: width,
891
- overscanCount: 5,
892
- ref: listRef
893
- }, DropdownVirtualizedItem)
894
- );
639
+ return React.createElement(VariableSizeList, {
640
+ height: height,
641
+ itemCount: data.length,
642
+ itemSize: this.getItemSize,
643
+ itemData: data,
644
+ style: {
645
+ overflowX: "hidden"
646
+ },
647
+ width: width,
648
+ overscanCount: 5,
649
+ ref: listRef
650
+ }, DropdownVirtualizedItem);
895
651
  }
896
652
 
897
653
  render() {
898
654
  if (this.state.width === undefined) {
899
- // if we don't pass a fixed value, then we need to render
900
- // non-virtualized items to calculate width
901
655
  return this.renderInitialItems();
902
656
  } else {
903
- // width has been provided, then render the virtualized list
904
657
  return this.renderVirtualizedList();
905
658
  }
906
659
  }
@@ -913,34 +666,23 @@ const modifiers = [{
913
666
  name: "preventOverflow",
914
667
  options: {
915
668
  rootBoundary: "viewport",
916
- // Allows to overlap the popper in case there's no more vertical
917
- // room in the viewport.
918
669
  altAxis: true,
919
- // Also needed to make sure the Popper will be displayed correctly
920
- // in different contexts (e.g inside a Modal)
921
670
  tether: false
922
671
  }
923
672
  }];
924
-
925
- /**
926
- * A wrapper for PopperJS that renders the children inside a portal.
927
- */
928
673
  function DropdownPopper({
929
674
  children,
930
675
  alignment = "left",
931
676
  onPopperElement,
932
677
  referenceElement
933
678
  }) {
934
- // If we are in a modal, we find where we should be portalling the menu by
935
- // using the helper function from the modal package on the opener element.
936
- // If we are not in a modal, we use body as the location to portal to.
937
679
  const modalHost = maybeGetPortalMountedModalHostElement(referenceElement) || document.querySelector("body");
938
680
 
939
681
  if (!modalHost) {
940
682
  return null;
941
683
  }
942
684
 
943
- return /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement(Popper, {
685
+ return ReactDOM.createPortal(React.createElement(Popper, {
944
686
  innerRef: node => {
945
687
  if (node && onPopperElement) {
946
688
  onPopperElement(node);
@@ -958,7 +700,7 @@ function DropdownPopper({
958
700
  isReferenceHidden
959
701
  }) => {
960
702
  const shouldHidePopper = !!(hasPopperEscaped || isReferenceHidden);
961
- return /*#__PURE__*/React.createElement("div", {
703
+ return React.createElement("div", {
962
704
  ref: ref,
963
705
  style: style,
964
706
  "data-test-id": "dropdown-popper",
@@ -967,34 +709,9 @@ function DropdownPopper({
967
709
  }), modalHost);
968
710
  }
969
711
 
970
- /**
971
- * The number of options to apply the virtualized list to.
972
- *
973
- * NOTE: The threshold is defined taking into account performance
974
- * implications (e.g. process input events for users should not be longer
975
- * than 100ms).
976
- * @see https://web.dev/rail/?utm_source=devtools#goals-and-guidelines
977
- *
978
- * TODO(juan, WB-1263): Improve performance by refactoring this component.
979
- */
980
-
981
712
  const VIRTUALIZE_THRESHOLD = 125;
982
713
 
983
- /**
984
- * A core dropdown component that takes an opener and children to display as
985
- * part of the dropdown menu. Renders the dropdown as a portal to avoid clipping
986
- * in overflow: auto containers.
987
- */
988
714
  class DropdownCore extends React.Component {
989
- // Keeps track of the index of the focused item, out of a list of focusable items
990
- // Keeps track of the index of the focused item in the context of all the
991
- // items contained by this menu, whether focusable or not, used for figuring
992
- // out focus correctly when the items have changed in terms of whether
993
- // they're focusable or not
994
- // Whether any items have been selected since the menu was opened
995
- // Keeps a reference of the virtualized list instance
996
- // Figure out if the same items are focusable. If an item has been added or
997
- // removed, this method will return false.
998
715
  static sameItemsFocusable(prevItems, currentItems) {
999
716
  if (prevItems.length !== currentItems.length) {
1000
717
  return false;
@@ -1009,16 +726,13 @@ class DropdownCore extends React.Component {
1009
726
  return true;
1010
727
  }
1011
728
 
1012
- // This is here to avoid calling React.createRef on each rerender. Instead,
1013
- // we create the itemRefs only if it's the first time or if the set of items
1014
- // that are focusable has changed.
1015
729
  static getDerivedStateFromProps(props, state) {
1016
730
  if (state.itemRefs.length === 0 && props.open || !DropdownCore.sameItemsFocusable(state.prevItems, props.items)) {
1017
731
  const itemRefs = [];
1018
732
 
1019
733
  for (let i = 0; i < props.items.length; i++) {
1020
734
  if (props.items[i].focusable) {
1021
- const ref = /*#__PURE__*/React.createRef();
735
+ const ref = React.createRef();
1022
736
  itemRefs.push({
1023
737
  ref,
1024
738
  originalIndex: i
@@ -1040,7 +754,7 @@ class DropdownCore extends React.Component {
1040
754
  }
1041
755
 
1042
756
  constructor(props) {
1043
- super(props); // Apply our initial focus index
757
+ super(props);
1044
758
 
1045
759
  this.handleInteract = event => {
1046
760
  const {
@@ -1061,7 +775,7 @@ class DropdownCore extends React.Component {
1061
775
  open,
1062
776
  searchText
1063
777
  } = this.props;
1064
- const keyCode = event.which || event.keyCode; // If menu isn't open and user presses down, open the menu
778
+ const keyCode = event.which || event.keyCode;
1065
779
 
1066
780
  if (!open) {
1067
781
  if (keyCode === keyCodes.down) {
@@ -1071,15 +785,10 @@ class DropdownCore extends React.Component {
1071
785
  }
1072
786
 
1073
787
  return;
1074
- } // Handle all other key behavior
1075
-
788
+ }
1076
789
 
1077
790
  switch (keyCode) {
1078
791
  case keyCodes.tab:
1079
- // When we show SearchTextInput and that is focused and the
1080
- // searchText is entered at least one character, dismiss button
1081
- // is displayed. When user presses tab, we should move focus
1082
- // to the dismiss button.
1083
792
  if (this.hasSearchBox() && this.focusedIndex === 0 && searchText) {
1084
793
  return;
1085
794
  }
@@ -1089,12 +798,9 @@ class DropdownCore extends React.Component {
1089
798
  return;
1090
799
 
1091
800
  case keyCodes.space:
1092
- // When we display SearchTextInput and the focus is on it,
1093
- // we should let the user type space.
1094
801
  if (this.hasSearchBox() && this.focusedIndex === 0) {
1095
802
  return;
1096
- } // Prevent space from scrolling down the page
1097
-
803
+ }
1098
804
 
1099
805
  event.preventDefault();
1100
806
  return;
@@ -1120,19 +826,14 @@ class DropdownCore extends React.Component {
1120
826
 
1121
827
  switch (keyCode) {
1122
828
  case keyCodes.space:
1123
- // When we display SearchTextInput and the focus is on it,
1124
- // we should let the user type space.
1125
829
  if (this.hasSearchBox() && this.focusedIndex === 0) {
1126
830
  return;
1127
- } // Prevent space from scrolling down the page
1128
-
831
+ }
1129
832
 
1130
833
  event.preventDefault();
1131
834
  return;
1132
835
 
1133
836
  case keyCodes.escape:
1134
- // Close only the dropdown, not other elements that are
1135
- // listening for an escape press
1136
837
  if (open) {
1137
838
  event.stopPropagation();
1138
839
  this.restoreTabOrder();
@@ -1144,19 +845,15 @@ class DropdownCore extends React.Component {
1144
845
  };
1145
846
 
1146
847
  this.handleClickFocus = index => {
1147
- // Turn itemsClicked on so pressing up or down would focus the
1148
- // appropriate item in handleKeyDown
1149
848
  this.itemsClicked = true;
1150
849
  this.focusedIndex = index;
1151
850
  this.focusedOriginalIndex = this.state.itemRefs[this.focusedIndex].originalIndex;
1152
851
  };
1153
852
 
1154
853
  this.handleDropdownMouseUp = event => {
1155
- // $FlowIgnore[method-unbinding]
1156
854
  if (event.nativeEvent.stopImmediatePropagation) {
1157
855
  event.nativeEvent.stopImmediatePropagation();
1158
856
  } else {
1159
- // Workaround for jsdom
1160
857
  event.stopPropagation();
1161
858
  }
1162
859
  };
@@ -1182,7 +879,7 @@ class DropdownCore extends React.Component {
1182
879
  noResults: defaultLabels.noResults
1183
880
  }, props.labels)
1184
881
  };
1185
- this.virtualizedListRef = /*#__PURE__*/React.createRef();
882
+ this.virtualizedListRef = React.createRef();
1186
883
  }
1187
884
 
1188
885
  componentDidMount() {
@@ -1198,33 +895,19 @@ class DropdownCore extends React.Component {
1198
895
  if (prevProps.open !== open) {
1199
896
  this.updateEventListeners();
1200
897
  this.initialFocusItem();
1201
- } // If the menu changed, but from open to open, figure out if we need
1202
- // to recalculate the focus somehow.
1203
- else if (open) {
898
+ } else if (open) {
1204
899
  const {
1205
900
  itemRefs,
1206
901
  sameItemsFocusable
1207
- } = this.state; // Check if the same items are focused by comparing the items at
1208
- // each index and seeing if the {focusable} property is the same.
1209
- // Very rarely do the set of focusable items change if the menu
1210
- // hasn't been re-opened. This is for cases like a {Select all}
1211
- // option that becomes disabled iff all the options are selected.
902
+ } = this.state;
1212
903
 
1213
904
  if (sameItemsFocusable) {
1214
905
  return;
1215
906
  } else {
1216
- // If the set of items that was focusabled changed, it's very
1217
- // likely that the previously focused item no longer has the
1218
- // same index relative to the list of focusable items. Instead,
1219
- // use the focusedOriginalIndex to find the new index of the
1220
- // last item that was focused before this change
1221
907
  const newFocusableIndex = itemRefs.findIndex(ref => ref.originalIndex === this.focusedOriginalIndex);
1222
908
 
1223
909
  if (newFocusableIndex === -1) {
1224
- // Can't find the originally focused item, return focus to
1225
- // the first item that IS focusable
1226
- this.focusedIndex = 0; // Reset the knowlege that things had been clicked
1227
-
910
+ this.focusedIndex = 0;
1228
911
  this.itemsClicked = false;
1229
912
  this.scheduleToFocusCurrentItem();
1230
913
  } else {
@@ -1233,7 +916,6 @@ class DropdownCore extends React.Component {
1233
916
  }
1234
917
 
1235
918
  if (this.props.labels !== prevProps.labels) {
1236
- // eslint-disable-next-line react/no-did-update-set-state
1237
919
  this.setState({
1238
920
  labels: _extends({}, this.state.labels, this.props.labels)
1239
921
  });
@@ -1247,21 +929,14 @@ class DropdownCore extends React.Component {
1247
929
 
1248
930
  hasSearchBox() {
1249
931
  return !!this.props.onSearchTextChanged && typeof this.props.searchText === "string";
1250
- } // Resets our initial focus index to what was passed in
1251
- // via the props
1252
-
932
+ }
1253
933
 
1254
934
  resetFocusedIndex() {
1255
935
  const {
1256
936
  initialFocusedIndex
1257
- } = this.props; // If we are given an initial focus index, select it. Otherwise
1258
- // default to the first item
937
+ } = this.props;
1259
938
 
1260
939
  if (initialFocusedIndex) {
1261
- // If we have a search box visible, then our focus
1262
- // index is going to be offset by 1, since the orginal
1263
- // index doesn't account for the search box's
1264
- // existence.
1265
940
  if (this.hasSearchBox()) {
1266
941
  this.focusedIndex = initialFocusedIndex + 1;
1267
942
  } else {
@@ -1270,9 +945,7 @@ class DropdownCore extends React.Component {
1270
945
  } else {
1271
946
  this.focusedIndex = 0;
1272
947
  }
1273
- } // Figure out focus states for the dropdown after it has changed from open
1274
- // to closed or vice versa
1275
-
948
+ }
1276
949
 
1277
950
  initialFocusItem() {
1278
951
  const {
@@ -1307,10 +980,8 @@ class DropdownCore extends React.Component {
1307
980
 
1308
981
  scheduleToFocusCurrentItem() {
1309
982
  if (this.shouldVirtualizeList()) {
1310
- // wait for windowed items to be recalculated
1311
983
  this.props.schedule.animationFrame(() => this.focusCurrentItem());
1312
984
  } else {
1313
- // immediately focus the current item if we're not virtualizing
1314
985
  this.focusCurrentItem();
1315
986
  }
1316
987
  }
@@ -1319,21 +990,14 @@ class DropdownCore extends React.Component {
1319
990
  const fousedItemRef = this.state.itemRefs[this.focusedIndex];
1320
991
 
1321
992
  if (fousedItemRef) {
1322
- // force react-window to scroll to ensure the focused item is visible
1323
993
  if (this.virtualizedListRef.current) {
1324
- // Our focused index does not include disabled items, but the
1325
- // react-window index system does include the disabled items
1326
- // in the count. So we need to use "originalIndex", which
1327
- // does account for disabled items.
1328
994
  this.virtualizedListRef.current.scrollToItem(fousedItemRef.originalIndex);
1329
995
  }
1330
996
 
1331
997
  const node = ReactDOM.findDOMNode(fousedItemRef.ref.current);
1332
998
 
1333
999
  if (node) {
1334
- node.focus(); // Keep track of the original index of the newly focused item.
1335
- // To be used if the set of focusable items in the menu changes
1336
-
1000
+ node.focus();
1337
1001
  this.focusedOriginalIndex = fousedItemRef.originalIndex;
1338
1002
  }
1339
1003
  }
@@ -1360,10 +1024,6 @@ class DropdownCore extends React.Component {
1360
1024
  }
1361
1025
 
1362
1026
  restoreTabOrder() {
1363
- // NOTE: Because the dropdown is portalled out of its natural
1364
- // position in the DOM, we need to manually return focus to the
1365
- // opener element before we let the natural propagation of tab
1366
- // shift the focus to the next element in the tab order.
1367
1027
  if (this.props.openerElement) {
1368
1028
  this.props.openerElement.focus();
1369
1029
  }
@@ -1396,12 +1056,11 @@ class DropdownCore extends React.Component {
1396
1056
  }
1397
1057
  } = this.props;
1398
1058
  const showSearchTextInput = !!onSearchTextChanged && typeof searchText === "string";
1399
- const includeSearchCount = showSearchTextInput ? 1 : 0; // Verify if there are items to be rendered or not
1400
-
1059
+ const includeSearchCount = showSearchTextInput ? 1 : 0;
1401
1060
  const numResults = items.length - includeSearchCount;
1402
1061
 
1403
1062
  if (numResults === 0) {
1404
- return /*#__PURE__*/React.createElement(LabelMedium, {
1063
+ return React.createElement(LabelMedium, {
1405
1064
  style: styles$3.noResult,
1406
1065
  testId: "dropdown-core-no-results"
1407
1066
  }, noResults);
@@ -1409,29 +1068,14 @@ class DropdownCore extends React.Component {
1409
1068
 
1410
1069
  return null;
1411
1070
  }
1412
- /**
1413
- * Handles click events for each item in the dropdown.
1414
- */
1415
1071
 
1416
-
1417
- /**
1418
- * Determines which rendering strategy we are going to apply to the options
1419
- * list.
1420
- */
1421
1072
  shouldVirtualizeList() {
1422
- // Verify if the list is long enough to be virtualized (passes the
1423
- // threshold).
1424
1073
  return this.props.items.length > VIRTUALIZE_THRESHOLD;
1425
1074
  }
1426
- /**
1427
- * Renders the non-virtualized list of items.
1428
- */
1429
-
1430
1075
 
1431
1076
  renderList() {
1432
1077
  let focusCounter = 0;
1433
- const itemRole = this.getItemRole(); // if we don't need to virtualize, we can render the list directly
1434
-
1078
+ const itemRole = this.getItemRole();
1435
1079
  return this.props.items.map((item, index) => {
1436
1080
  if (SeparatorItem.isClassOf(item.component)) {
1437
1081
  return item.component;
@@ -1447,46 +1091,31 @@ class DropdownCore extends React.Component {
1447
1091
  focusCounter += 1;
1448
1092
  }
1449
1093
 
1450
- const focusIndex = focusCounter - 1; // The reference to the item is used to restore focus.
1451
-
1452
- const currentRef = this.state.itemRefs[focusIndex] ? this.state.itemRefs[focusIndex].ref : null; // Render the SearchField component.
1094
+ const focusIndex = focusCounter - 1;
1095
+ const currentRef = this.state.itemRefs[focusIndex] ? this.state.itemRefs[focusIndex].ref : null;
1453
1096
 
1454
1097
  if (SearchTextInput.isClassOf(component)) {
1455
- return /*#__PURE__*/React.cloneElement(component, _extends({}, populatedProps, {
1098
+ return React.cloneElement(component, _extends({}, populatedProps, {
1456
1099
  key: "search-text-input",
1457
- // pass the current ref down to the input element
1458
1100
  itemRef: currentRef,
1459
- // override to avoid losing focus when pressing a key
1460
1101
  onClick: () => {
1461
1102
  this.handleClickFocus(0);
1462
1103
  this.focusCurrentItem();
1463
1104
  },
1464
- // apply custom styles
1465
1105
  style: searchInputStyle
1466
1106
  }));
1467
- } // Render OptionItem and/or ActionItem elements.
1468
-
1107
+ }
1469
1108
 
1470
- return /*#__PURE__*/React.cloneElement(component, _extends({}, populatedProps, {
1109
+ return React.cloneElement(component, _extends({}, populatedProps, {
1471
1110
  key: index,
1472
1111
  onClick: () => {
1473
1112
  this.handleItemClick(focusIndex, item);
1474
1113
  },
1475
- // Only pass the ref if the item is focusable.
1476
1114
  ref: focusable ? currentRef : null,
1477
1115
  role: itemRole
1478
1116
  }));
1479
1117
  });
1480
1118
  }
1481
- /**
1482
- * Process the items and wrap them into an array that react-window can
1483
- * interpret.
1484
- *
1485
- * NOTE: The main difference with the collection in renderList() is that we
1486
- * massage the items to be able to clone them later in
1487
- * DropdownVirtualizedItem, where as renderList() clones the items directly.
1488
- */
1489
-
1490
1119
 
1491
1120
  parseVirtualizedItems() {
1492
1121
  let focusCounter = 0;
@@ -1500,14 +1129,12 @@ class DropdownCore extends React.Component {
1500
1129
 
1501
1130
  if (SearchTextInput.isClassOf(item.component)) {
1502
1131
  return _extends({}, item, {
1503
- // override to avoid losing focus when pressing a key
1504
1132
  onClick: () => {
1505
1133
  this.handleClickFocus(0);
1506
1134
  this.focusCurrentItem();
1507
1135
  },
1508
1136
  populatedProps: {
1509
1137
  style: searchInputStyle,
1510
- // pass the current ref down to the input element
1511
1138
  itemRef: this.state.itemRefs[focusIndex] ? this.state.itemRefs[focusIndex].ref : null
1512
1139
  }
1513
1140
  });
@@ -1522,15 +1149,10 @@ class DropdownCore extends React.Component {
1522
1149
  });
1523
1150
  });
1524
1151
  }
1525
- /**
1526
- * Render the items using a virtualized list
1527
- */
1528
-
1529
1152
 
1530
1153
  renderVirtualizedList() {
1531
- // preprocess items data to pass it to the renderer
1532
1154
  const virtualizedItems = this.parseVirtualizedItems();
1533
- return /*#__PURE__*/React.createElement(DropdownCoreVirtualized$1, {
1155
+ return React.createElement(DropdownCoreVirtualized$1, {
1534
1156
  data: virtualizedItems,
1535
1157
  listRef: this.virtualizedListRef
1536
1158
  });
@@ -1541,19 +1163,15 @@ class DropdownCore extends React.Component {
1541
1163
  dropdownStyle,
1542
1164
  light,
1543
1165
  openerElement
1544
- } = this.props; // The dropdown width is at least the width of the opener.
1545
- // It's only used if the element exists in the DOM
1546
-
1166
+ } = this.props;
1547
1167
  const openerStyle = openerElement && window.getComputedStyle(openerElement);
1548
1168
  const minDropdownWidth = openerStyle ? openerStyle.getPropertyValue("width") : 0;
1549
- return /*#__PURE__*/React.createElement(View // Stop propagation to prevent the mouseup listener on the
1550
- // document from closing the menu.
1551
- , {
1169
+ const initialHeight = 12;
1170
+ const maxDropdownHeight = getDropdownMenuHeight(this.props.items, initialHeight);
1171
+ return React.createElement(View, {
1552
1172
  onMouseUp: this.handleDropdownMouseUp,
1553
1173
  role: this.props.role,
1554
- style: [styles$3.dropdown, light && styles$3.light, isReferenceHidden && styles$3.hidden, {
1555
- minWidth: minDropdownWidth
1556
- }, dropdownStyle]
1174
+ style: [styles$3.dropdown, light && styles$3.light, isReferenceHidden && styles$3.hidden, generateDropdownMenuStyles(minDropdownWidth, maxDropdownHeight), dropdownStyle]
1557
1175
  }, listRenderer, this.maybeRenderNoResults());
1558
1176
  }
1559
1177
 
@@ -1561,14 +1179,9 @@ class DropdownCore extends React.Component {
1561
1179
  const {
1562
1180
  alignment,
1563
1181
  openerElement
1564
- } = this.props; // Preprocess the items that are used inside the Popper instance. By
1565
- // doing this, we optimize the list to be processed only one time
1566
- // instead of every time popper changes.
1567
- // NOTE: This improves the performance impact of the dropdown by
1568
- // reducing the execution time up to 2.5X.
1569
-
1182
+ } = this.props;
1570
1183
  const listRenderer = this.shouldVirtualizeList() ? this.renderVirtualizedList() : this.renderList();
1571
- return /*#__PURE__*/React.createElement(DropdownPopper, {
1184
+ return React.createElement(DropdownPopper, {
1572
1185
  alignment: alignment,
1573
1186
  onPopperElement: popperElement => {
1574
1187
  this.popperElement = popperElement;
@@ -1584,7 +1197,7 @@ class DropdownCore extends React.Component {
1584
1197
  style,
1585
1198
  className
1586
1199
  } = this.props;
1587
- return /*#__PURE__*/React.createElement(View, {
1200
+ return React.createElement(View, {
1588
1201
  onKeyDown: this.handleKeyDown,
1589
1202
  onKeyUp: this.handleKeyUp,
1590
1203
  style: [styles$3.menuWrapper, style],
@@ -1615,7 +1228,6 @@ const styles$3 = StyleSheet.create({
1615
1228
  overflowY: "auto"
1616
1229
  },
1617
1230
  light: {
1618
- // Pretty much just remove the border
1619
1231
  border: "none"
1620
1232
  },
1621
1233
  hidden: {
@@ -1632,13 +1244,6 @@ var DropdownCore$1 = withActionScheduler(DropdownCore);
1632
1244
 
1633
1245
  const _excluded$4 = ["children", "disabled", "focused", "hovered", "pressed", "waiting", "testId", "opened", "aria-label"];
1634
1246
  const StyledButton$1 = addStyle("button");
1635
- /**
1636
- * Although this component shares a lot with ButtonCore there are a couple
1637
- * of differences:
1638
- * - the down caret icon appears on the right instead of the left
1639
- * - the down caret icon is smaller that the one that would be used by ButtonCore
1640
- */
1641
-
1642
1247
  class ActionMenuOpenerCore extends React.Component {
1643
1248
  render() {
1644
1249
  const _this$props = this.props,
@@ -1660,10 +1265,10 @@ class ActionMenuOpenerCore extends React.Component {
1660
1265
 
1661
1266
  const disabled = disabledProp;
1662
1267
  const defaultStyle = [sharedStyles.shared, disabled && sharedStyles.disabled, buttonStyles.default, disabled && buttonStyles.disabled, !disabled && pressed && buttonStyles.active];
1663
- const label = /*#__PURE__*/React.createElement(LabelLarge, {
1268
+ const label = React.createElement(LabelLarge, {
1664
1269
  style: sharedStyles.text
1665
1270
  }, children);
1666
- return /*#__PURE__*/React.createElement(StyledButton$1, _extends({
1271
+ return React.createElement(StyledButton$1, _extends({
1667
1272
  "aria-expanded": opened ? "true" : "false",
1668
1273
  "aria-haspopup": "menu",
1669
1274
  "aria-label": ariaLabel,
@@ -1672,11 +1277,11 @@ class ActionMenuOpenerCore extends React.Component {
1672
1277
  type: "button"
1673
1278
  }, restProps, {
1674
1279
  "data-test-id": testId
1675
- }), /*#__PURE__*/React.createElement(View, {
1280
+ }), React.createElement(View, {
1676
1281
  style: !disabled && (hovered || focused) && buttonStyles.focus
1677
- }, label), /*#__PURE__*/React.createElement(Strut, {
1282
+ }, label), React.createElement(Strut, {
1678
1283
  size: Spacing.xxxSmall_4
1679
- }), /*#__PURE__*/React.createElement(Icon, {
1284
+ }), React.createElement(Icon, {
1680
1285
  size: "small",
1681
1286
  color: "currentColor",
1682
1287
  icon: icons.caretDown
@@ -1697,11 +1302,8 @@ const sharedStyles = StyleSheet.create({
1697
1302
  outline: "none",
1698
1303
  textDecoration: "none",
1699
1304
  boxSizing: "border-box",
1700
- // This removes the 300ms click delay on mobile browsers by indicating that
1701
- // "double-tap to zoom" shouldn't be used on this element.
1702
1305
  touchAction: "manipulation",
1703
1306
  ":focus": {
1704
- // Mobile: Removes a blue highlight style shown when the user clicks a button
1705
1307
  WebkitTapHighlightColor: "rgba(0,0,0,0)"
1706
1308
  }
1707
1309
  },
@@ -1720,8 +1322,7 @@ const sharedStyles = StyleSheet.create({
1720
1322
  whiteSpace: "nowrap",
1721
1323
  overflow: "hidden",
1722
1324
  textOverflow: "ellipsis",
1723
- pointerEvents: "none" // fix Safari bug where the browser was eating mouse events
1724
-
1325
+ pointerEvents: "none"
1725
1326
  },
1726
1327
  hiddenText: {
1727
1328
  visibility: "hidden"
@@ -1774,10 +1375,6 @@ const _generateStyles$1 = color => {
1774
1375
  };
1775
1376
 
1776
1377
  const _excluded$3 = ["text"];
1777
-
1778
- /**
1779
- * A menu that consists of various types of items.
1780
- */
1781
1378
  class ActionMenu extends React.Component {
1782
1379
  constructor(...args) {
1783
1380
  super(...args);
@@ -1786,8 +1383,7 @@ class ActionMenu extends React.Component {
1786
1383
  };
1787
1384
 
1788
1385
  this.handleItemSelected = () => {
1789
- // close menu
1790
- this.handleOpenChanged(false); // Bring focus back to the opener element.
1386
+ this.handleOpenChanged(false);
1791
1387
 
1792
1388
  if (this.openerElement) {
1793
1389
  this.openerElement.focus();
@@ -1808,7 +1404,7 @@ class ActionMenu extends React.Component {
1808
1404
  const {
1809
1405
  onChange,
1810
1406
  selectedValues
1811
- } = this.props; // If either of these are not defined, return.
1407
+ } = this.props;
1812
1408
 
1813
1409
  if (!onChange || !selectedValues) {
1814
1410
  return;
@@ -1819,7 +1415,6 @@ class ActionMenu extends React.Component {
1819
1415
  const updatedSelection = [].concat(selectedValues.slice(0, index), selectedValues.slice(index + 1));
1820
1416
  onChange(updatedSelection);
1821
1417
  } else {
1822
- // Item was newly selected
1823
1418
  onChange([].concat(selectedValues, [selectedValue]));
1824
1419
  }
1825
1420
 
@@ -1835,10 +1430,6 @@ class ActionMenu extends React.Component {
1835
1430
  };
1836
1431
  }
1837
1432
 
1838
- /**
1839
- * Used to sync the `opened` state when this component acts as a controlled
1840
- * component
1841
- */
1842
1433
  static getDerivedStateFromProps(props, state) {
1843
1434
  return {
1844
1435
  opened: typeof props.opened === "boolean" ? props.opened : state.opened
@@ -1850,9 +1441,7 @@ class ActionMenu extends React.Component {
1850
1441
  children,
1851
1442
  selectedValues
1852
1443
  } = this.props;
1853
- const allChildren = React.Children.toArray(children).filter(Boolean); // verify if there's at least one OptionItem element to indent the
1854
- // possible Action items
1855
-
1444
+ const allChildren = React.Children.toArray(children).filter(Boolean);
1856
1445
  const isOptionItemIncluded = allChildren.some(item => OptionItem.isClassOf(item));
1857
1446
  return allChildren.map(item => {
1858
1447
  const {
@@ -1896,7 +1485,7 @@ class ActionMenu extends React.Component {
1896
1485
  const {
1897
1486
  opened
1898
1487
  } = this.state;
1899
- return /*#__PURE__*/React.createElement(DropdownOpener, {
1488
+ return React.createElement(DropdownOpener, {
1900
1489
  onClick: this.handleClick,
1901
1490
  disabled: numItems === 0 || disabled,
1902
1491
  text: menuText,
@@ -1905,7 +1494,7 @@ class ActionMenu extends React.Component {
1905
1494
  }, opener ? opener : openerProps => {
1906
1495
  const eventState = _objectWithoutPropertiesLoose(openerProps, _excluded$3);
1907
1496
 
1908
- return /*#__PURE__*/React.createElement(ActionMenuOpenerCore, _extends({}, eventState, {
1497
+ return React.createElement(ActionMenuOpenerCore, _extends({}, eventState, {
1909
1498
  disabled: disabled,
1910
1499
  opened: !!opened,
1911
1500
  testId: testId
@@ -1922,7 +1511,7 @@ class ActionMenu extends React.Component {
1922
1511
  } = this.props;
1923
1512
  const items = this.getMenuItems();
1924
1513
  const dropdownOpener = this.renderOpener(items.length);
1925
- return /*#__PURE__*/React.createElement(DropdownCore$1, {
1514
+ return React.createElement(DropdownCore$1, {
1926
1515
  role: "menu",
1927
1516
  style: style,
1928
1517
  className: className,
@@ -1945,14 +1534,12 @@ const styles$1 = StyleSheet.create({
1945
1534
  caret: {
1946
1535
  marginLeft: 4
1947
1536
  },
1948
- // The design calls for additional offset around the opener.
1949
1537
  opener: {
1950
1538
  whiteSpace: "nowrap",
1951
1539
  userSelect: "none",
1952
1540
  overflow: "hidden",
1953
1541
  textOverflow: "ellipsis"
1954
1542
  },
1955
- // This is to adjust the space between the menu and the opener.
1956
1543
  menuTopSpace: {
1957
1544
  top: -4
1958
1545
  }
@@ -1969,10 +1556,6 @@ const {
1969
1556
  offBlack32,
1970
1557
  offBlack64
1971
1558
  } = Color;
1972
-
1973
- /**
1974
- * An opener that opens select boxes.
1975
- */
1976
1559
  class SelectOpener extends React.Component {
1977
1560
  constructor(...args) {
1978
1561
  super(...args);
@@ -1999,7 +1582,7 @@ class SelectOpener extends React.Component {
1999
1582
  sharedProps = _objectWithoutPropertiesLoose(_this$props, _excluded$2);
2000
1583
 
2001
1584
  const ClickableBehavior = getClickableBehavior(router);
2002
- return /*#__PURE__*/React.createElement(ClickableBehavior, {
1585
+ return React.createElement(ClickableBehavior, {
2003
1586
  disabled: disabled,
2004
1587
  onClick: this.handleClick
2005
1588
  }, (state, childrenProps) => {
@@ -2009,12 +1592,10 @@ class SelectOpener extends React.Component {
2009
1592
  hovered,
2010
1593
  focused,
2011
1594
  pressed
2012
- } = state; // The icon colors are kind of fickle. This is just logic
2013
- // based on the zeplin design.
2014
-
1595
+ } = state;
2015
1596
  const iconColor = light ? disabled || pressed ? "currentColor" : white : disabled ? offBlack32 : offBlack64;
2016
1597
  const style = [styles.shared, stateStyles.default, disabled && stateStyles.disabled, !disabled && (pressed ? stateStyles.active : (hovered || focused) && stateStyles.focus)];
2017
- return /*#__PURE__*/React.createElement(StyledButton, _extends({}, sharedProps, {
1598
+ return React.createElement(StyledButton, _extends({}, sharedProps, {
2018
1599
  "aria-expanded": open ? "true" : "false",
2019
1600
  "aria-haspopup": "listbox",
2020
1601
  "data-test-id": testId,
@@ -2022,9 +1603,9 @@ class SelectOpener extends React.Component {
2022
1603
  id: id,
2023
1604
  style: style,
2024
1605
  type: "button"
2025
- }, childrenProps), /*#__PURE__*/React.createElement(LabelMedium, {
1606
+ }, childrenProps), React.createElement(LabelMedium, {
2026
1607
  style: styles.text
2027
- }, children), /*#__PURE__*/React.createElement(Icon, {
1608
+ }, children), React.createElement(Icon, {
2028
1609
  icon: icons.caretDown,
2029
1610
  color: iconColor,
2030
1611
  size: "small",
@@ -2035,7 +1616,7 @@ class SelectOpener extends React.Component {
2035
1616
  }
2036
1617
 
2037
1618
  render() {
2038
- return /*#__PURE__*/React.createElement(__RouterContext.Consumer, null, router => this.renderClickableBehavior(router));
1619
+ return React.createElement(__RouterContext.Consumer, null, router => this.renderClickableBehavior(router));
2039
1620
  }
2040
1621
 
2041
1622
  }
@@ -2046,7 +1627,6 @@ SelectOpener.defaultProps = {
2046
1627
  };
2047
1628
  const buttonRadius = 4;
2048
1629
  const styles = StyleSheet.create({
2049
- // TODO: Dedupe with Button styles
2050
1630
  shared: {
2051
1631
  position: "relative",
2052
1632
  display: "inline-flex",
@@ -2054,9 +1634,6 @@ const styles = StyleSheet.create({
2054
1634
  justifyContent: "space-between",
2055
1635
  color: offBlack,
2056
1636
  height: DROPDOWN_ITEM_HEIGHT,
2057
- // This asymmetry arises from the Icon on the right side, which has
2058
- // extra padding built in. To have the component look more balanced,
2059
- // we need to take off some paddingRight here.
2060
1637
  paddingLeft: 16,
2061
1638
  paddingRight: 12,
2062
1639
  borderWidth: 0,
@@ -2066,8 +1643,6 @@ const styles = StyleSheet.create({
2066
1643
  textDecoration: "none",
2067
1644
  boxSizing: "border-box",
2068
1645
  whiteSpace: "nowrap",
2069
- // This removes the 300ms click delay on mobile browsers by indicating that
2070
- // "double-tap to zoom" shouldn't be used on this element.
2071
1646
  touchAction: "manipulation"
2072
1647
  },
2073
1648
  text: {
@@ -2080,16 +1655,12 @@ const styles = StyleSheet.create({
2080
1655
  caret: {
2081
1656
  minWidth: 16
2082
1657
  }
2083
- }); // These values are default padding (16 and 12) minus 1, because
2084
- // changing the borderWidth to 2 messes up the button width
2085
- // and causes it to move a couple pixels. This fixes that.
2086
-
1658
+ });
2087
1659
  const adjustedPaddingLeft = 16 - 1;
2088
1660
  const adjustedPaddingRight = 12 - 1;
2089
1661
  const stateStyles = {};
2090
1662
 
2091
1663
  const _generateStyles = (light, placeholder) => {
2092
- // "hash" the parameters
2093
1664
  const styleKey = `${String(light)}-${String(placeholder)}`;
2094
1665
 
2095
1666
  if (stateStyles[styleKey]) {
@@ -2161,20 +1732,6 @@ const _generateStyles = (light, placeholder) => {
2161
1732
  };
2162
1733
 
2163
1734
  const _excluded$1 = ["children", "disabled", "id", "light", "opener", "placeholder", "selectedValue", "testId", "alignment", "dropdownStyle", "isFilterable", "onChange", "onToggle", "opened", "style", "className"];
2164
-
2165
- /**
2166
- * The single select allows the selection of one item. Clients are responsible
2167
- * for keeping track of the selected item in the select.
2168
- *
2169
- * The single select dropdown closes after the selection of an item. If the same
2170
- * item is selected, there is no callback.
2171
- *
2172
- * *NOTE:* The component automatically uses
2173
- * [react-window](https://github.com/bvaughn/react-window) to improve
2174
- * performance when rendering these elements and is capable of handling many
2175
- * hundreds of items without performance problems.
2176
- *
2177
- */
2178
1735
  class SingleSelect extends React.Component {
2179
1736
  constructor(props) {
2180
1737
  super(props);
@@ -2191,19 +1748,16 @@ class SingleSelect extends React.Component {
2191
1748
  };
2192
1749
 
2193
1750
  this.handleToggle = selectedValue => {
2194
- // Call callback if selection changed.
2195
1751
  if (selectedValue !== this.props.selectedValue) {
2196
1752
  this.props.onChange(selectedValue);
2197
- } // Bring focus back to the opener element.
2198
-
1753
+ }
2199
1754
 
2200
1755
  if (this.state.open && this.state.openerElement) {
2201
1756
  this.state.openerElement.focus();
2202
1757
  }
2203
1758
 
2204
1759
  this.setState({
2205
- open: false // close the menu upon selection
2206
-
1760
+ open: false
2207
1761
  });
2208
1762
 
2209
1763
  if (this.props.onToggle) {
@@ -2212,8 +1766,6 @@ class SingleSelect extends React.Component {
2212
1766
  };
2213
1767
 
2214
1768
  this.mapOptionItemsToDropdownItems = children => {
2215
- // Figure out which index should receive focus when this select opens
2216
- // Needs to exclude counting items that are disabled
2217
1769
  let indexCounter = 0;
2218
1770
  this.selectedIndex = 0;
2219
1771
  return children.map(option => {
@@ -2270,11 +1822,6 @@ class SingleSelect extends React.Component {
2270
1822
  openerElement: null
2271
1823
  };
2272
1824
  }
2273
- /**
2274
- * Used to sync the `opened` state when this component acts as a controlled
2275
- * component
2276
- */
2277
-
2278
1825
 
2279
1826
  static getDerivedStateFromProps(props, state) {
2280
1827
  return {
@@ -2286,8 +1833,7 @@ class SingleSelect extends React.Component {
2286
1833
  const {
2287
1834
  searchText
2288
1835
  } = this.state;
2289
- const lowercasedSearchText = searchText.toLowerCase(); // Filter the children with the searchText if any.
2290
-
1836
+ const lowercasedSearchText = searchText.toLowerCase();
2291
1837
  return children.filter(({
2292
1838
  props
2293
1839
  }) => !searchText || props.label.toLowerCase().indexOf(lowercasedSearchText) > -1);
@@ -2296,9 +1842,7 @@ class SingleSelect extends React.Component {
2296
1842
  getMenuItems(children) {
2297
1843
  const {
2298
1844
  isFilterable
2299
- } = this.props; // If it's not filterable, no need to do any extra besides mapping the
2300
- // option items to dropdown items.
2301
-
1845
+ } = this.props;
2302
1846
  return this.mapOptionItemsToDropdownItems(isFilterable ? this.filterChildren(children) : children);
2303
1847
  }
2304
1848
 
@@ -2308,7 +1852,7 @@ class SingleSelect extends React.Component {
2308
1852
  }
2309
1853
 
2310
1854
  return {
2311
- component: /*#__PURE__*/React.createElement(SearchTextInput, {
1855
+ component: React.createElement(SearchTextInput, {
2312
1856
  key: "search-text-input",
2313
1857
  onChange: this.handleSearchTextChanged,
2314
1858
  searchText: this.state.searchText,
@@ -2336,16 +1880,14 @@ class SingleSelect extends React.Component {
2336
1880
  } = _this$props,
2337
1881
  sharedProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
2338
1882
 
2339
- const selectedItem = React.Children.toArray(children).find(option => option.props.value === selectedValue); // If nothing is selected, or if the selectedValue doesn't match any
2340
- // item in the menu, use the placeholder.
2341
-
1883
+ const selectedItem = React.Children.toArray(children).find(option => option.props.value === selectedValue);
2342
1884
  const menuText = selectedItem ? selectedItem.props.label : placeholder;
2343
- const dropdownOpener = opener ? /*#__PURE__*/React.createElement(DropdownOpener, {
1885
+ const dropdownOpener = opener ? React.createElement(DropdownOpener, {
2344
1886
  onClick: this.handleClick,
2345
1887
  disabled: numItems === 0 || disabled,
2346
1888
  ref: this.handleOpenerRef,
2347
1889
  text: menuText
2348
- }, opener) : /*#__PURE__*/React.createElement(SelectOpener, _extends({}, sharedProps, {
1890
+ }, opener) : React.createElement(SelectOpener, _extends({}, sharedProps, {
2349
1891
  disabled: numItems === 0 || disabled,
2350
1892
  id: id,
2351
1893
  isPlaceholder: !selectedItem,
@@ -2376,7 +1918,7 @@ class SingleSelect extends React.Component {
2376
1918
  const opener = this.renderOpener(allChildren.length);
2377
1919
  const searchField = this.getSearchField();
2378
1920
  const items = searchField ? [searchField].concat(filteredItems) : filteredItems;
2379
- return /*#__PURE__*/React.createElement(DropdownCore$1, {
1921
+ return React.createElement(DropdownCore$1, {
2380
1922
  role: "listbox",
2381
1923
  alignment: alignment,
2382
1924
  dropdownStyle: [isFilterable && filterableDropdownStyle, selectDropdownStyle, dropdownStyle],
@@ -2402,15 +1944,6 @@ SingleSelect.defaultProps = {
2402
1944
  };
2403
1945
 
2404
1946
  const _excluded = ["disabled", "id", "light", "opener", "testId", "alignment", "dropdownStyle", "implicitAllEnabled", "isFilterable", "labels", "onChange", "onToggle", "opened", "selectedValues", "shortcuts", "style", "className"];
2405
-
2406
- /**
2407
- * A dropdown that consists of multiple selection items. This select allows
2408
- * multiple options to be selected. Clients are responsible for keeping track
2409
- * of the selected items.
2410
- *
2411
- * The multi select stays open until closed by the user. The onChange callback
2412
- * happens every time there is a change in the selection of the items.
2413
- */
2414
1947
  class MultiSelect extends React.Component {
2415
1948
  constructor(props) {
2416
1949
  super(props);
@@ -2438,7 +1971,6 @@ class MultiSelect extends React.Component {
2438
1971
  const updatedSelection = [].concat(selectedValues.slice(0, index), selectedValues.slice(index + 1));
2439
1972
  onChange(updatedSelection);
2440
1973
  } else {
2441
- // Item was newly selected
2442
1974
  onChange([].concat(selectedValues, [selectedValue]));
2443
1975
  }
2444
1976
  };
@@ -2499,18 +2031,11 @@ class MultiSelect extends React.Component {
2499
2031
  open: false,
2500
2032
  searchText: "",
2501
2033
  lastSelectedValues: [],
2502
- // merge custom labels with the default ones
2503
2034
  labels: _extends({}, defaultLabels, props.labels),
2504
2035
  openerElement: null
2505
- }; // merge custom labels with the default ones
2506
-
2036
+ };
2507
2037
  this.labels = _extends({}, defaultLabels, props.labels);
2508
2038
  }
2509
- /**
2510
- * Used to sync the `opened` state when this component acts as a controlled
2511
- * component
2512
- */
2513
-
2514
2039
 
2515
2040
  static getDerivedStateFromProps(props, state) {
2516
2041
  return {
@@ -2520,7 +2045,6 @@ class MultiSelect extends React.Component {
2520
2045
 
2521
2046
  componentDidUpdate(prevProps) {
2522
2047
  if (this.props.labels !== prevProps.labels) {
2523
- // eslint-disable-next-line react/no-did-update-set-state
2524
2048
  this.setState({
2525
2049
  labels: _extends({}, this.state.labels, this.props.labels)
2526
2050
  });
@@ -2536,9 +2060,7 @@ class MultiSelect extends React.Component {
2536
2060
  noneSelected,
2537
2061
  someSelected,
2538
2062
  allSelected
2539
- } = this.state.labels; // When implicit all enabled, use `labels.allSelected` when no selection
2540
- // otherwise, use the `labels.noneSelected` value
2541
-
2063
+ } = this.state.labels;
2542
2064
  const noSelectionText = implicitAllEnabled ? allSelected : noneSelected;
2543
2065
 
2544
2066
  switch (selectedValues.length) {
@@ -2546,9 +2068,6 @@ class MultiSelect extends React.Component {
2546
2068
  return noSelectionText;
2547
2069
 
2548
2070
  case 1:
2549
- // If there is one item selected, we display its label. If for
2550
- // some reason we can't find the selected item, we use the
2551
- // display text for the case where nothing is selected.
2552
2071
  const selectedItem = children.find(option => option.props.value === selectedValues[0]);
2553
2072
  return selectedItem ? selectedItem.props.label : noSelectionText;
2554
2073
 
@@ -2570,7 +2089,7 @@ class MultiSelect extends React.Component {
2570
2089
  filter
2571
2090
  } = this.state.labels;
2572
2091
  return [{
2573
- component: /*#__PURE__*/React.createElement(SearchTextInput, {
2092
+ component: React.createElement(SearchTextInput, {
2574
2093
  key: "search-text-input",
2575
2094
  onChange: this.handleSearchTextChanged,
2576
2095
  searchText: this.state.searchText,
@@ -2592,12 +2111,12 @@ class MultiSelect extends React.Component {
2592
2111
  const {
2593
2112
  selectAllLabel,
2594
2113
  selectNoneLabel
2595
- } = this.state.labels; // When there's search text input to filter, shortcuts should be hidden
2114
+ } = this.state.labels;
2596
2115
 
2597
2116
  if (shortcuts && !this.state.searchText) {
2598
2117
  const selectAllDisabled = numOptions === selectedValues.length;
2599
2118
  const selectAll = {
2600
- component: /*#__PURE__*/React.createElement(ActionItem, {
2119
+ component: React.createElement(ActionItem, {
2601
2120
  disabled: selectAllDisabled,
2602
2121
  label: selectAllLabel(numOptions),
2603
2122
  indent: true,
@@ -2608,7 +2127,7 @@ class MultiSelect extends React.Component {
2608
2127
  };
2609
2128
  const selectNoneDisabled = selectedValues.length === 0;
2610
2129
  const selectNone = {
2611
- component: /*#__PURE__*/React.createElement(ActionItem, {
2130
+ component: React.createElement(ActionItem, {
2612
2131
  disabled: selectNoneDisabled,
2613
2132
  label: selectNoneLabel,
2614
2133
  indent: true,
@@ -2618,7 +2137,7 @@ class MultiSelect extends React.Component {
2618
2137
  populatedProps: {}
2619
2138
  };
2620
2139
  const separator = {
2621
- component: /*#__PURE__*/React.createElement(SeparatorItem, {
2140
+ component: React.createElement(SeparatorItem, {
2622
2141
  key: "shortcuts-separator"
2623
2142
  }),
2624
2143
  focusable: false,
@@ -2633,8 +2152,7 @@ class MultiSelect extends React.Component {
2633
2152
  getMenuItems(children) {
2634
2153
  const {
2635
2154
  isFilterable
2636
- } = this.props; // If it's not filterable, no need to do any extra besides mapping the
2637
- // option items to dropdown items.
2155
+ } = this.props;
2638
2156
 
2639
2157
  if (!isFilterable) {
2640
2158
  return children.map(this.mapOptionItemToDropdownItem);
@@ -2644,8 +2162,7 @@ class MultiSelect extends React.Component {
2644
2162
  searchText,
2645
2163
  lastSelectedValues
2646
2164
  } = this.state;
2647
- const lowercasedSearchText = searchText.toLowerCase(); // Filter the children with the searchText if any.
2648
-
2165
+ const lowercasedSearchText = searchText.toLowerCase();
2649
2166
  const filteredChildren = children.filter(({
2650
2167
  props
2651
2168
  }) => !searchText || props.label.toLowerCase().indexOf(lowercasedSearchText) > -1);
@@ -2660,12 +2177,11 @@ class MultiSelect extends React.Component {
2660
2177
  }
2661
2178
  }
2662
2179
 
2663
- const lastSelectedItems = lastSelectedChildren.map(this.mapOptionItemToDropdownItem); // We want to add SeparatorItem in between last selected items and the
2664
- // rest of the items only when both of them exists.
2180
+ const lastSelectedItems = lastSelectedChildren.map(this.mapOptionItemToDropdownItem);
2665
2181
 
2666
2182
  if (lastSelectedChildren.length && restOfTheChildren.length) {
2667
2183
  lastSelectedItems.push({
2668
- component: /*#__PURE__*/React.createElement(SeparatorItem, {
2184
+ component: React.createElement(SeparatorItem, {
2669
2185
  key: "selected-separator"
2670
2186
  }),
2671
2187
  focusable: false,
@@ -2692,12 +2208,12 @@ class MultiSelect extends React.Component {
2692
2208
  } = this.state.labels;
2693
2209
  const menuText = this.getMenuText(allChildren);
2694
2210
  const numOptions = allChildren.length;
2695
- const dropdownOpener = opener ? /*#__PURE__*/React.createElement(DropdownOpener, {
2211
+ const dropdownOpener = opener ? React.createElement(DropdownOpener, {
2696
2212
  onClick: this.handleClick,
2697
2213
  disabled: numOptions === 0 || disabled,
2698
2214
  ref: this.handleOpenerRef,
2699
2215
  text: menuText
2700
- }, opener) : /*#__PURE__*/React.createElement(SelectOpener, _extends({}, sharedProps, {
2216
+ }, opener) : React.createElement(SelectOpener, _extends({}, sharedProps, {
2701
2217
  disabled: numOptions === 0 || disabled,
2702
2218
  id: id,
2703
2219
  isPlaceholder: menuText === noneSelected,
@@ -2731,7 +2247,7 @@ class MultiSelect extends React.Component {
2731
2247
  const numOptions = allChildren.length;
2732
2248
  const filteredItems = this.getMenuItems(allChildren);
2733
2249
  const opener = this.renderOpener(allChildren);
2734
- return /*#__PURE__*/React.createElement(DropdownCore$1, {
2250
+ return React.createElement(DropdownCore$1, {
2735
2251
  role: "listbox",
2736
2252
  alignment: alignment,
2737
2253
  dropdownStyle: [isFilterable && filterableDropdownStyle, selectDropdownStyle, dropdownStyle],