@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
@@ -25,12 +25,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
25
25
  return (mod && mod.__esModule) ? mod : { "default": mod };
26
26
  };
27
27
  Object.defineProperty(exports, "__esModule", { value: true });
28
- exports.VirtualScroll = void 0;
28
+ exports.useVirtualization = exports.VirtualScroll = void 0;
29
29
  /*---------------------------------------------------------------------------------------------
30
30
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
31
31
  * See LICENSE.md in the project root for license terms and full copyright notice.
32
32
  *--------------------------------------------------------------------------------------------*/
33
33
  var react_1 = __importDefault(require("react"));
34
+ var hooks_1 = require("../hooks");
34
35
  var useResizeObserver_1 = require("../hooks/useResizeObserver");
35
36
  var getScrollableParent = function (element, ownerDocument) {
36
37
  if (ownerDocument === void 0) { ownerDocument = document; }
@@ -52,6 +53,14 @@ var getElementHeight = function (element) {
52
53
  var _a;
53
54
  return (_a = element === null || element === void 0 ? void 0 : element.getBoundingClientRect().height) !== null && _a !== void 0 ? _a : 0;
54
55
  };
56
+ var getElementHeightWithMargins = function (element) {
57
+ if (!element) {
58
+ return undefined;
59
+ }
60
+ var margin = parseFloat(getElementStyle(element, 'margin-top')) +
61
+ parseFloat(getElementStyle(element, 'margin-bottom'));
62
+ return getElementHeight(element) + (isNaN(margin) ? 0 : margin);
63
+ };
55
64
  var getNumberOfNodesInHeight = function (childHeight, totalHeight) {
56
65
  if (!childHeight) {
57
66
  return 0;
@@ -59,7 +68,10 @@ var getNumberOfNodesInHeight = function (childHeight, totalHeight) {
59
68
  return Math.floor(totalHeight / childHeight);
60
69
  };
61
70
  var getTranslateValue = function (childHeight, startIndex) {
62
- return childHeight * startIndex;
71
+ if (startIndex > 0) {
72
+ return childHeight * startIndex;
73
+ }
74
+ return 0;
63
75
  };
64
76
  var getVisibleNodeCount = function (childHeight, startIndex, childrenLength, scrollContainer) {
65
77
  return Math.min(childrenLength - startIndex, getNumberOfNodesInHeight(childHeight, getElementHeight(scrollContainer)));
@@ -85,21 +97,55 @@ var getVisibleNodeCount = function (childHeight, startIndex, childrenLength, scr
85
97
  * />
86
98
  * @private
87
99
  */
88
- exports.VirtualScroll = react_1.default.forwardRef(function (_a, ref) {
89
- var itemsLength = _a.itemsLength, itemRenderer = _a.itemRenderer, _b = _a.bufferSize, bufferSize = _b === void 0 ? 10 : _b, style = _a.style, rest = __rest(_a, ["itemsLength", "itemRenderer", "bufferSize", "style"]);
90
- var _c = react_1.default.useState(0), startNode = _c[0], setStartNode = _c[1];
91
- var _d = react_1.default.useState(0), visibleNodeCount = _d[0], setVisibleNodeCount = _d[1];
100
+ exports.VirtualScroll = react_1.default.forwardRef(function (props, ref) {
101
+ var _a = (0, exports.useVirtualization)(props), innerProps = _a.innerProps, outerProps = _a.outerProps, visibleChildren = _a.visibleChildren;
102
+ return (react_1.default.createElement("div", __assign({}, outerProps, { ref: ref }),
103
+ react_1.default.createElement("div", __assign({}, innerProps), visibleChildren)));
104
+ });
105
+ /**
106
+ * `useVirtualization` is used for efficiently rendering only the visible rows from a large list.
107
+ * It returns `outerProps` and `innerProps`, which need to be applied on 2 container elements and `visibleChildren` which is a list of virtualized items.
108
+ * @example
109
+ * const itemRenderer = React.useCallback((index: number) => (
110
+ * <li key={index}>
111
+ * This is my item #{index}
112
+ * </li>
113
+ * ), [])
114
+ *
115
+ * const { outerProps, innerProps, visibleChildren } = useVirtualization({itemsLength: 1000, itemRenderer: itemRenderer});
116
+ * return (
117
+ * <div {...outerProps}>
118
+ * <ul {...innerProps}>
119
+ * {visibleChildren}
120
+ * </ul>
121
+ * </div>
122
+ * );
123
+ * @private
124
+ */
125
+ var useVirtualization = function (props) {
126
+ var itemsLength = props.itemsLength, itemRenderer = props.itemRenderer, _a = props.bufferSize, bufferSize = _a === void 0 ? 10 : _a, scrollToIndex = props.scrollToIndex, style = props.style, rest = __rest(props, ["itemsLength", "itemRenderer", "bufferSize", "scrollToIndex", "style"]);
127
+ var _b = react_1.default.useState(0), startNode = _b[0], setStartNode = _b[1];
128
+ var _c = react_1.default.useState(0), visibleNodeCount = _c[0], setVisibleNodeCount = _c[1];
92
129
  var scrollContainer = react_1.default.useRef();
93
130
  var parentRef = react_1.default.useRef(null);
94
- var childHeight = react_1.default.useRef(0);
131
+ var childHeight = react_1.default.useRef({ first: 0, middle: 0, last: 0 });
95
132
  var onScrollRef = react_1.default.useRef();
96
133
  // Used only to recalculate on resize
97
- var _e = react_1.default.useState(0), scrollContainerHeight = _e[0], setScrollContainerHeight = _e[1];
134
+ var _d = react_1.default.useState(0), scrollContainerHeight = _d[0], setScrollContainerHeight = _d[1];
135
+ var visibleIndex = react_1.default.useRef({ start: 0, end: 0 });
136
+ // Used to mark when scroll container has height (updated by resize observer)
137
+ // because before that calculations are not right
138
+ var _e = react_1.default.useState(false), isMounted = _e[0], setIsMounted = _e[1];
98
139
  var onResize = react_1.default.useCallback(function (_a) {
99
140
  var height = _a.height;
141
+ // Initial value returned by resize observer is 0
142
+ // So wait for the next one
143
+ if (height > 0) {
144
+ setIsMounted(true);
145
+ }
100
146
  setScrollContainerHeight(height);
101
147
  }, []);
102
- var resizeRef = (0, useResizeObserver_1.useResizeObserver)(onResize)[0];
148
+ var _f = (0, useResizeObserver_1.useResizeObserver)(onResize), resizeRef = _f[0], resizeObserver = _f[1];
103
149
  // Find scrollable parent
104
150
  // Needed only on init
105
151
  react_1.default.useLayoutEffect(function () {
@@ -108,6 +154,14 @@ exports.VirtualScroll = react_1.default.forwardRef(function (_a, ref) {
108
154
  scrollContainer.current = scrollableParent;
109
155
  resizeRef(scrollableParent);
110
156
  }, [resizeRef]);
157
+ // Stop watching resize, when virtual scroll is unmounted
158
+ react_1.default.useLayoutEffect(function () {
159
+ return function () { return resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect(); };
160
+ }, [resizeObserver]);
161
+ var getScrollableContainer = function () {
162
+ var _a, _b;
163
+ return (_a = scrollContainer.current) !== null && _a !== void 0 ? _a : (_b = parentRef.current) === null || _b === void 0 ? void 0 : _b.ownerDocument.scrollingElement;
164
+ };
111
165
  var visibleChildren = react_1.default.useMemo(function () {
112
166
  var arr = [];
113
167
  var endIndex = Math.min(itemsLength, startNode + visibleNodeCount + bufferSize * 2);
@@ -118,27 +172,42 @@ exports.VirtualScroll = react_1.default.forwardRef(function (_a, ref) {
118
172
  }, [itemsLength, itemRenderer, bufferSize, startNode, visibleNodeCount]);
119
173
  // Get child height when children available
120
174
  react_1.default.useLayoutEffect(function () {
175
+ var _a, _b, _c, _d, _e, _f;
121
176
  if (!parentRef.current || !visibleChildren.length) {
122
177
  return;
123
178
  }
124
179
  var firstChild = parentRef.current.children.item(0);
125
- childHeight.current = Number(getElementHeight(firstChild).toFixed(2));
180
+ var secondChild = parentRef.current.children.item(1);
181
+ var lastChild = parentRef.current.children.item(parentRef.current.children.length - 1);
182
+ var firstChildHeight = Number((_b = (_a = getElementHeightWithMargins(firstChild)) === null || _a === void 0 ? void 0 : _a.toFixed(2)) !== null && _b !== void 0 ? _b : 0);
183
+ childHeight.current = {
184
+ first: firstChildHeight,
185
+ middle: Number((_d = (_c = getElementHeightWithMargins(secondChild)) === null || _c === void 0 ? void 0 : _c.toFixed(2)) !== null && _d !== void 0 ? _d : firstChildHeight),
186
+ last: Number((_f = (_e = getElementHeightWithMargins(lastChild)) === null || _e === void 0 ? void 0 : _e.toFixed(2)) !== null && _f !== void 0 ? _f : firstChildHeight),
187
+ };
126
188
  }, [visibleChildren.length]);
127
189
  var updateVirtualScroll = react_1.default.useCallback(function () {
128
- var _a, _b;
129
- var scrollableContainer = (_a = scrollContainer.current) !== null && _a !== void 0 ? _a : (_b = parentRef.current) === null || _b === void 0 ? void 0 : _b.ownerDocument.scrollingElement;
190
+ var scrollableContainer = getScrollableContainer();
130
191
  if (!scrollableContainer) {
131
192
  return;
132
193
  }
133
- var start = getNumberOfNodesInHeight(childHeight.current, scrollableContainer.scrollTop);
134
- var startIndex = Math.max(0, start - bufferSize);
194
+ var start = getNumberOfNodesInHeight(childHeight.current.middle, Math.round(scrollableContainer.scrollTop));
195
+ var visibleNodes = getVisibleNodeCount(childHeight.current.middle, start, itemsLength, scrollableContainer);
196
+ // If there are less items at the end than buffer size
197
+ // show more items at the start.
198
+ // Have boundaries for edge cases, e.g. 1 item length
199
+ var startIndex = Math.min(Math.max(0, start - bufferSize), Math.max(0, itemsLength - bufferSize * 2 - visibleNodes));
200
+ visibleIndex.current = { start: start, end: start + visibleNodes };
135
201
  setStartNode(startIndex);
136
- setVisibleNodeCount(getVisibleNodeCount(childHeight.current, start, itemsLength, scrollableContainer));
202
+ setVisibleNodeCount(visibleNodes);
137
203
  if (!parentRef.current) {
138
204
  return;
139
205
  }
140
- parentRef.current.style.transform = "translateY(".concat(getTranslateValue(childHeight.current, startIndex), "px)");
206
+ parentRef.current.style.transform = "translateY(".concat(getTranslateValue(childHeight.current.middle, startIndex), "px)");
141
207
  }, [bufferSize, itemsLength]);
208
+ var onScroll = react_1.default.useCallback(function () {
209
+ updateVirtualScroll();
210
+ }, [updateVirtualScroll]);
142
211
  var removeScrollListener = react_1.default.useCallback(function () {
143
212
  var _a, _b;
144
213
  if (!onScrollRef.current) {
@@ -153,22 +222,86 @@ exports.VirtualScroll = react_1.default.forwardRef(function (_a, ref) {
153
222
  react_1.default.useLayoutEffect(function () {
154
223
  var _a, _b;
155
224
  removeScrollListener();
156
- onScrollRef.current = updateVirtualScroll;
225
+ onScrollRef.current = onScroll;
157
226
  if (!scrollContainer.current ||
158
227
  scrollContainer.current === ((_a = parentRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument.body)) {
159
- (_b = parentRef.current) === null || _b === void 0 ? void 0 : _b.ownerDocument.addEventListener('scroll', updateVirtualScroll);
228
+ (_b = parentRef.current) === null || _b === void 0 ? void 0 : _b.ownerDocument.addEventListener('scroll', onScroll);
160
229
  }
161
230
  else {
162
- scrollContainer.current.addEventListener('scroll', updateVirtualScroll);
231
+ scrollContainer.current.addEventListener('scroll', onScroll);
163
232
  }
164
233
  return removeScrollListener;
165
- }, [updateVirtualScroll, removeScrollListener]);
234
+ }, [onScroll, removeScrollListener]);
235
+ react_1.default.useLayoutEffect(function () {
236
+ if (!isMounted) {
237
+ return;
238
+ }
239
+ var scrollableContainer = getScrollableContainer();
240
+ if (!scrollableContainer || scrollToIndex == null) {
241
+ return;
242
+ }
243
+ // if `scrollToIndex` is not visible, scroll to it
244
+ if (scrollToIndex > visibleIndex.current.end ||
245
+ scrollToIndex < visibleIndex.current.start) {
246
+ var indexDiff = scrollToIndex > visibleIndex.current.end
247
+ ? scrollToIndex - visibleIndex.current.end
248
+ : scrollToIndex - visibleIndex.current.start;
249
+ if (scrollToIndex === 0) {
250
+ scrollableContainer.scrollTo({ top: 0 });
251
+ return;
252
+ }
253
+ // If go down: add to the existing scrollTop needed height
254
+ // If go up: calculate the exact scroll top
255
+ scrollableContainer.scrollTo({
256
+ top: indexDiff > 0
257
+ ? Math.ceil(scrollableContainer.scrollTop) +
258
+ indexDiff * childHeight.current.middle
259
+ : scrollToIndex * childHeight.current.middle,
260
+ });
261
+ }
262
+ // if `scrollToIndex` is the first visible node
263
+ // ensure it is fully visible
264
+ if (scrollToIndex === visibleIndex.current.start) {
265
+ var roundedScrollTop = Math.round(scrollableContainer.scrollTop);
266
+ var diff = roundedScrollTop % childHeight.current.middle;
267
+ diff > 0 &&
268
+ scrollableContainer.scrollTo({
269
+ top: roundedScrollTop - diff,
270
+ });
271
+ return;
272
+ }
273
+ // if `scrollToIndex` is the last visible node
274
+ // ensure it is fully visible
275
+ if (scrollToIndex === visibleIndex.current.end) {
276
+ var diff = (scrollableContainer.offsetHeight - childHeight.current.first) %
277
+ childHeight.current.middle;
278
+ var roundedScrollTop = Math.ceil(scrollableContainer.scrollTop);
279
+ var scrollTopMod = roundedScrollTop % childHeight.current.middle;
280
+ if (diff > 0 && scrollTopMod === 0) {
281
+ scrollableContainer.scrollTo({
282
+ top: roundedScrollTop + childHeight.current.middle - diff,
283
+ });
284
+ }
285
+ }
286
+ }, [scrollToIndex, isMounted]);
166
287
  react_1.default.useLayoutEffect(function () {
288
+ if (!scrollContainerHeight) {
289
+ return;
290
+ }
167
291
  updateVirtualScroll();
168
- }, [scrollContainerHeight, itemsLength, updateVirtualScroll]);
169
- return (react_1.default.createElement("div", __assign({ style: __assign({ overflow: 'hidden', minHeight: itemsLength * childHeight.current, width: '100%' }, style), ref: ref }, rest),
170
- react_1.default.createElement("div", { style: {
171
- willChange: 'transform',
172
- }, ref: parentRef }, visibleChildren)));
173
- });
292
+ }, [scrollContainerHeight, updateVirtualScroll]);
293
+ return {
294
+ outerProps: __assign({ style: __assign({ overflow: 'hidden', minHeight: itemsLength > 1
295
+ ? Math.max(itemsLength - 2, 0) * childHeight.current.middle +
296
+ childHeight.current.first +
297
+ childHeight.current.last
298
+ : childHeight.current.middle, width: '100%' }, style) }, rest),
299
+ innerProps: {
300
+ style: { willChange: 'transform' },
301
+ ref: (0, hooks_1.mergeRefs)(parentRef), // convert object ref to callback ref for better types
302
+ },
303
+ visibleChildren: visibleChildren,
304
+ };
305
+ };
306
+ exports.useVirtualization = useVirtualization;
174
307
  exports.default = exports.VirtualScroll;
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ export declare type VisuallyHiddenProps = React.ComponentPropsWithRef<'div'>;
3
+ /**
4
+ * Hides content visually but is still accessible to screen readers.
5
+ */
6
+ export declare const VisuallyHidden: React.ForwardRefExoticComponent<Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
7
+ ref?: ((instance: HTMLDivElement | null) => void) | React.RefObject<HTMLDivElement> | null | undefined;
8
+ }, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & React.RefAttributes<HTMLDivElement>>;
9
+ export default VisuallyHidden;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __rest = (this && this.__rest) || function (s, e) {
14
+ var t = {};
15
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
16
+ t[p] = s[p];
17
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
18
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
19
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
20
+ t[p[i]] = s[p[i]];
21
+ }
22
+ return t;
23
+ };
24
+ var __importDefault = (this && this.__importDefault) || function (mod) {
25
+ return (mod && mod.__esModule) ? mod : { "default": mod };
26
+ };
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.VisuallyHidden = void 0;
29
+ /*---------------------------------------------------------------------------------------------
30
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
31
+ * See LICENSE.md in the project root for license terms and full copyright notice.
32
+ *--------------------------------------------------------------------------------------------*/
33
+ var react_1 = __importDefault(require("react"));
34
+ var classnames_1 = __importDefault(require("classnames"));
35
+ var hooks_1 = require("../hooks");
36
+ /**
37
+ * Hides content visually but is still accessible to screen readers.
38
+ */
39
+ exports.VisuallyHidden = react_1.default.forwardRef(function (props, ref) {
40
+ var className = props.className, rest = __rest(props, ["className"]);
41
+ (0, hooks_1.useTheme)();
42
+ return (react_1.default.createElement("div", __assign({ className: (0, classnames_1.default)('iui-visually-hidden', className), ref: ref }, rest)));
43
+ });
44
+ exports.default = exports.VisuallyHidden;
@@ -1,7 +1,6 @@
1
1
  /// <reference types="react" />
2
- import { CSSTransition } from 'react-transition-group';
3
2
  import { CSSTransitionProps } from 'react-transition-group/CSSTransition';
4
- export declare const WithCSSTransition: (props: Partial<CSSTransition.CSSTransitionProps> & {
3
+ export declare const WithCSSTransition: (props: Partial<CSSTransitionProps<undefined>> & {
5
4
  children: JSX.Element;
6
5
  dimension?: "width" | "height" | undefined;
7
6
  }) => JSX.Element;
@@ -1,8 +1,8 @@
1
1
  /// <reference types="react" />
2
2
  import { CommonProps } from '../props';
3
3
  export declare const StatusIconMap: {
4
- negative: (args?: CommonProps | undefined) => JSX.Element;
5
- positive: (args?: CommonProps | undefined) => JSX.Element;
6
- warning: (args?: CommonProps | undefined) => JSX.Element;
7
- informational: (args?: CommonProps | undefined) => JSX.Element;
4
+ negative: (args?: CommonProps) => JSX.Element;
5
+ positive: (args?: CommonProps) => JSX.Element;
6
+ warning: (args?: CommonProps) => JSX.Element;
7
+ informational: (args?: CommonProps) => JSX.Element;
8
8
  };
@@ -5,3 +5,4 @@ export * from './icons';
5
5
  export * from './WithCSSTransition';
6
6
  export * from './MiddleTextTruncation';
7
7
  export * from './VirtualScroll';
8
+ export * from './VisuallyHidden';
@@ -25,3 +25,4 @@ __exportStar(require("./icons"), exports);
25
25
  __exportStar(require("./WithCSSTransition"), exports);
26
26
  __exportStar(require("./MiddleTextTruncation"), exports);
27
27
  __exportStar(require("./VirtualScroll"), exports);
28
+ __exportStar(require("./VisuallyHidden"), exports);
@@ -78,8 +78,10 @@ var useOverflow = function (items, disabled, orientation) {
78
78
  var childrenSize = Array.from(containerRef.current.children).reduce(function (sum, child) { return sum + child["offset".concat(dimension)]; }, 0);
79
79
  var avgItemSize = childrenSize / visibleCount;
80
80
  var visibleItems = Math.floor(availableSize / avgItemSize);
81
- // Doubling the visible items to overflow the container. Just to be safe.
82
- setVisibleCount(Math.min(items.length, visibleItems * 2));
81
+ if (!isNaN(visibleItems)) {
82
+ // Doubling the visible items to overflow the container. Just to be safe.
83
+ setVisibleCount(Math.min(items.length, visibleItems * 2));
84
+ }
83
85
  }
84
86
  needsFullRerender.current = false;
85
87
  }, [containerSize, visibleCount, disabled, items.length, orientation]);
@@ -19,4 +19,4 @@ export declare type ThemeType = 'light' | 'dark' | 'os';
19
19
  * @param theme Light, dark, or based on OS setting.
20
20
  * @param themeOptions Options that override default theming behavior.
21
21
  */
22
- export declare const useTheme: (theme?: ThemeType | undefined, themeOptions?: ThemeOptions | undefined) => void;
22
+ export declare const useTheme: (theme?: ThemeType, themeOptions?: ThemeOptions) => void;
@@ -46,6 +46,10 @@ declare module 'react-table' {
46
46
  };
47
47
  isTableResizing?: boolean;
48
48
  columnReorderStartIndex: number;
49
+ sticky: {
50
+ isScrolledToRight?: boolean;
51
+ isScrolledToLeft?: boolean;
52
+ };
49
53
  }
50
54
  interface ColumnInterface<D extends object = {}> extends UseSortByColumnOptions<D>, UseFiltersColumnOptions<D>, UseResizeColumnsColumnOptions<D> {
51
55
  /**
@@ -91,12 +95,17 @@ declare module 'react-table' {
91
95
  * @default false
92
96
  */
93
97
  disableToggleVisibility?: boolean;
98
+ /**
99
+ * Side on which column should be sticked to.
100
+ */
101
+ sticky?: 'left' | 'right';
94
102
  }
95
103
  interface ColumnInstance<D extends object = {}> extends UseFiltersColumnProps<D>, UseGroupByColumnProps<D>, UseResizeColumnsColumnProps<D>, UseSortByColumnProps<D> {
96
104
  originalWidth: number;
97
105
  resizeWidth?: number;
98
106
  isResizerVisible?: boolean;
99
107
  getDragAndDropProps: () => TableKeyedProps;
108
+ originalSticky?: 'left' | 'right' | 'none';
100
109
  }
101
110
  interface Cell<D extends object = {}> extends UseGroupByCellProps<D>, UseRowStateCellProps<D> {
102
111
  }
@@ -58,19 +58,24 @@ export var Carousel = Object.assign(React.forwardRef(function (props, ref) {
58
58
  var id = React.useState(function () { var _a; return (_a = props.id) !== null && _a !== void 0 ? _a : "iui-carousel-".concat(getRandomValue(10)); })[0];
59
59
  useTheme();
60
60
  var isManuallyUpdating = React.useRef(false);
61
- var scrollInstantly = React.useRef(false);
62
61
  var carouselRef = React.useRef(null);
63
62
  var refs = useMergedRefs(carouselRef, ref);
64
- var _b = React.useState(userActiveIndex), currentIndex = _b[0], _setCurrentIndex = _b[1];
63
+ var _b = React.useState(userActiveIndex), currentIndex = _b[0], setCurrentIndex = _b[1];
64
+ var scrollToSlide = React.useRef(function () { }); // stub function populated in CarouselSlider
65
+ var justMounted = React.useRef(true);
65
66
  React.useEffect(function () {
66
- _setCurrentIndex(userActiveIndex);
67
- }, [userActiveIndex]);
68
- var setCurrentIndex = React.useCallback(function (index) {
69
67
  var _a;
70
- _setCurrentIndex(index);
71
- isManuallyUpdating.current = true;
72
- (_a = carouselRef.current) === null || _a === void 0 ? void 0 : _a.focus();
73
- }, []);
68
+ setCurrentIndex(userActiveIndex);
69
+ scrollToSlide.current(userActiveIndex, {
70
+ instant: justMounted.current,
71
+ });
72
+ // re-focus the carousel for keyboard nav, but not on first mount
73
+ // because it shows outline and might interfere with other components
74
+ if (!justMounted.current) {
75
+ (_a = carouselRef.current) === null || _a === void 0 ? void 0 : _a.focus({ preventScroll: true });
76
+ }
77
+ justMounted.current = false;
78
+ }, [userActiveIndex]);
74
79
  var _c = React.useState(0), slideCount = _c[0], setSlideCount = _c[1];
75
80
  var _d = React.useState({}), keysPressed = _d[0], setKeysPressed = _d[1];
76
81
  var handleKeyDown = function (event) {
@@ -88,12 +93,16 @@ export var Carousel = Object.assign(React.forwardRef(function (props, ref) {
88
93
  switch (event.key) {
89
94
  case 'ArrowLeft': {
90
95
  setKeysPressed(function (old) { return (__assign(__assign({}, old), { ArrowLeft: false })); });
91
- setCurrentIndex(function (old) { return (slideCount + old - 1) % slideCount; });
96
+ var prevIndex = (slideCount + currentIndex - 1) % slideCount;
97
+ scrollToSlide.current(prevIndex);
98
+ setCurrentIndex(prevIndex);
92
99
  break;
93
100
  }
94
101
  case 'ArrowRight': {
95
102
  setKeysPressed(function (old) { return (__assign(__assign({}, old), { ArrowRight: false })); });
96
- setCurrentIndex(function (old) { return (slideCount + old + 1) % slideCount; });
103
+ var nextIndex = (slideCount + currentIndex + 1) % slideCount;
104
+ scrollToSlide.current(nextIndex);
105
+ setCurrentIndex(nextIndex);
97
106
  break;
98
107
  }
99
108
  }
@@ -112,7 +121,7 @@ export var Carousel = Object.assign(React.forwardRef(function (props, ref) {
112
121
  keysPressed: keysPressed,
113
122
  idPrefix: id,
114
123
  isManuallyUpdating: isManuallyUpdating,
115
- scrollInstantly: scrollInstantly,
124
+ scrollToSlide: scrollToSlide,
116
125
  } }, children)));
117
126
  }), {
118
127
  Slider: 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>;
@@ -63,6 +63,7 @@ export var CarouselDotsList = React.forwardRef(function (props, ref) {
63
63
  var handleSlideChange = React.useCallback(function (index) {
64
64
  if (context) {
65
65
  context.setCurrentIndex(index);
66
+ context.scrollToSlide.current(index);
66
67
  }
67
68
  onSlideChange === null || onSlideChange === void 0 ? void 0 : onSlideChange(index);
68
69
  }, [context, onSlideChange]);
@@ -37,13 +37,12 @@ var PreviousButton = React.forwardRef(function (props, ref) {
37
37
  if (!context) {
38
38
  throw new Error('CarouselNavigation should be used inside Carousel');
39
39
  }
40
- var slideCount = context.slideCount, setCurrentIndex = context.setCurrentIndex, keysPressed = context.keysPressed, scrollInstantly = context.scrollInstantly;
40
+ var slideCount = context.slideCount, currentIndex = context.currentIndex, setCurrentIndex = context.setCurrentIndex, keysPressed = context.keysPressed, scrollToSlide = context.scrollToSlide;
41
41
  return (React.createElement(IconButton, __assign({ styleType: 'borderless', size: 'small', tabIndex: -1, "data-pressed": keysPressed['ArrowLeft'] || undefined, ref: ref }, props, { onClick: function (e) {
42
42
  var _a;
43
- if (e.detail > 3) {
44
- scrollInstantly.current = true;
45
- }
46
- setCurrentIndex(function (old) { return (slideCount + old - 1) % slideCount; });
43
+ var prevIndex = (slideCount + currentIndex - 1) % slideCount;
44
+ setCurrentIndex(prevIndex);
45
+ scrollToSlide.current(prevIndex, { instant: e.detail > 3 });
47
46
  (_a = props === null || props === void 0 ? void 0 : props.onClick) === null || _a === void 0 ? void 0 : _a.call(props, e);
48
47
  } }),
49
48
  React.createElement(SvgChevronLeft, null)));
@@ -54,13 +53,12 @@ var NextButton = React.forwardRef(function (props, ref) {
54
53
  if (!context) {
55
54
  throw new Error('CarouselNavigation should be used inside Carousel');
56
55
  }
57
- var slideCount = context.slideCount, setCurrentIndex = context.setCurrentIndex, keysPressed = context.keysPressed, scrollInstantly = context.scrollInstantly;
56
+ var slideCount = context.slideCount, currentIndex = context.currentIndex, setCurrentIndex = context.setCurrentIndex, keysPressed = context.keysPressed, scrollToSlide = context.scrollToSlide;
58
57
  return (React.createElement(IconButton, __assign({ styleType: 'borderless', size: 'small', tabIndex: -1, "data-pressed": keysPressed['ArrowRight'] || undefined, ref: ref }, props, { onClick: function (e) {
59
58
  var _a;
60
- if (e.detail > 3) {
61
- scrollInstantly.current = true;
62
- }
63
- setCurrentIndex(function (old) { return (slideCount + old + 1) % slideCount; });
59
+ var nextIndex = (slideCount + currentIndex + 1) % slideCount;
60
+ setCurrentIndex(nextIndex);
61
+ scrollToSlide.current(nextIndex, { instant: e.detail > 3 });
64
62
  (_a = props === null || props === void 0 ? void 0 : props.onClick) === null || _a === void 0 ? void 0 : _a.call(props, e);
65
63
  } }),
66
64
  React.createElement(SvgChevronRight, null)));
@@ -40,17 +40,13 @@ export var CarouselSlide = React.forwardRef(function (props, ref) {
40
40
  if (!context || index == null) {
41
41
  throw new Error('CarouselSlide must be used within Carousel');
42
42
  }
43
- var currentIndex = context.currentIndex, isManuallyUpdating = context.isManuallyUpdating, setCurrentIndex = context.setCurrentIndex;
43
+ var isManuallyUpdating = context.isManuallyUpdating, setCurrentIndex = context.setCurrentIndex;
44
44
  var updateActiveIndexOnScroll = React.useCallback(function () {
45
45
  // only update index if scroll was triggered by browser
46
- if (!isManuallyUpdating.current && currentIndex !== index) {
46
+ if (!isManuallyUpdating.current) {
47
47
  setCurrentIndex(index);
48
48
  }
49
- // when manual scroll completes, reset the state of `isManuallyUpdating` so that it's ready for future actions
50
- if (currentIndex === index) {
51
- isManuallyUpdating.current = false;
52
- }
53
- }, [currentIndex, index, isManuallyUpdating, setCurrentIndex]);
49
+ }, [index, isManuallyUpdating, setCurrentIndex]);
54
50
  var intersectionRef = useIntersection(updateActiveIndexOnScroll, { threshold: 0.5 }, false);
55
51
  var refs = useMergedRefs(intersectionRef, ref);
56
52
  return (React.createElement("li", __assign({ className: cx('iui-carousel-slider-item', className), role: 'tabpanel', "aria-roledescription": 'slide', ref: refs }, rest), children));
@@ -27,7 +27,7 @@ var __rest = (this && this.__rest) || function (s, e) {
27
27
  import React from 'react';
28
28
  import cx from 'classnames';
29
29
  import { CarouselContext } from './CarouselContext';
30
- import { getWindow, useMergedRefs, useResizeObserver } from '../utils';
30
+ import { getWindow, useMergedRefs } from '../utils';
31
31
  /**
32
32
  * `CarouselSlider` is the scrollable list that should consist of `CarouselSlide` components.
33
33
  */
@@ -37,7 +37,7 @@ export var CarouselSlider = React.forwardRef(function (props, ref) {
37
37
  if (!context) {
38
38
  throw new Error('CarouselSlider must be used within Carousel');
39
39
  }
40
- var currentIndex = context.currentIndex, setSlideCount = context.setSlideCount, idPrefix = context.idPrefix, isManuallyUpdating = context.isManuallyUpdating, scrollInstantly = context.scrollInstantly;
40
+ var setSlideCount = context.setSlideCount, idPrefix = context.idPrefix, scrollToSlide = context.scrollToSlide, isManuallyUpdating = context.isManuallyUpdating;
41
41
  var items = React.useMemo(function () {
42
42
  var _a;
43
43
  return (_a = React.Children.map(children, function (child, index) {
@@ -52,37 +52,32 @@ export var CarouselSlider = React.forwardRef(function (props, ref) {
52
52
  React.useLayoutEffect(function () {
53
53
  setSlideCount(items.length);
54
54
  }, [items.length, setSlideCount]);
55
- var _a = React.useState(), width = _a[0], setWidth = _a[1];
56
- var resizeRef = useResizeObserver(function (_a) {
57
- var width = _a.width;
58
- return setWidth(width);
59
- })[0];
60
55
  var sliderRef = React.useRef(null);
61
- var refs = useMergedRefs(sliderRef, resizeRef, ref);
62
- var justMounted = React.useRef(true);
63
- var previousWidth = React.useRef();
64
- React.useLayoutEffect(function () {
65
- var _a, _b, _c;
66
- var slideToShow = (_a = sliderRef.current) === null || _a === void 0 ? void 0 : _a.children.item(currentIndex);
67
- if (!sliderRef.current ||
68
- !slideToShow ||
69
- (!isManuallyUpdating.current && previousWidth.current === width)) {
56
+ var refs = useMergedRefs(sliderRef, ref);
57
+ scrollToSlide.current = function (slideIndex, _a) {
58
+ var _b, _c, _d;
59
+ var _e = _a === void 0 ? {} : _a, instant = _e.instant;
60
+ isManuallyUpdating.current = true; // start manual update
61
+ var slideToShow = (_b = sliderRef.current) === null || _b === void 0 ? void 0 : _b.children.item(slideIndex);
62
+ if (!sliderRef.current || !slideToShow) {
70
63
  return;
71
64
  }
72
- // instant scroll on first mount
73
- if (justMounted.current) {
74
- scrollInstantly.current = true;
75
- justMounted.current = false;
76
- }
77
- var motionOk = (_c = (_b = getWindow()) === null || _b === void 0 ? void 0 : _b.matchMedia('(prefers-reduced-motion: no-preference)')) === null || _c === void 0 ? void 0 : _c.matches;
65
+ var motionOk = (_d = (_c = getWindow()) === null || _c === void 0 ? void 0 : _c.matchMedia('(prefers-reduced-motion: no-preference)')) === null || _d === void 0 ? void 0 : _d.matches;
78
66
  sliderRef.current.scrollTo({
79
67
  left: slideToShow.offsetLeft - sliderRef.current.offsetLeft,
80
- behavior: (scrollInstantly.current || !motionOk
81
- ? 'instant'
82
- : 'smooth'), // scrollTo accepts 'instant' but ScrollBehavior type is wrong
68
+ behavior: (instant || !motionOk ? 'instant' : 'smooth'), // scrollTo accepts 'instant' but ScrollBehavior type is wrong
83
69
  });
84
- scrollInstantly.current = false;
85
- previousWidth.current = width;
86
- }, [currentIndex, isManuallyUpdating, scrollInstantly, width]);
87
- return (React.createElement("ol", __assign({ "aria-live": 'polite', className: cx('iui-carousel-slider', className), ref: refs }, rest), items));
70
+ };
71
+ var scrollTimeout = React.useRef();
72
+ // reset isManuallyUpdating.current to false after the last scroll event
73
+ var handleOnScroll = React.useCallback(function () {
74
+ var _a, _b;
75
+ if (scrollTimeout.current) {
76
+ (_a = getWindow()) === null || _a === void 0 ? void 0 : _a.clearTimeout(scrollTimeout.current);
77
+ }
78
+ scrollTimeout.current = (_b = getWindow()) === null || _b === void 0 ? void 0 : _b.setTimeout(function () {
79
+ isManuallyUpdating.current = false;
80
+ }, 100);
81
+ }, [isManuallyUpdating]);
82
+ return (React.createElement("ol", __assign({ "aria-live": 'polite', className: cx('iui-carousel-slider', className), ref: refs, onScroll: handleOnScroll }, rest), items));
88
83
  });