@khanacademy/wonder-blocks-dropdown 2.7.4 → 2.8.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.
Files changed (31) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/es/index.js +167 -167
  3. package/dist/index.js +389 -360
  4. package/package.json +7 -7
  5. package/src/components/__docs__/action-menu.argtypes.js +44 -0
  6. package/src/components/__docs__/action-menu.stories.js +435 -0
  7. package/src/components/__docs__/base-select.argtypes.js +54 -0
  8. package/src/components/__docs__/multi-select.stories.js +509 -0
  9. package/src/components/__docs__/single-select.accessibility.stories.mdx +59 -0
  10. package/src/components/__docs__/single-select.argtypes.js +54 -0
  11. package/src/components/__docs__/single-select.stories.js +464 -0
  12. package/src/components/__tests__/dropdown-core-virtualized.test.js +0 -15
  13. package/src/components/__tests__/dropdown-core.test.js +113 -209
  14. package/src/components/__tests__/multi-select.test.js +49 -3
  15. package/src/components/__tests__/single-select.test.js +43 -50
  16. package/src/components/action-menu.js +11 -0
  17. package/src/components/dropdown-core-virtualized.js +0 -5
  18. package/src/components/dropdown-core.js +224 -130
  19. package/src/components/multi-select.js +18 -33
  20. package/src/components/single-select.js +16 -30
  21. package/src/util/__tests__/dropdown-menu-styles.test.js +0 -26
  22. package/src/util/__tests__/helpers.test.js +73 -0
  23. package/src/util/constants.js +0 -11
  24. package/src/util/dropdown-menu-styles.js +0 -5
  25. package/src/util/helpers.js +44 -0
  26. package/src/util/types.js +2 -5
  27. package/src/components/__tests__/search-text-input.test.js +0 -212
  28. package/src/components/action-menu.stories.js +0 -48
  29. package/src/components/multi-select.stories.js +0 -124
  30. package/src/components/search-text-input.js +0 -115
  31. package/src/components/single-select.stories.js +0 -247
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @khanacademy/wonder-blocks-dropdown
2
2
 
3
+ ## 2.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ee6fc773: Added keyboard support to search items when the dropdown is focused, included "Enter" as a key to trigger actions with the "option" role
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [ee6fc773]
12
+ - @khanacademy/wonder-blocks-clickable@2.3.0
13
+ - @khanacademy/wonder-blocks-button@3.0.1
14
+ - @khanacademy/wonder-blocks-icon-button@3.4.9
15
+ - @khanacademy/wonder-blocks-modal@2.3.4
16
+ - @khanacademy/wonder-blocks-search-field@1.0.7
17
+
18
+ ## 2.7.6
19
+
20
+ ### Patch Changes
21
+
22
+ - 3007ecd7: Move the search field out of the listbox container
23
+
24
+ ## 2.7.5
25
+
26
+ ### Patch Changes
27
+
28
+ - Updated dependencies [85c31780]
29
+ - @khanacademy/wonder-blocks-button@3.0.0
30
+
3
31
  ## 2.7.4
4
32
 
5
33
  ### Patch Changes
package/dist/es/index.js CHANGED
@@ -12,8 +12,8 @@ import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/objectWithoutP
12
12
  import Icon, { icons } from '@khanacademy/wonder-blocks-icon';
13
13
  import ReactDOM from 'react-dom';
14
14
  import { VariableSizeList } from 'react-window';
15
- import { withActionScheduler } from '@khanacademy/wonder-blocks-timing';
16
15
  import SearchField from '@khanacademy/wonder-blocks-search-field';
16
+ import { withActionScheduler } from '@khanacademy/wonder-blocks-timing';
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';
@@ -33,15 +33,9 @@ const selectDropdownStyle = {
33
33
  const filterableDropdownStyle = {
34
34
  minHeight: 100
35
35
  };
36
- const searchInputStyle = {
37
- margin: Spacing.xSmall_8,
38
- marginTop: Spacing.xxxSmall_4,
39
- minHeight: "auto"
40
- };
41
36
  const DROPDOWN_ITEM_HEIGHT = 40;
42
37
  const MAX_VISIBLE_ITEMS = 9;
43
38
  const SEPARATOR_ITEM_HEIGHT = 9;
44
- const SEARCH_ITEM_HEIGHT = DROPDOWN_ITEM_HEIGHT + searchInputStyle.margin + searchInputStyle.marginTop;
45
39
  const defaultLabels = {
46
40
  clearSearch: "Clear search",
47
41
  filter: "Filter",
@@ -487,56 +481,10 @@ class DropdownVirtualizedItem extends React.Component {
487
481
 
488
482
  }
489
483
 
490
- class SearchTextInput extends React.Component {
491
- static isClassOf(instance) {
492
- return instance && instance.type && instance.type.__IS_SEARCH_TEXT_INPUT__;
493
- }
494
-
495
- componentDidMount() {
496
- if (this.props.autofocus) {
497
- var _this$props$itemRef;
498
-
499
- (_this$props$itemRef = this.props.itemRef) == null ? void 0 : _this$props$itemRef.current.focus();
500
- }
501
- }
502
-
503
- render() {
504
- const {
505
- labels,
506
- onChange,
507
- onClick,
508
- itemRef,
509
- searchText,
510
- style,
511
- testId
512
- } = this.props;
513
- return React.createElement(SearchField, {
514
- clearAriaLabel: labels.clearSearch,
515
- onChange: onChange,
516
- onClick: onClick,
517
- placeholder: labels.filter,
518
- ref: itemRef,
519
- style: style,
520
- testId: testId,
521
- value: searchText
522
- });
523
- }
524
-
525
- }
526
- SearchTextInput.defaultProps = {
527
- labels: {
528
- clearSearch: defaultLabels.clearSearch,
529
- filter: defaultLabels.filter
530
- }
531
- };
532
- SearchTextInput.__IS_SEARCH_TEXT_INPUT__ = true;
533
-
534
484
  function getDropdownMenuHeight(items, initialHeight = 0) {
535
485
  return items.slice(0, MAX_VISIBLE_ITEMS).reduce((sum, item) => {
536
486
  if (SeparatorItem.isClassOf(item.component)) {
537
487
  return sum + SEPARATOR_ITEM_HEIGHT;
538
- } else if (SearchTextInput.isClassOf(item.component)) {
539
- return sum + SEARCH_ITEM_HEIGHT;
540
488
  } else {
541
489
  return sum + DROPDOWN_ITEM_HEIGHT;
542
490
  }
@@ -561,8 +509,6 @@ class DropdownCoreVirtualized extends React.Component {
561
509
 
562
510
  if (SeparatorItem.isClassOf(item.component)) {
563
511
  return SEPARATOR_ITEM_HEIGHT;
564
- } else if (SearchTextInput.isClassOf(item.component)) {
565
- return SEARCH_ITEM_HEIGHT;
566
512
  } else {
567
513
  return DROPDOWN_ITEM_HEIGHT;
568
514
  }
@@ -718,6 +664,26 @@ function DropdownPopper({
718
664
  }), modalHost);
719
665
  }
720
666
 
667
+ function getStringForKey(key) {
668
+ if (key.length === 1 || !/^[A-Z]/i.test(key)) {
669
+ return key;
670
+ }
671
+
672
+ return "";
673
+ }
674
+ function debounce(callback, wait) {
675
+ let timeout;
676
+ return function executedFunction(...args) {
677
+ const later = () => {
678
+ clearTimeout(timeout);
679
+ callback.apply(void 0, args);
680
+ };
681
+
682
+ clearTimeout(timeout);
683
+ timeout = setTimeout(later, wait);
684
+ };
685
+ }
686
+
721
687
  const VIRTUALIZE_THRESHOLD = 125;
722
688
  const StyledSpan = addStyle("span");
723
689
 
@@ -765,6 +731,7 @@ class DropdownCore extends React.Component {
765
731
 
766
732
  constructor(props) {
767
733
  super(props);
734
+ this.searchFieldRef = React.createRef();
768
735
 
769
736
  this.handleInteract = event => {
770
737
  const {
@@ -787,6 +754,12 @@ class DropdownCore extends React.Component {
787
754
  } = this.props;
788
755
  const keyCode = event.which || event.keyCode;
789
756
 
757
+ if (getStringForKey(event.key)) {
758
+ event.stopPropagation();
759
+ this.textSuggestion += event.key;
760
+ this.handleKeyDownDebounced(this.textSuggestion);
761
+ }
762
+
790
763
  if (!open) {
791
764
  if (keyCode === keyCodes.down) {
792
765
  event.preventDefault();
@@ -799,7 +772,7 @@ class DropdownCore extends React.Component {
799
772
 
800
773
  switch (keyCode) {
801
774
  case keyCodes.tab:
802
- if (this.hasSearchBox() && this.focusedIndex === 0 && searchText) {
775
+ if (this.isSearchFieldFocused() && searchText) {
803
776
  return;
804
777
  }
805
778
 
@@ -808,7 +781,7 @@ class DropdownCore extends React.Component {
808
781
  return;
809
782
 
810
783
  case keyCodes.space:
811
- if (this.hasSearchBox() && this.focusedIndex === 0) {
784
+ if (this.isSearchFieldFocused()) {
812
785
  return;
813
786
  }
814
787
 
@@ -836,7 +809,7 @@ class DropdownCore extends React.Component {
836
809
 
837
810
  switch (keyCode) {
838
811
  case keyCodes.space:
839
- if (this.hasSearchBox() && this.focusedIndex === 0) {
812
+ if (this.isSearchFieldFocused()) {
840
813
  return;
841
814
  }
842
815
 
@@ -854,6 +827,39 @@ class DropdownCore extends React.Component {
854
827
  }
855
828
  };
856
829
 
830
+ this.handleKeyDownDebounceResult = key => {
831
+ const foundIndex = this.props.items.filter(item => item.focusable).findIndex(({
832
+ component
833
+ }) => {
834
+ var _component$props;
835
+
836
+ if (SeparatorItem.isClassOf(component)) {
837
+ return false;
838
+ }
839
+
840
+ const label = (_component$props = component.props) == null ? void 0 : _component$props.label.toLowerCase();
841
+ return label.startsWith(key.toLowerCase());
842
+ });
843
+
844
+ if (foundIndex >= 0) {
845
+ const isClosed = !this.props.open;
846
+
847
+ if (isClosed) {
848
+ this.props.onOpenChanged(true);
849
+ }
850
+
851
+ this.focusedIndex = foundIndex;
852
+ this.scheduleToFocusCurrentItem(node => {
853
+ if (this.props.selectionType === "single" && isClosed && node) {
854
+ node.click();
855
+ this.props.onOpenChanged(false);
856
+ }
857
+ });
858
+ }
859
+
860
+ this.textSuggestion = "";
861
+ };
862
+
857
863
  this.handleClickFocus = index => {
858
864
  this.itemsClicked = true;
859
865
  this.focusedIndex = index;
@@ -880,6 +886,16 @@ class DropdownCore extends React.Component {
880
886
  }
881
887
  };
882
888
 
889
+ this.handleSearchTextChanged = searchText => {
890
+ const {
891
+ onSearchTextChanged
892
+ } = this.props;
893
+
894
+ if (onSearchTextChanged) {
895
+ onSearchTextChanged(searchText);
896
+ }
897
+ };
898
+
883
899
  this.resetFocusedIndex();
884
900
  this.state = {
885
901
  prevItems: this.props.items,
@@ -890,6 +906,8 @@ class DropdownCore extends React.Component {
890
906
  }, props.labels)
891
907
  };
892
908
  this.virtualizedListRef = React.createRef();
909
+ this.handleKeyDownDebounced = debounce(this.handleKeyDownDebounceResult, 500);
910
+ this.textSuggestion = "";
893
911
  }
894
912
 
895
913
  componentDidMount() {
@@ -937,22 +955,18 @@ class DropdownCore extends React.Component {
937
955
  this.removeEventListeners();
938
956
  }
939
957
 
940
- hasSearchBox() {
941
- return !!this.props.onSearchTextChanged && typeof this.props.searchText === "string";
942
- }
943
-
944
958
  resetFocusedIndex() {
945
959
  const {
946
960
  initialFocusedIndex
947
961
  } = this.props;
948
962
 
949
- if (initialFocusedIndex) {
950
- if (this.hasSearchBox()) {
951
- this.focusedIndex = initialFocusedIndex + 1;
952
- } else {
953
- this.focusedIndex = initialFocusedIndex;
954
- }
963
+ if (typeof initialFocusedIndex !== "undefined") {
964
+ this.focusedIndex = initialFocusedIndex;
955
965
  } else {
966
+ if (this.hasSearchField() && !this.isSearchFieldFocused()) {
967
+ return this.focusSearchField();
968
+ }
969
+
956
970
  this.focusedIndex = 0;
957
971
  }
958
972
  }
@@ -988,33 +1002,57 @@ class DropdownCore extends React.Component {
988
1002
  document.removeEventListener("touchend", this.handleInteract);
989
1003
  }
990
1004
 
991
- scheduleToFocusCurrentItem() {
1005
+ scheduleToFocusCurrentItem(onFocus) {
992
1006
  if (this.shouldVirtualizeList()) {
993
- this.props.schedule.animationFrame(() => this.focusCurrentItem());
1007
+ this.props.schedule.animationFrame(() => {
1008
+ this.focusCurrentItem(onFocus);
1009
+ });
994
1010
  } else {
995
- this.focusCurrentItem();
1011
+ this.focusCurrentItem(onFocus);
996
1012
  }
997
1013
  }
998
1014
 
999
- focusCurrentItem() {
1000
- const fousedItemRef = this.state.itemRefs[this.focusedIndex];
1015
+ focusCurrentItem(onFocus) {
1016
+ const focusedItemRef = this.state.itemRefs[this.focusedIndex];
1001
1017
 
1002
- if (fousedItemRef) {
1018
+ if (focusedItemRef) {
1003
1019
  if (this.virtualizedListRef.current) {
1004
- this.virtualizedListRef.current.scrollToItem(fousedItemRef.originalIndex);
1020
+ this.virtualizedListRef.current.scrollToItem(focusedItemRef.originalIndex);
1005
1021
  }
1006
1022
 
1007
- const node = ReactDOM.findDOMNode(fousedItemRef.ref.current);
1023
+ const node = ReactDOM.findDOMNode(focusedItemRef.ref.current);
1008
1024
 
1009
1025
  if (node) {
1010
1026
  node.focus();
1011
- this.focusedOriginalIndex = fousedItemRef.originalIndex;
1027
+ this.focusedOriginalIndex = focusedItemRef.originalIndex;
1028
+
1029
+ if (onFocus) {
1030
+ onFocus(node);
1031
+ }
1012
1032
  }
1013
1033
  }
1014
1034
  }
1015
1035
 
1036
+ focusSearchField() {
1037
+ if (this.searchFieldRef.current) {
1038
+ this.searchFieldRef.current.focus();
1039
+ }
1040
+ }
1041
+
1042
+ hasSearchField() {
1043
+ return !!this.props.isFilterable;
1044
+ }
1045
+
1046
+ isSearchFieldFocused() {
1047
+ return this.hasSearchField() && document.activeElement === this.searchFieldRef.current;
1048
+ }
1049
+
1016
1050
  focusPreviousItem() {
1017
1051
  if (this.focusedIndex === 0) {
1052
+ if (this.hasSearchField() && !this.isSearchFieldFocused()) {
1053
+ return this.focusSearchField();
1054
+ }
1055
+
1018
1056
  this.focusedIndex = this.state.itemRefs.length - 1;
1019
1057
  } else {
1020
1058
  this.focusedIndex -= 1;
@@ -1025,6 +1063,10 @@ class DropdownCore extends React.Component {
1025
1063
 
1026
1064
  focusNextItem() {
1027
1065
  if (this.focusedIndex === this.state.itemRefs.length - 1) {
1066
+ if (this.hasSearchField() && !this.isSearchFieldFocused()) {
1067
+ return this.focusSearchField();
1068
+ }
1069
+
1028
1070
  this.focusedIndex = 0;
1029
1071
  } else {
1030
1072
  this.focusedIndex += 1;
@@ -1059,15 +1101,11 @@ class DropdownCore extends React.Component {
1059
1101
  maybeRenderNoResults() {
1060
1102
  const {
1061
1103
  items,
1062
- onSearchTextChanged,
1063
- searchText,
1064
1104
  labels: {
1065
1105
  noResults
1066
1106
  }
1067
1107
  } = this.props;
1068
- const showSearchTextInput = !!onSearchTextChanged && typeof searchText === "string";
1069
- const includeSearchCount = showSearchTextInput ? 1 : 0;
1070
- const numResults = items.length - includeSearchCount;
1108
+ const numResults = items.length;
1071
1109
 
1072
1110
  if (numResults === 0) {
1073
1111
  return React.createElement(LabelMedium, {
@@ -1103,20 +1141,6 @@ class DropdownCore extends React.Component {
1103
1141
 
1104
1142
  const focusIndex = focusCounter - 1;
1105
1143
  const currentRef = this.state.itemRefs[focusIndex] ? this.state.itemRefs[focusIndex].ref : null;
1106
-
1107
- if (SearchTextInput.isClassOf(component)) {
1108
- return React.cloneElement(component, _extends({}, populatedProps, {
1109
- key: "search-text-input",
1110
- itemRef: currentRef,
1111
- onClick: () => {
1112
- this.handleClickFocus(0);
1113
- this.focusCurrentItem();
1114
- },
1115
- style: searchInputStyle,
1116
- autofocus: this.focusedIndex === 0
1117
- }));
1118
- }
1119
-
1120
1144
  return React.cloneElement(component, _extends({}, populatedProps, {
1121
1145
  key: index,
1122
1146
  onClick: () => {
@@ -1137,21 +1161,6 @@ class DropdownCore extends React.Component {
1137
1161
  }
1138
1162
 
1139
1163
  const focusIndex = focusCounter - 1;
1140
-
1141
- if (SearchTextInput.isClassOf(item.component)) {
1142
- return _extends({}, item, {
1143
- onClick: () => {
1144
- this.handleClickFocus(0);
1145
- this.focusCurrentItem();
1146
- },
1147
- populatedProps: {
1148
- style: searchInputStyle,
1149
- itemRef: this.state.itemRefs[focusIndex] ? this.state.itemRefs[focusIndex].ref : null,
1150
- autofocus: this.focusedIndex === 0
1151
- }
1152
- });
1153
- }
1154
-
1155
1164
  return _extends({}, item, {
1156
1165
  role: itemRole,
1157
1166
  ref: item.focusable ? this.state.itemRefs[focusIndex] ? this.state.itemRefs[focusIndex].ref : null : null,
@@ -1170,6 +1179,23 @@ class DropdownCore extends React.Component {
1170
1179
  });
1171
1180
  }
1172
1181
 
1182
+ renderSearchField() {
1183
+ const {
1184
+ searchText
1185
+ } = this.props;
1186
+ const {
1187
+ labels
1188
+ } = this.state;
1189
+ return React.createElement(SearchField, {
1190
+ clearAriaLabel: labels.clearSearch,
1191
+ onChange: this.handleSearchTextChanged,
1192
+ placeholder: labels.filter,
1193
+ ref: this.searchFieldRef,
1194
+ style: styles$3.searchInputStyle,
1195
+ value: searchText || ""
1196
+ });
1197
+ }
1198
+
1173
1199
  renderDropdownMenu(listRenderer, isReferenceHidden) {
1174
1200
  const {
1175
1201
  dropdownStyle,
@@ -1178,13 +1204,15 @@ class DropdownCore extends React.Component {
1178
1204
  } = this.props;
1179
1205
  const openerStyle = openerElement && window.getComputedStyle(openerElement);
1180
1206
  const minDropdownWidth = openerStyle ? openerStyle.getPropertyValue("width") : 0;
1181
- const initialHeight = 12;
1182
- const maxDropdownHeight = getDropdownMenuHeight(this.props.items, initialHeight);
1207
+ const maxDropdownHeight = getDropdownMenuHeight(this.props.items);
1183
1208
  return React.createElement(View, {
1184
1209
  onMouseUp: this.handleDropdownMouseUp,
1210
+ style: [styles$3.dropdown, light && styles$3.light, isReferenceHidden && styles$3.hidden, dropdownStyle],
1211
+ testId: "dropdown-core-container"
1212
+ }, this.props.isFilterable && this.renderSearchField(), React.createElement(View, {
1185
1213
  role: this.props.role,
1186
- style: [styles$3.dropdown, light && styles$3.light, isReferenceHidden && styles$3.hidden, generateDropdownMenuStyles(minDropdownWidth, maxDropdownHeight), dropdownStyle]
1187
- }, listRenderer, this.maybeRenderNoResults());
1214
+ style: [styles$3.listboxOrMenu, generateDropdownMenuStyles(minDropdownWidth, maxDropdownHeight)]
1215
+ }, listRenderer), this.maybeRenderNoResults());
1188
1216
  }
1189
1217
 
1190
1218
  renderDropdown() {
@@ -1210,7 +1238,7 @@ class DropdownCore extends React.Component {
1210
1238
  const {
1211
1239
  labels
1212
1240
  } = this.state;
1213
- const totalItems = this.hasSearchBox() ? items.length - 1 : items.length;
1241
+ const totalItems = items.length;
1214
1242
  return React.createElement(StyledSpan, {
1215
1243
  "aria-live": "polite",
1216
1244
  "aria-atomic": "true",
@@ -1240,10 +1268,13 @@ class DropdownCore extends React.Component {
1240
1268
  DropdownCore.defaultProps = {
1241
1269
  alignment: "left",
1242
1270
  labels: {
1271
+ clearSearch: defaultLabels.clearSearch,
1272
+ filter: defaultLabels.filter,
1243
1273
  noResults: defaultLabels.noResults,
1244
1274
  someSelected: defaultLabels.someSelected
1245
1275
  },
1246
- light: false
1276
+ light: false,
1277
+ selectionType: "single"
1247
1278
  };
1248
1279
  const styles$3 = StyleSheet.create({
1249
1280
  menuWrapper: {
@@ -1255,12 +1286,14 @@ const styles$3 = StyleSheet.create({
1255
1286
  paddingTop: Spacing.xxxSmall_4,
1256
1287
  paddingBottom: Spacing.xxxSmall_4,
1257
1288
  border: `solid 1px ${Color.offBlack16}`,
1258
- boxShadow: `0px 8px 8px 0px ${fade(Color.offBlack, 0.1)}`,
1259
- overflowY: "auto"
1289
+ boxShadow: `0px 8px 8px 0px ${fade(Color.offBlack, 0.1)}`
1260
1290
  },
1261
1291
  light: {
1262
1292
  border: "none"
1263
1293
  },
1294
+ listboxOrMenu: {
1295
+ overflowY: "auto"
1296
+ },
1264
1297
  hidden: {
1265
1298
  pointerEvents: "none",
1266
1299
  visibility: "hidden"
@@ -1270,6 +1303,11 @@ const styles$3 = StyleSheet.create({
1270
1303
  alignSelf: "center",
1271
1304
  marginTop: Spacing.xxSmall_6
1272
1305
  },
1306
+ searchInputStyle: {
1307
+ margin: Spacing.xSmall_8,
1308
+ marginTop: Spacing.xxxSmall_4,
1309
+ minHeight: "auto"
1310
+ },
1273
1311
  srOnly: {
1274
1312
  border: 0,
1275
1313
  clip: "rect(0,0,0,0)",
@@ -1887,26 +1925,6 @@ class SingleSelect extends React.Component {
1887
1925
  return this.mapOptionItemsToDropdownItems(isFilterable ? this.filterChildren(children) : children);
1888
1926
  }
1889
1927
 
1890
- getSearchField() {
1891
- if (!this.props.isFilterable) {
1892
- return null;
1893
- }
1894
-
1895
- return {
1896
- component: React.createElement(SearchTextInput, {
1897
- key: "search-text-input",
1898
- onChange: this.handleSearchTextChanged,
1899
- searchText: this.state.searchText,
1900
- labels: {
1901
- clearSearch: defaultLabels.clearSearch,
1902
- filter: defaultLabels.filter
1903
- }
1904
- }),
1905
- focusable: true,
1906
- populatedProps: {}
1907
- };
1908
- }
1909
-
1910
1928
  renderOpener(numItems) {
1911
1929
  const _this$props = this.props,
1912
1930
  {
@@ -1955,12 +1973,11 @@ class SingleSelect extends React.Component {
1955
1973
  searchText
1956
1974
  } = this.state;
1957
1975
  const allChildren = React.Children.toArray(children).filter(Boolean);
1958
- const filteredItems = this.getMenuItems(allChildren);
1976
+ const items = this.getMenuItems(allChildren);
1959
1977
  const opener = this.renderOpener(allChildren.length);
1960
- const searchField = this.getSearchField();
1961
- const items = searchField ? [searchField].concat(filteredItems) : filteredItems;
1962
1978
  return React.createElement(DropdownCore$1, {
1963
1979
  role: "listbox",
1980
+ selectionType: "single",
1964
1981
  alignment: alignment,
1965
1982
  dropdownStyle: [isFilterable && filterableDropdownStyle, selectDropdownStyle, dropdownStyle],
1966
1983
  initialFocusedIndex: this.selectedIndex,
@@ -1972,6 +1989,7 @@ class SingleSelect extends React.Component {
1972
1989
  openerElement: this.state.openerElement,
1973
1990
  style: style,
1974
1991
  className: className,
1992
+ isFilterable: isFilterable,
1975
1993
  onSearchTextChanged: isFilterable ? this.handleSearchTextChanged : null,
1976
1994
  searchText: isFilterable ? searchText : ""
1977
1995
  });
@@ -2120,30 +2138,6 @@ class MultiSelect extends React.Component {
2120
2138
  }
2121
2139
  }
2122
2140
 
2123
- getSearchField() {
2124
- if (!this.props.isFilterable) {
2125
- return [];
2126
- }
2127
-
2128
- const {
2129
- clearSearch,
2130
- filter
2131
- } = this.state.labels;
2132
- return [{
2133
- component: React.createElement(SearchTextInput, {
2134
- key: "search-text-input",
2135
- onChange: this.handleSearchTextChanged,
2136
- searchText: this.state.searchText,
2137
- labels: {
2138
- clearSearch,
2139
- filter
2140
- }
2141
- }),
2142
- focusable: true,
2143
- populatedProps: {}
2144
- }];
2145
- }
2146
-
2147
2141
  getShortcuts(numOptions) {
2148
2142
  const {
2149
2143
  selectedValues,
@@ -2282,6 +2276,8 @@ class MultiSelect extends React.Component {
2282
2276
  searchText
2283
2277
  } = this.state;
2284
2278
  const {
2279
+ clearSearch,
2280
+ filter,
2285
2281
  noResults,
2286
2282
  someSelected
2287
2283
  } = this.state.labels;
@@ -2293,17 +2289,21 @@ class MultiSelect extends React.Component {
2293
2289
  role: "listbox",
2294
2290
  alignment: alignment,
2295
2291
  dropdownStyle: [isFilterable && filterableDropdownStyle, selectDropdownStyle, dropdownStyle],
2296
- items: [].concat(this.getSearchField(), this.getShortcuts(numOptions), filteredItems),
2292
+ isFilterable: isFilterable,
2293
+ items: [].concat(this.getShortcuts(numOptions), filteredItems),
2297
2294
  light: light,
2298
2295
  onOpenChanged: this.handleOpenChanged,
2299
2296
  open: open,
2300
2297
  opener: opener,
2301
2298
  openerElement: this.state.openerElement,
2299
+ selectionType: "multi",
2302
2300
  style: style,
2303
2301
  className: className,
2304
2302
  onSearchTextChanged: isFilterable ? this.handleSearchTextChanged : null,
2305
2303
  searchText: isFilterable ? searchText : "",
2306
2304
  labels: {
2305
+ clearSearch,
2306
+ filter,
2307
2307
  noResults,
2308
2308
  someSelected
2309
2309
  }