@itwin/itwinui-react 1.38.0 → 1.40.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 (106) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/cjs/core/Carousel/Carousel.js +21 -12
  3. package/cjs/core/Carousel/CarouselContext.d.ts +4 -2
  4. package/cjs/core/Carousel/CarouselDotsList.js +1 -0
  5. package/cjs/core/Carousel/CarouselNavigation.js +8 -10
  6. package/cjs/core/Carousel/CarouselSlide.js +3 -7
  7. package/cjs/core/Carousel/CarouselSlider.js +23 -28
  8. package/cjs/core/ColorPicker/ColorPickerContext.d.ts +2 -2
  9. package/cjs/core/ComboBox/ComboBox.d.ts +17 -1
  10. package/cjs/core/ComboBox/ComboBox.js +50 -24
  11. package/cjs/core/ComboBox/ComboBoxDropdown.d.ts +5 -6
  12. package/cjs/core/ComboBox/ComboBoxInput.js +28 -9
  13. package/cjs/core/ComboBox/ComboBoxMenu.js +46 -2
  14. package/cjs/core/ComboBox/ComboBoxMenuItem.js +2 -3
  15. package/cjs/core/ComboBox/helpers.d.ts +8 -3
  16. package/cjs/core/ComboBox/helpers.js +1 -1
  17. package/cjs/core/DatePicker/DatePicker.d.ts +1 -1
  18. package/cjs/core/Menu/MenuItemSkeleton.d.ts +32 -0
  19. package/cjs/core/Menu/MenuItemSkeleton.js +53 -0
  20. package/cjs/core/Menu/index.d.ts +2 -0
  21. package/cjs/core/Menu/index.js +3 -1
  22. package/cjs/core/Select/Select.js +1 -1
  23. package/cjs/core/Table/Table.js +68 -25
  24. package/cjs/core/Table/TableCell.js +10 -3
  25. package/cjs/core/Table/TablePaginator.js +1 -1
  26. package/cjs/core/Table/TableRowMemoized.js +5 -1
  27. package/cjs/core/Table/actionHandlers/resizeHandler.d.ts +8 -0
  28. package/cjs/core/Table/actionHandlers/selectHandler.d.ts +4 -0
  29. package/cjs/core/Table/columns/selectionColumn.js +4 -2
  30. package/cjs/core/Table/filters/tableFilters.d.ts +3 -3
  31. package/cjs/core/Table/hooks/index.d.ts +1 -0
  32. package/cjs/core/Table/hooks/index.js +3 -1
  33. package/cjs/core/Table/hooks/useExpanderCell.js +11 -1
  34. package/cjs/core/Table/hooks/useStickyColumns.d.ts +2 -0
  35. package/cjs/core/Table/hooks/useStickyColumns.js +84 -0
  36. package/cjs/core/Table/utils.d.ts +1 -0
  37. package/cjs/core/Table/utils.js +36 -1
  38. package/cjs/core/Toast/Toaster.d.ts +1 -1
  39. package/cjs/core/Toast/Toaster.js +72 -29
  40. package/cjs/core/index.d.ts +2 -2
  41. package/cjs/core/index.js +4 -3
  42. package/cjs/core/utils/components/Popover.d.ts +1 -18
  43. package/cjs/core/utils/components/VirtualScroll.d.ts +35 -1
  44. package/cjs/core/utils/components/VirtualScroll.js +159 -26
  45. package/cjs/core/utils/components/VisuallyHidden.d.ts +9 -0
  46. package/cjs/core/utils/components/VisuallyHidden.js +44 -0
  47. package/cjs/core/utils/components/WithCSSTransition.d.ts +1 -2
  48. package/cjs/core/utils/components/icons.d.ts +4 -4
  49. package/cjs/core/utils/components/index.d.ts +1 -0
  50. package/cjs/core/utils/components/index.js +1 -0
  51. package/cjs/core/utils/hooks/useOverflow.js +4 -2
  52. package/cjs/core/utils/hooks/useTheme.d.ts +1 -1
  53. package/cjs/types/react-table-config.d.ts +9 -0
  54. package/esm/core/Carousel/Carousel.js +21 -12
  55. package/esm/core/Carousel/CarouselContext.d.ts +4 -2
  56. package/esm/core/Carousel/CarouselDotsList.js +1 -0
  57. package/esm/core/Carousel/CarouselNavigation.js +8 -10
  58. package/esm/core/Carousel/CarouselSlide.js +3 -7
  59. package/esm/core/Carousel/CarouselSlider.js +24 -29
  60. package/esm/core/ColorPicker/ColorPickerContext.d.ts +2 -2
  61. package/esm/core/ComboBox/ComboBox.d.ts +17 -1
  62. package/esm/core/ComboBox/ComboBox.js +50 -24
  63. package/esm/core/ComboBox/ComboBoxDropdown.d.ts +5 -6
  64. package/esm/core/ComboBox/ComboBoxInput.js +28 -9
  65. package/esm/core/ComboBox/ComboBoxMenu.js +47 -3
  66. package/esm/core/ComboBox/ComboBoxMenuItem.js +2 -3
  67. package/esm/core/ComboBox/helpers.d.ts +8 -3
  68. package/esm/core/ComboBox/helpers.js +1 -1
  69. package/esm/core/DatePicker/DatePicker.d.ts +1 -1
  70. package/esm/core/Menu/MenuItemSkeleton.d.ts +32 -0
  71. package/esm/core/Menu/MenuItemSkeleton.js +46 -0
  72. package/esm/core/Menu/index.d.ts +2 -0
  73. package/esm/core/Menu/index.js +1 -0
  74. package/esm/core/Select/Select.js +1 -1
  75. package/esm/core/Table/Table.js +70 -27
  76. package/esm/core/Table/TableCell.js +11 -4
  77. package/esm/core/Table/TablePaginator.js +1 -1
  78. package/esm/core/Table/TableRowMemoized.js +5 -1
  79. package/esm/core/Table/actionHandlers/resizeHandler.d.ts +8 -0
  80. package/esm/core/Table/actionHandlers/selectHandler.d.ts +4 -0
  81. package/esm/core/Table/columns/selectionColumn.js +4 -2
  82. package/esm/core/Table/filters/tableFilters.d.ts +3 -3
  83. package/esm/core/Table/hooks/index.d.ts +1 -0
  84. package/esm/core/Table/hooks/index.js +1 -0
  85. package/esm/core/Table/hooks/useExpanderCell.js +8 -1
  86. package/esm/core/Table/hooks/useStickyColumns.d.ts +2 -0
  87. package/esm/core/Table/hooks/useStickyColumns.js +80 -0
  88. package/esm/core/Table/utils.d.ts +1 -0
  89. package/esm/core/Table/utils.js +34 -0
  90. package/esm/core/Toast/Toaster.d.ts +1 -1
  91. package/esm/core/Toast/Toaster.js +50 -30
  92. package/esm/core/index.d.ts +2 -2
  93. package/esm/core/index.js +1 -1
  94. package/esm/core/utils/components/Popover.d.ts +1 -18
  95. package/esm/core/utils/components/VirtualScroll.d.ts +35 -1
  96. package/esm/core/utils/components/VirtualScroll.js +157 -25
  97. package/esm/core/utils/components/VisuallyHidden.d.ts +9 -0
  98. package/esm/core/utils/components/VisuallyHidden.js +38 -0
  99. package/esm/core/utils/components/WithCSSTransition.d.ts +1 -2
  100. package/esm/core/utils/components/icons.d.ts +4 -4
  101. package/esm/core/utils/components/index.d.ts +1 -0
  102. package/esm/core/utils/components/index.js +1 -0
  103. package/esm/core/utils/hooks/useOverflow.js +4 -2
  104. package/esm/core/utils/hooks/useTheme.d.ts +1 -1
  105. package/esm/types/react-table-config.d.ts +9 -0
  106. package/package.json +24 -39
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.40.0](https://www.github.com/iTwin/iTwinUI-react/compare/v1.39.0...v1.40.0) (2022-06-10)
4
+
5
+ ### What's new
6
+
7
+ * **Combobox:** Loading state with skeletons ([#655](https://www.github.com/iTwin/iTwinUI-react/issues/655)) ([cc1c7fb](https://www.github.com/iTwin/iTwinUI-react/commit/cc1c7fb6b5c494c94c01fe06483b788e0a27ec36))
8
+ * **Table:** Add sticky columns feature ([#695](https://www.github.com/iTwin/iTwinUI-react/issues/695)) ([eb6b0c0](https://www.github.com/iTwin/iTwinUI-react/commit/eb6b0c03e83b6e1417a444901c033a52545de186))
9
+
10
+ ### Fixes
11
+
12
+ * **Table:** Overriding min-width for the whole table ([#706](https://www.github.com/iTwin/iTwinUI-react/issues/706)) ([ad8173b](https://www.github.com/iTwin/iTwinUI-react/commit/ad8173b5764277a06a4b87a408e80affb2271749))
13
+ * **Table:** Removed title from selection checkboxes ([#704](https://www.github.com/iTwin/iTwinUI-react/issues/704)) ([5f72e59](https://www.github.com/iTwin/iTwinUI-react/commit/5f72e59a6d6e66b5f69c30ad82f7b37017242df6))
14
+
15
+ ## [1.39.0](https://www.github.com/iTwin/iTwinUI-react/compare/v1.38.0...v1.39.0) (2022-06-03)
16
+
17
+ ### What's new
18
+
19
+ * Add support of react 18 ([#656](https://www.github.com/iTwin/iTwinUI-react/issues/656)) ([b7a4c7b](https://www.github.com/iTwin/iTwinUI-react/commit/b7a4c7ba1e26445308dcb7f1fd5a374743de4e6f))
20
+ * **Combobox:** Virtualization ([#539](https://www.github.com/iTwin/iTwinUI-react/issues/539)) ([9e93871](https://www.github.com/iTwin/iTwinUI-react/commit/9e93871c59935a39f6ee1d633d96df04b78f33a1))
21
+
22
+ ### Fixes
23
+
24
+ * **Carousel:** Use event handler instead of useEffect for scroll ([#683](https://www.github.com/iTwin/iTwinUI-react/issues/683)) ([bcf125b](https://www.github.com/iTwin/iTwinUI-react/commit/bcf125be76495352a06c063bc7a0d5d2a884c860))
25
+ * **Toaster:** Fix inital position setting ([#687](https://www.github.com/iTwin/iTwinUI-react/issues/687)) ([c58b747](https://www.github.com/iTwin/iTwinUI-react/commit/c58b74786bf90a165993afb2eec926f74b37a1eb))
26
+
27
+ ### [1.38.1](https://www.github.com/iTwin/iTwinUI-react/compare/v1.38.0...v1.38.1) (2022-05-23)
28
+
29
+ ### Fixes
30
+
31
+ * **Toaster:** Fix initial position setting ([#687](https://www.github.com/iTwin/iTwinUI-react/issues/687)) ([c58b747](https://www.github.com/iTwin/iTwinUI-react/commit/c58b74786bf90a165993afb2eec926f74b37a1eb))
32
+
3
33
  ## [1.38.0](https://www.github.com/iTwin/iTwinUI-react/compare/v1.37.3...v1.38.0) (2022-05-23)
4
34
 
5
35
  ### What's new
@@ -64,19 +64,24 @@ exports.Carousel = Object.assign(react_1.default.forwardRef(function (props, ref
64
64
  var id = react_1.default.useState(function () { var _a; return (_a = props.id) !== null && _a !== void 0 ? _a : "iui-carousel-".concat((0, utils_1.getRandomValue)(10)); })[0];
65
65
  (0, utils_1.useTheme)();
66
66
  var isManuallyUpdating = react_1.default.useRef(false);
67
- var scrollInstantly = react_1.default.useRef(false);
68
67
  var carouselRef = react_1.default.useRef(null);
69
68
  var refs = (0, utils_1.useMergedRefs)(carouselRef, ref);
70
- var _b = react_1.default.useState(userActiveIndex), currentIndex = _b[0], _setCurrentIndex = _b[1];
69
+ var _b = react_1.default.useState(userActiveIndex), currentIndex = _b[0], setCurrentIndex = _b[1];
70
+ var scrollToSlide = react_1.default.useRef(function () { }); // stub function populated in CarouselSlider
71
+ var justMounted = react_1.default.useRef(true);
71
72
  react_1.default.useEffect(function () {
72
- _setCurrentIndex(userActiveIndex);
73
- }, [userActiveIndex]);
74
- var setCurrentIndex = react_1.default.useCallback(function (index) {
75
73
  var _a;
76
- _setCurrentIndex(index);
77
- isManuallyUpdating.current = true;
78
- (_a = carouselRef.current) === null || _a === void 0 ? void 0 : _a.focus();
79
- }, []);
74
+ setCurrentIndex(userActiveIndex);
75
+ scrollToSlide.current(userActiveIndex, {
76
+ instant: justMounted.current,
77
+ });
78
+ // re-focus the carousel for keyboard nav, but not on first mount
79
+ // because it shows outline and might interfere with other components
80
+ if (!justMounted.current) {
81
+ (_a = carouselRef.current) === null || _a === void 0 ? void 0 : _a.focus({ preventScroll: true });
82
+ }
83
+ justMounted.current = false;
84
+ }, [userActiveIndex]);
80
85
  var _c = react_1.default.useState(0), slideCount = _c[0], setSlideCount = _c[1];
81
86
  var _d = react_1.default.useState({}), keysPressed = _d[0], setKeysPressed = _d[1];
82
87
  var handleKeyDown = function (event) {
@@ -94,12 +99,16 @@ exports.Carousel = Object.assign(react_1.default.forwardRef(function (props, ref
94
99
  switch (event.key) {
95
100
  case 'ArrowLeft': {
96
101
  setKeysPressed(function (old) { return (__assign(__assign({}, old), { ArrowLeft: false })); });
97
- setCurrentIndex(function (old) { return (slideCount + old - 1) % slideCount; });
102
+ var prevIndex = (slideCount + currentIndex - 1) % slideCount;
103
+ scrollToSlide.current(prevIndex);
104
+ setCurrentIndex(prevIndex);
98
105
  break;
99
106
  }
100
107
  case 'ArrowRight': {
101
108
  setKeysPressed(function (old) { return (__assign(__assign({}, old), { ArrowRight: false })); });
102
- setCurrentIndex(function (old) { return (slideCount + old + 1) % slideCount; });
109
+ var nextIndex = (slideCount + currentIndex + 1) % slideCount;
110
+ scrollToSlide.current(nextIndex);
111
+ setCurrentIndex(nextIndex);
103
112
  break;
104
113
  }
105
114
  }
@@ -118,7 +127,7 @@ exports.Carousel = Object.assign(react_1.default.forwardRef(function (props, ref
118
127
  keysPressed: keysPressed,
119
128
  idPrefix: id,
120
129
  isManuallyUpdating: isManuallyUpdating,
121
- scrollInstantly: scrollInstantly,
130
+ scrollToSlide: scrollToSlide,
122
131
  } }, children)));
123
132
  }), {
124
133
  Slider: CarouselSlider_1.CarouselSlider,
@@ -31,7 +31,9 @@ export declare const CarouselContext: React.Context<{
31
31
  */
32
32
  isManuallyUpdating: React.MutableRefObject<boolean>;
33
33
  /**
34
- * Ref object used to skip smooth scrolling when button is clicked too many times.
34
+ * Function that scrolls to the current slide. Should be called on all managed events (clicks and keydowns).
35
35
  */
36
- scrollInstantly: React.MutableRefObject<boolean>;
36
+ scrollToSlide: React.MutableRefObject<(slideIndex: number, options?: {
37
+ instant?: boolean;
38
+ }) => void>;
37
39
  } | undefined>;
@@ -69,6 +69,7 @@ exports.CarouselDotsList = react_1.default.forwardRef(function (props, ref) {
69
69
  var handleSlideChange = react_1.default.useCallback(function (index) {
70
70
  if (context) {
71
71
  context.setCurrentIndex(index);
72
+ context.scrollToSlide.current(index);
72
73
  }
73
74
  onSlideChange === null || onSlideChange === void 0 ? void 0 : onSlideChange(index);
74
75
  }, [context, onSlideChange]);
@@ -43,13 +43,12 @@ var PreviousButton = react_1.default.forwardRef(function (props, ref) {
43
43
  if (!context) {
44
44
  throw new Error('CarouselNavigation should be used inside Carousel');
45
45
  }
46
- var slideCount = context.slideCount, setCurrentIndex = context.setCurrentIndex, keysPressed = context.keysPressed, scrollInstantly = context.scrollInstantly;
46
+ var slideCount = context.slideCount, currentIndex = context.currentIndex, setCurrentIndex = context.setCurrentIndex, keysPressed = context.keysPressed, scrollToSlide = context.scrollToSlide;
47
47
  return (react_1.default.createElement(Buttons_1.IconButton, __assign({ styleType: 'borderless', size: 'small', tabIndex: -1, "data-pressed": keysPressed['ArrowLeft'] || undefined, ref: ref }, props, { onClick: function (e) {
48
48
  var _a;
49
- if (e.detail > 3) {
50
- scrollInstantly.current = true;
51
- }
52
- setCurrentIndex(function (old) { return (slideCount + old - 1) % slideCount; });
49
+ var prevIndex = (slideCount + currentIndex - 1) % slideCount;
50
+ setCurrentIndex(prevIndex);
51
+ scrollToSlide.current(prevIndex, { instant: e.detail > 3 });
53
52
  (_a = props === null || props === void 0 ? void 0 : props.onClick) === null || _a === void 0 ? void 0 : _a.call(props, e);
54
53
  } }),
55
54
  react_1.default.createElement(ChevronLeft_1.default, null)));
@@ -60,13 +59,12 @@ var NextButton = react_1.default.forwardRef(function (props, ref) {
60
59
  if (!context) {
61
60
  throw new Error('CarouselNavigation should be used inside Carousel');
62
61
  }
63
- var slideCount = context.slideCount, setCurrentIndex = context.setCurrentIndex, keysPressed = context.keysPressed, scrollInstantly = context.scrollInstantly;
62
+ var slideCount = context.slideCount, currentIndex = context.currentIndex, setCurrentIndex = context.setCurrentIndex, keysPressed = context.keysPressed, scrollToSlide = context.scrollToSlide;
64
63
  return (react_1.default.createElement(Buttons_1.IconButton, __assign({ styleType: 'borderless', size: 'small', tabIndex: -1, "data-pressed": keysPressed['ArrowRight'] || undefined, ref: ref }, props, { onClick: function (e) {
65
64
  var _a;
66
- if (e.detail > 3) {
67
- scrollInstantly.current = true;
68
- }
69
- setCurrentIndex(function (old) { return (slideCount + old + 1) % slideCount; });
65
+ var nextIndex = (slideCount + currentIndex + 1) % slideCount;
66
+ setCurrentIndex(nextIndex);
67
+ scrollToSlide.current(nextIndex, { instant: e.detail > 3 });
70
68
  (_a = props === null || props === void 0 ? void 0 : props.onClick) === null || _a === void 0 ? void 0 : _a.call(props, e);
71
69
  } }),
72
70
  react_1.default.createElement(ChevronRight_1.default, null)));
@@ -46,17 +46,13 @@ exports.CarouselSlide = react_1.default.forwardRef(function (props, ref) {
46
46
  if (!context || index == null) {
47
47
  throw new Error('CarouselSlide must be used within Carousel');
48
48
  }
49
- var currentIndex = context.currentIndex, isManuallyUpdating = context.isManuallyUpdating, setCurrentIndex = context.setCurrentIndex;
49
+ var isManuallyUpdating = context.isManuallyUpdating, setCurrentIndex = context.setCurrentIndex;
50
50
  var updateActiveIndexOnScroll = react_1.default.useCallback(function () {
51
51
  // only update index if scroll was triggered by browser
52
- if (!isManuallyUpdating.current && currentIndex !== index) {
52
+ if (!isManuallyUpdating.current) {
53
53
  setCurrentIndex(index);
54
54
  }
55
- // when manual scroll completes, reset the state of `isManuallyUpdating` so that it's ready for future actions
56
- if (currentIndex === index) {
57
- isManuallyUpdating.current = false;
58
- }
59
- }, [currentIndex, index, isManuallyUpdating, setCurrentIndex]);
55
+ }, [index, isManuallyUpdating, setCurrentIndex]);
60
56
  var intersectionRef = (0, utils_1.useIntersection)(updateActiveIndexOnScroll, { threshold: 0.5 }, false);
61
57
  var refs = (0, utils_1.useMergedRefs)(intersectionRef, ref);
62
58
  return (react_1.default.createElement("li", __assign({ className: (0, classnames_1.default)('iui-carousel-slider-item', className), role: 'tabpanel', "aria-roledescription": 'slide', ref: refs }, rest), children));
@@ -43,7 +43,7 @@ exports.CarouselSlider = react_1.default.forwardRef(function (props, ref) {
43
43
  if (!context) {
44
44
  throw new Error('CarouselSlider must be used within Carousel');
45
45
  }
46
- var currentIndex = context.currentIndex, setSlideCount = context.setSlideCount, idPrefix = context.idPrefix, isManuallyUpdating = context.isManuallyUpdating, scrollInstantly = context.scrollInstantly;
46
+ var setSlideCount = context.setSlideCount, idPrefix = context.idPrefix, scrollToSlide = context.scrollToSlide, isManuallyUpdating = context.isManuallyUpdating;
47
47
  var items = react_1.default.useMemo(function () {
48
48
  var _a;
49
49
  return (_a = react_1.default.Children.map(children, function (child, index) {
@@ -58,37 +58,32 @@ exports.CarouselSlider = react_1.default.forwardRef(function (props, ref) {
58
58
  react_1.default.useLayoutEffect(function () {
59
59
  setSlideCount(items.length);
60
60
  }, [items.length, setSlideCount]);
61
- var _a = react_1.default.useState(), width = _a[0], setWidth = _a[1];
62
- var resizeRef = (0, utils_1.useResizeObserver)(function (_a) {
63
- var width = _a.width;
64
- return setWidth(width);
65
- })[0];
66
61
  var sliderRef = react_1.default.useRef(null);
67
- var refs = (0, utils_1.useMergedRefs)(sliderRef, resizeRef, ref);
68
- var justMounted = react_1.default.useRef(true);
69
- var previousWidth = react_1.default.useRef();
70
- react_1.default.useLayoutEffect(function () {
71
- var _a, _b, _c;
72
- var slideToShow = (_a = sliderRef.current) === null || _a === void 0 ? void 0 : _a.children.item(currentIndex);
73
- if (!sliderRef.current ||
74
- !slideToShow ||
75
- (!isManuallyUpdating.current && previousWidth.current === width)) {
62
+ var refs = (0, utils_1.useMergedRefs)(sliderRef, ref);
63
+ scrollToSlide.current = function (slideIndex, _a) {
64
+ var _b, _c, _d;
65
+ var _e = _a === void 0 ? {} : _a, instant = _e.instant;
66
+ isManuallyUpdating.current = true; // start manual update
67
+ var slideToShow = (_b = sliderRef.current) === null || _b === void 0 ? void 0 : _b.children.item(slideIndex);
68
+ if (!sliderRef.current || !slideToShow) {
76
69
  return;
77
70
  }
78
- // instant scroll on first mount
79
- if (justMounted.current) {
80
- scrollInstantly.current = true;
81
- justMounted.current = false;
82
- }
83
- var motionOk = (_c = (_b = (0, utils_1.getWindow)()) === null || _b === void 0 ? void 0 : _b.matchMedia('(prefers-reduced-motion: no-preference)')) === null || _c === void 0 ? void 0 : _c.matches;
71
+ var motionOk = (_d = (_c = (0, utils_1.getWindow)()) === null || _c === void 0 ? void 0 : _c.matchMedia('(prefers-reduced-motion: no-preference)')) === null || _d === void 0 ? void 0 : _d.matches;
84
72
  sliderRef.current.scrollTo({
85
73
  left: slideToShow.offsetLeft - sliderRef.current.offsetLeft,
86
- behavior: (scrollInstantly.current || !motionOk
87
- ? 'instant'
88
- : 'smooth'), // scrollTo accepts 'instant' but ScrollBehavior type is wrong
74
+ behavior: (instant || !motionOk ? 'instant' : 'smooth'), // scrollTo accepts 'instant' but ScrollBehavior type is wrong
89
75
  });
90
- scrollInstantly.current = false;
91
- previousWidth.current = width;
92
- }, [currentIndex, isManuallyUpdating, scrollInstantly, width]);
93
- return (react_1.default.createElement("ol", __assign({ "aria-live": 'polite', className: (0, classnames_1.default)('iui-carousel-slider', className), ref: refs }, rest), items));
76
+ };
77
+ var scrollTimeout = react_1.default.useRef();
78
+ // reset isManuallyUpdating.current to false after the last scroll event
79
+ var handleOnScroll = react_1.default.useCallback(function () {
80
+ var _a, _b;
81
+ if (scrollTimeout.current) {
82
+ (_a = (0, utils_1.getWindow)()) === null || _a === void 0 ? void 0 : _a.clearTimeout(scrollTimeout.current);
83
+ }
84
+ scrollTimeout.current = (_b = (0, utils_1.getWindow)()) === null || _b === void 0 ? void 0 : _b.setTimeout(function () {
85
+ isManuallyUpdating.current = false;
86
+ }, 100);
87
+ }, [isManuallyUpdating]);
88
+ return (react_1.default.createElement("ol", __assign({ "aria-live": 'polite', className: (0, classnames_1.default)('iui-carousel-slider', className), ref: refs, onScroll: handleOnScroll }, rest), items));
94
89
  });
@@ -5,7 +5,7 @@ export declare const ColorPickerContext: React.Context<{
5
5
  setActiveColor: (color: ColorValue | ((prevColor: ColorValue) => ColorValue)) => void;
6
6
  hsvColor: HsvColor;
7
7
  onChangeComplete?: ((color: ColorValue) => void) | undefined;
8
- applyHsvColorChange: (newColor: HsvColor, selectionChanged: boolean, newColorValue?: ColorValue | undefined) => void;
8
+ applyHsvColorChange: (newColor: HsvColor, selectionChanged: boolean, newColorValue?: ColorValue) => void;
9
9
  showAlpha: boolean;
10
10
  } | undefined>;
11
11
  export declare const useColorPickerContext: () => {
@@ -13,6 +13,6 @@ export declare const useColorPickerContext: () => {
13
13
  setActiveColor: (color: ColorValue | ((prevColor: ColorValue) => ColorValue)) => void;
14
14
  hsvColor: HsvColor;
15
15
  onChangeComplete?: ((color: ColorValue) => void) | undefined;
16
- applyHsvColorChange: (newColor: HsvColor, selectionChanged: boolean, newColorValue?: ColorValue | undefined) => void;
16
+ applyHsvColorChange: (newColor: HsvColor, selectionChanged: boolean, newColorValue?: ColorValue) => void;
17
17
  showAlpha: boolean;
18
18
  };
@@ -35,9 +35,10 @@ export declare type ComboBoxProps<T> = {
35
35
  dropdownMenuProps?: PopoverProps;
36
36
  /**
37
37
  * Message shown when no options are available.
38
+ * If `JSX.Element` is provided, it will be rendered as is and won't be wrapped with `MenuExtraContent`.
38
39
  * @default 'No options found'
39
40
  */
40
- emptyStateMessage?: string;
41
+ emptyStateMessage?: React.ReactNode;
41
42
  /**
42
43
  * A custom item renderer can be specified to control the rendering.
43
44
  *
@@ -51,6 +52,21 @@ export declare type ComboBoxProps<T> = {
51
52
  id: string;
52
53
  index: number;
53
54
  }) => JSX.Element;
55
+ /**
56
+ * If enabled, virtualization is used for the scrollable dropdown list.
57
+ * Use it if you expect a very long list of items.
58
+ * @default false
59
+ * @beta
60
+ */
61
+ enableVirtualization?: boolean;
62
+ /**
63
+ * Callback fired when dropdown menu is opened.
64
+ */
65
+ onShow?: () => void;
66
+ /**
67
+ * Callback fired when dropdown menu is closed.
68
+ */
69
+ onHide?: () => void;
54
70
  } & Pick<InputContainerProps, 'status'> & Omit<CommonProps, 'title'>;
55
71
  /**
56
72
  * ComboBox component that allows typing a value to filter the options in dropdown list.
@@ -62,8 +62,8 @@ var getOptionId = function (option, idPrefix) {
62
62
  * />
63
63
  */
64
64
  var ComboBox = function (props) {
65
- var _a;
66
- var options = props.options, valueProp = props.value, onChange = props.onChange, filterFunction = props.filterFunction, inputProps = props.inputProps, dropdownMenuProps = props.dropdownMenuProps, _b = props.emptyStateMessage, emptyStateMessage = _b === void 0 ? 'No options found' : _b, itemRenderer = props.itemRenderer, rest = __rest(props, ["options", "value", "onChange", "filterFunction", "inputProps", "dropdownMenuProps", "emptyStateMessage", "itemRenderer"]);
65
+ var _a, _b;
66
+ var options = props.options, valueProp = props.value, onChange = props.onChange, filterFunction = props.filterFunction, inputProps = props.inputProps, dropdownMenuProps = props.dropdownMenuProps, _c = props.emptyStateMessage, emptyStateMessage = _c === void 0 ? 'No options found' : _c, itemRenderer = props.itemRenderer, _d = props.enableVirtualization, enableVirtualization = _d === void 0 ? false : _d, onShow = props.onShow, onHide = props.onHide, rest = __rest(props, ["options", "value", "onChange", "filterFunction", "inputProps", "dropdownMenuProps", "emptyStateMessage", "itemRenderer", "enableVirtualization", "onShow", "onHide"]);
67
67
  // Generate a stateful random id if not specified
68
68
  var id = react_1.default.useState(function () {
69
69
  var _a, _b;
@@ -95,17 +95,18 @@ var ComboBox = function (props) {
95
95
  });
96
96
  }
97
97
  // Reducer where all the component-wide state is stored
98
- var _c = react_1.default.useReducer(helpers_1.comboBoxReducer, {
98
+ var _e = react_1.default.useReducer(helpers_1.comboBoxReducer, {
99
99
  isOpen: false,
100
100
  selectedIndex: -1,
101
101
  focusedIndex: -1,
102
- }), _d = _c[0], isOpen = _d.isOpen, selectedIndex = _d.selectedIndex, focusedIndex = _d.focusedIndex, dispatch = _c[1];
103
- react_1.default.useEffect(function () {
102
+ }), _f = _e[0], isOpen = _f.isOpen, selectedIndex = _f.selectedIndex, focusedIndex = _f.focusedIndex, dispatch = _e[1];
103
+ react_1.default.useLayoutEffect(function () {
104
104
  var _a, _b;
105
105
  // When the dropdown opens
106
106
  if (isOpen) {
107
107
  (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); // Focus the input
108
108
  setFilteredOptions(options); // Reset the filtered list
109
+ dispatch(['focus']);
109
110
  }
110
111
  // When the dropdown closes
111
112
  else {
@@ -118,19 +119,30 @@ var ComboBox = function (props) {
118
119
  }
119
120
  }, [isOpen, options, selectedIndex]);
120
121
  // Set min-width of menu to be same as input
121
- var _e = react_1.default.useState(0), minWidth = _e[0], setMinWidth = _e[1];
122
+ var _g = react_1.default.useState(0), minWidth = _g[0], setMinWidth = _g[1];
122
123
  react_1.default.useEffect(function () {
123
124
  if (inputRef.current) {
124
125
  setMinWidth(inputRef.current.offsetWidth);
125
126
  }
126
127
  }, [isOpen]);
127
- // Initialize filtered options to the latest value options
128
- var _f = react_1.default.useState(options), filteredOptions = _f[0], setFilteredOptions = _f[1];
128
+ // Update filtered options to the latest value options according to input value
129
+ var _h = react_1.default.useState(options), filteredOptions = _h[0], setFilteredOptions = _h[1];
129
130
  react_1.default.useEffect(function () {
130
- setFilteredOptions(options);
131
+ var _a;
132
+ if (inputValue) {
133
+ setFilteredOptions((_a = filterFunction === null || filterFunction === void 0 ? void 0 : filterFunction(options, inputValue)) !== null && _a !== void 0 ? _a : options.filter(function (option) {
134
+ return option.label.toLowerCase().includes(inputValue.toLowerCase());
135
+ }));
136
+ }
137
+ else {
138
+ setFilteredOptions(options);
139
+ }
140
+ dispatch(['focus']);
141
+ // Only need to call on options update
142
+ // eslint-disable-next-line react-hooks/exhaustive-deps
131
143
  }, [options]);
132
144
  // Filter options based on input value
133
- var _g = react_1.default.useState((_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.value) !== null && _a !== void 0 ? _a : ''), inputValue = _g[0], setInputValue = _g[1];
145
+ var _j = react_1.default.useState((_b = (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.value) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : ''), inputValue = _j[0], setInputValue = _j[1];
134
146
  var handleOnInput = react_1.default.useCallback(function (event) {
135
147
  var _a, _b;
136
148
  var value = event.currentTarget.value;
@@ -139,12 +151,11 @@ var ComboBox = function (props) {
139
151
  setFilteredOptions((_a = filterFunction === null || filterFunction === void 0 ? void 0 : filterFunction(options, value)) !== null && _a !== void 0 ? _a : options.filter(function (option) {
140
152
  return option.label.toLowerCase().includes(value.toLowerCase());
141
153
  }));
154
+ if (focusedIndex != -1) {
155
+ dispatch(['focus', -1]);
156
+ }
142
157
  (_b = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onChange) === null || _b === void 0 ? void 0 : _b.call(inputProps, event);
143
- }, [filterFunction, inputProps, options]);
144
- // Reset focused item when filteredOptions change
145
- react_1.default.useEffect(function () {
146
- dispatch(['focus']);
147
- }, [filteredOptions]);
158
+ }, [filterFunction, focusedIndex, inputProps, options]);
148
159
  // When the value prop changes, update the selectedIndex
149
160
  react_1.default.useEffect(function () {
150
161
  dispatch([
@@ -163,7 +174,7 @@ var ComboBox = function (props) {
163
174
  (_b = onChangeProp.current) === null || _b === void 0 ? void 0 : _b.call(onChangeProp, value);
164
175
  }
165
176
  }, [options, selectedIndex, valueProp]);
166
- var getMenuItem = react_1.default.useCallback(function (option) {
177
+ var getMenuItem = react_1.default.useCallback(function (option, filteredIndex) {
167
178
  var optionId = getOptionId(option, id);
168
179
  var __originalIndex = optionsExtraInfoRef.current[optionId].__originalIndex;
169
180
  var customItem = itemRenderer
@@ -178,6 +189,7 @@ var ComboBox = function (props) {
178
189
  onClick: function (e) {
179
190
  var _a, _b;
180
191
  dispatch(['select', __originalIndex]);
192
+ dispatch(['close']);
181
193
  (_b = (_a = customItem.props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
182
194
  },
183
195
  // ComboBox.MenuItem handles scrollIntoView, data-iui-index and iui-focused through context
@@ -186,23 +198,37 @@ var ComboBox = function (props) {
186
198
  'iui-focused': focusedIndex === __originalIndex,
187
199
  }),
188
200
  'data-iui-index': __originalIndex,
201
+ 'data-iui-filtered-index': filteredIndex,
189
202
  ref: (0, utils_1.mergeRefs)(customItem.props.ref, function (el) {
190
- // will need to check for virtualization here too
191
- if (focusedIndex === __originalIndex) {
203
+ if (!enableVirtualization && focusedIndex === __originalIndex) {
192
204
  el === null || el === void 0 ? void 0 : el.scrollIntoView({ block: 'nearest' });
193
205
  }
194
206
  }),
195
- })) : (react_1.default.createElement(ComboBoxMenuItem_1.ComboBoxMenuItem, __assign({ key: optionId, id: optionId }, option, { isSelected: selectedIndex === __originalIndex, onClick: function () { return dispatch(['select', __originalIndex]); }, index: __originalIndex }), option.label));
196
- }, [focusedIndex, id, itemRenderer, selectedIndex]);
207
+ })) : (react_1.default.createElement(ComboBoxMenuItem_1.ComboBoxMenuItem, __assign({ key: optionId, id: optionId }, option, { isSelected: selectedIndex === __originalIndex, onClick: function () {
208
+ dispatch(['select', __originalIndex]);
209
+ dispatch(['close']);
210
+ }, index: __originalIndex, "data-iui-filtered-index": filteredIndex }), option.label));
211
+ }, [enableVirtualization, focusedIndex, id, itemRenderer, selectedIndex]);
212
+ var emptyContent = react_1.default.useMemo(function () { return (react_1.default.createElement(react_1.default.Fragment, null, react_1.default.isValidElement(emptyStateMessage) ? (emptyStateMessage) : (react_1.default.createElement(Menu_1.MenuExtraContent, null,
213
+ react_1.default.createElement(Typography_1.Text, { isMuted: true }, emptyStateMessage))))); }, [emptyStateMessage]);
197
214
  return (react_1.default.createElement(helpers_1.ComboBoxRefsContext.Provider, { value: { inputRef: inputRef, menuRef: menuRef, toggleButtonRef: toggleButtonRef, optionsExtraInfoRef: optionsExtraInfoRef } },
198
215
  react_1.default.createElement(helpers_1.ComboBoxActionContext.Provider, { value: dispatch },
199
- react_1.default.createElement(helpers_1.ComboBoxStateContext.Provider, { value: { id: id, minWidth: minWidth, isOpen: isOpen, focusedIndex: focusedIndex } },
216
+ react_1.default.createElement(helpers_1.ComboBoxStateContext.Provider, { value: {
217
+ id: id,
218
+ minWidth: minWidth,
219
+ isOpen: isOpen,
220
+ focusedIndex: focusedIndex,
221
+ enableVirtualization: enableVirtualization,
222
+ filteredOptions: filteredOptions,
223
+ getMenuItem: getMenuItem,
224
+ } },
200
225
  react_1.default.createElement(ComboBoxInputContainer_1.ComboBoxInputContainer, __assign({ disabled: inputProps === null || inputProps === void 0 ? void 0 : inputProps.disabled }, rest),
201
226
  react_1.default.createElement(ComboBoxInput_1.ComboBoxInput, __assign({ value: inputValue }, inputProps, { onChange: handleOnInput })),
202
227
  react_1.default.createElement(ComboBoxEndIcon_1.ComboBoxEndIcon, { disabled: inputProps === null || inputProps === void 0 ? void 0 : inputProps.disabled, isOpen: isOpen })),
203
- react_1.default.createElement(ComboBoxDropdown_1.ComboBoxDropdown, __assign({}, dropdownMenuProps),
204
- react_1.default.createElement(ComboBoxMenu_1.ComboBoxMenu, null, filteredOptions.length > 0 ? (filteredOptions.map(getMenuItem)) : (react_1.default.createElement(Menu_1.MenuExtraContent, null,
205
- react_1.default.createElement(Typography_1.Text, { isMuted: true }, emptyStateMessage)))))))));
228
+ react_1.default.createElement(ComboBoxDropdown_1.ComboBoxDropdown, __assign({}, dropdownMenuProps, { onShow: onShow, onHide: onHide }),
229
+ react_1.default.createElement(ComboBoxMenu_1.ComboBoxMenu, null, filteredOptions.length > 0 && !enableVirtualization
230
+ ? filteredOptions.map(getMenuItem)
231
+ : emptyContent))))));
206
232
  };
207
233
  exports.ComboBox = ComboBox;
208
234
  exports.default = exports.ComboBox;
@@ -1,8 +1,7 @@
1
1
  import React from 'react';
2
- export declare const ComboBoxDropdown: React.ForwardRefExoticComponent<Pick<{
3
- visible?: boolean | undefined;
4
- trigger?: string | undefined;
5
- placement?: import("@popperjs/core").Placement | undefined;
6
- } & Omit<import("@tippyjs/react").TippyProps, "placement" | "trigger" | "visible"> & {
2
+ import { PopoverProps } from '../utils';
3
+ declare type ComboBoxDropdownProps = PopoverProps & {
7
4
  children: JSX.Element;
8
- }, "disabled" | "children" | "placement" | "trigger" | "visible" | "content" | "render" | "animateFill" | "appendTo" | "aria" | "delay" | "duration" | "followCursor" | "getReferenceClientRect" | "hideOnClick" | "ignoreAttributes" | "inlinePositioning" | "interactive" | "interactiveBorder" | "interactiveDebounce" | "moveTransition" | "offset" | "plugins" | "popperOptions" | "showOnCreate" | "sticky" | "touch" | "triggerTarget" | "onAfterUpdate" | "onBeforeUpdate" | "onCreate" | "onDestroy" | "onHidden" | "onHide" | "onMount" | "onShow" | "onShown" | "onTrigger" | "onUntrigger" | "onClickOutside" | "allowHTML" | "animation" | "arrow" | "inertia" | "maxWidth" | "role" | "theme" | "zIndex" | "className" | "singleton" | "reference"> & React.RefAttributes<Element>>;
5
+ };
6
+ export declare const ComboBoxDropdown: React.ForwardRefExoticComponent<Pick<ComboBoxDropdownProps, "disabled" | "children" | "placement" | "trigger" | "visible" | "content" | "render" | "animateFill" | "appendTo" | "aria" | "delay" | "duration" | "followCursor" | "getReferenceClientRect" | "hideOnClick" | "ignoreAttributes" | "inlinePositioning" | "interactive" | "interactiveBorder" | "interactiveDebounce" | "moveTransition" | "offset" | "plugins" | "popperOptions" | "showOnCreate" | "sticky" | "touch" | "triggerTarget" | "onAfterUpdate" | "onBeforeUpdate" | "onCreate" | "onDestroy" | "onHidden" | "onHide" | "onMount" | "onShow" | "onShown" | "onTrigger" | "onUntrigger" | "onClickOutside" | "allowHTML" | "animation" | "arrow" | "inertia" | "maxWidth" | "role" | "theme" | "zIndex" | "className" | "singleton" | "reference"> & React.RefAttributes<Element>>;
7
+ export {};
@@ -36,7 +36,7 @@ var utils_1 = require("../utils");
36
36
  var helpers_1 = require("./helpers");
37
37
  exports.ComboBoxInput = react_1.default.forwardRef(function (props, forwardedRef) {
38
38
  var onKeyDownProp = props.onKeyDown, onFocusProp = props.onFocus, rest = __rest(props, ["onKeyDown", "onFocus"]);
39
- var _a = (0, utils_1.useSafeContext)(helpers_1.ComboBoxStateContext), isOpen = _a.isOpen, id = _a.id, focusedIndex = _a.focusedIndex;
39
+ var _a = (0, utils_1.useSafeContext)(helpers_1.ComboBoxStateContext), isOpen = _a.isOpen, id = _a.id, focusedIndex = _a.focusedIndex, enableVirtualization = _a.enableVirtualization;
40
40
  var dispatch = (0, utils_1.useSafeContext)(helpers_1.ComboBoxActionContext);
41
41
  var _b = (0, utils_1.useSafeContext)(helpers_1.ComboBoxRefsContext), inputRef = _b.inputRef, menuRef = _b.menuRef, optionsExtraInfoRef = _b.optionsExtraInfoRef;
42
42
  var refs = (0, utils_1.useMergedRefs)(inputRef, forwardedRef);
@@ -49,7 +49,7 @@ exports.ComboBoxInput = react_1.default.forwardRef(function (props, forwardedRef
49
49
  return ((_c = (_b = (_a = menuRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("[data-iui-index=\"".concat(index, "\"]"))) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : '');
50
50
  };
51
51
  var handleKeyDown = react_1.default.useCallback(function (event) {
52
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
52
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
53
53
  onKeyDownProp === null || onKeyDownProp === void 0 ? void 0 : onKeyDownProp(event);
54
54
  var length = (_a = Object.keys(optionsExtraInfoRef.current).length) !== null && _a !== void 0 ? _a : 0;
55
55
  switch (event.key) {
@@ -62,15 +62,21 @@ exports.ComboBoxInput = react_1.default.forwardRef(function (props, forwardedRef
62
62
  return;
63
63
  }
64
64
  if (focusedIndexRef.current === -1) {
65
+ var currentElement = (_b = menuRef.current) === null || _b === void 0 ? void 0 : _b.querySelector('[data-iui-index]');
65
66
  return dispatch([
66
67
  'focus',
67
- (_c = (_b = Object.values(optionsExtraInfoRef.current)) === null || _b === void 0 ? void 0 : _b[0].__originalIndex) !== null && _c !== void 0 ? _c : -1,
68
+ Number((_c = currentElement === null || currentElement === void 0 ? void 0 : currentElement.getAttribute('data-iui-index')) !== null && _c !== void 0 ? _c : 0),
68
69
  ]);
69
70
  }
71
+ // If virtualization is enabled, dont let round scrolling
72
+ if (enableVirtualization &&
73
+ !((_e = (_d = menuRef.current) === null || _d === void 0 ? void 0 : _d.querySelector("[data-iui-index=\"".concat(focusedIndexRef.current, "\"]"))) === null || _e === void 0 ? void 0 : _e.nextElementSibling)) {
74
+ return;
75
+ }
70
76
  var nextIndex = focusedIndexRef.current;
71
77
  do {
72
- var currentElement = (_d = menuRef.current) === null || _d === void 0 ? void 0 : _d.querySelector("[data-iui-index=\"".concat(nextIndex, "\"]"));
73
- var nextElement = (_e = currentElement === null || currentElement === void 0 ? void 0 : currentElement.nextElementSibling) !== null && _e !== void 0 ? _e : (_f = menuRef.current) === null || _f === void 0 ? void 0 : _f.querySelector('[data-iui-index]');
78
+ var currentElement = (_f = menuRef.current) === null || _f === void 0 ? void 0 : _f.querySelector("[data-iui-index=\"".concat(nextIndex, "\"]"));
79
+ var nextElement = (_g = currentElement === null || currentElement === void 0 ? void 0 : currentElement.nextElementSibling) !== null && _g !== void 0 ? _g : (_h = menuRef.current) === null || _h === void 0 ? void 0 : _h.querySelector('[data-iui-index]');
74
80
  nextIndex = Number(nextElement === null || nextElement === void 0 ? void 0 : nextElement.getAttribute('data-iui-index'));
75
81
  if ((nextElement === null || nextElement === void 0 ? void 0 : nextElement.ariaDisabled) !== 'true') {
76
82
  return dispatch(['focus', nextIndex]);
@@ -86,16 +92,21 @@ exports.ComboBoxInput = react_1.default.forwardRef(function (props, forwardedRef
86
92
  if (length === 0) {
87
93
  return;
88
94
  }
95
+ // If virtualization is enabled, dont let round scrolling
96
+ if (enableVirtualization &&
97
+ !((_k = (_j = menuRef.current) === null || _j === void 0 ? void 0 : _j.querySelector("[data-iui-index=\"".concat(focusedIndexRef.current, "\"]"))) === null || _k === void 0 ? void 0 : _k.previousElementSibling)) {
98
+ return;
99
+ }
89
100
  if (focusedIndexRef.current === -1) {
90
101
  return dispatch([
91
102
  'focus',
92
- (_h = (_g = Object.values(optionsExtraInfoRef.current)) === null || _g === void 0 ? void 0 : _g[length - 1].__originalIndex) !== null && _h !== void 0 ? _h : -1,
103
+ (_m = (_l = Object.values(optionsExtraInfoRef.current)) === null || _l === void 0 ? void 0 : _l[length - 1].__originalIndex) !== null && _m !== void 0 ? _m : -1,
93
104
  ]);
94
105
  }
95
106
  var prevIndex = focusedIndexRef.current;
96
107
  do {
97
- var currentElement = (_j = menuRef.current) === null || _j === void 0 ? void 0 : _j.querySelector("[data-iui-index=\"".concat(prevIndex, "\"]"));
98
- var prevElement = (_k = currentElement === null || currentElement === void 0 ? void 0 : currentElement.previousElementSibling) !== null && _k !== void 0 ? _k : (_l = menuRef.current) === null || _l === void 0 ? void 0 : _l.querySelector('[data-iui-index]:last-of-type');
108
+ var currentElement = (_o = menuRef.current) === null || _o === void 0 ? void 0 : _o.querySelector("[data-iui-index=\"".concat(prevIndex, "\"]"));
109
+ var prevElement = (_p = currentElement === null || currentElement === void 0 ? void 0 : currentElement.previousElementSibling) !== null && _p !== void 0 ? _p : (_q = menuRef.current) === null || _q === void 0 ? void 0 : _q.querySelector('[data-iui-index]:last-of-type');
99
110
  prevIndex = Number(prevElement === null || prevElement === void 0 ? void 0 : prevElement.getAttribute('data-iui-index'));
100
111
  if ((prevElement === null || prevElement === void 0 ? void 0 : prevElement.ariaDisabled) !== 'true') {
101
112
  return dispatch(['focus', prevIndex]);
@@ -107,6 +118,7 @@ exports.ComboBoxInput = react_1.default.forwardRef(function (props, forwardedRef
107
118
  event.preventDefault();
108
119
  if (isOpen) {
109
120
  dispatch(['select', focusedIndexRef.current]);
121
+ dispatch(['close']);
110
122
  }
111
123
  else {
112
124
  dispatch(['open']);
@@ -122,7 +134,14 @@ exports.ComboBoxInput = react_1.default.forwardRef(function (props, forwardedRef
122
134
  dispatch(['close']);
123
135
  break;
124
136
  }
125
- }, [dispatch, isOpen, menuRef, onKeyDownProp, optionsExtraInfoRef]);
137
+ }, [
138
+ dispatch,
139
+ enableVirtualization,
140
+ isOpen,
141
+ menuRef,
142
+ onKeyDownProp,
143
+ optionsExtraInfoRef,
144
+ ]);
126
145
  var handleFocus = react_1.default.useCallback(function (event) {
127
146
  dispatch(['open']);
128
147
  onFocusProp === null || onFocusProp === void 0 ? void 0 : onFocusProp(event);