@itwin/itwinui-react 1.40.0 → 1.42.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 (50) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/cjs/core/ComboBox/ComboBox.js +22 -18
  3. package/cjs/core/ErrorPage/ErrorPage.d.ts +3 -1
  4. package/cjs/core/ErrorPage/ErrorPage.js +31 -1
  5. package/cjs/core/Modal/Modal.d.ts +1 -0
  6. package/cjs/core/Modal/Modal.js +11 -8
  7. package/cjs/core/Table/Table.d.ts +23 -0
  8. package/cjs/core/Table/Table.js +15 -9
  9. package/cjs/core/Table/TableRowMemoized.d.ts +4 -0
  10. package/cjs/core/Table/TableRowMemoized.js +15 -3
  11. package/cjs/core/Table/cells/EditableCell.js +7 -2
  12. package/cjs/core/Table/hooks/index.d.ts +1 -0
  13. package/cjs/core/Table/hooks/index.js +3 -1
  14. package/cjs/core/Table/hooks/useScrollToRow.d.ts +11 -0
  15. package/cjs/core/Table/hooks/useScrollToRow.js +49 -0
  16. package/cjs/core/Tree/Tree.d.ts +9 -0
  17. package/cjs/core/Tree/Tree.js +67 -19
  18. package/cjs/core/Tree/TreeContext.d.ts +4 -0
  19. package/cjs/core/Tree/TreeNode.js +8 -9
  20. package/cjs/core/Typography/Small/Small.js +1 -1
  21. package/cjs/core/utils/components/VirtualScroll.js +2 -2
  22. package/cjs/core/utils/hooks/index.d.ts +1 -0
  23. package/cjs/core/utils/hooks/index.js +1 -0
  24. package/cjs/core/utils/hooks/useLatestRef.d.ts +9 -0
  25. package/cjs/core/utils/hooks/useLatestRef.js +26 -0
  26. package/esm/core/ComboBox/ComboBox.js +23 -19
  27. package/esm/core/ErrorPage/ErrorPage.d.ts +3 -1
  28. package/esm/core/ErrorPage/ErrorPage.js +31 -1
  29. package/esm/core/Modal/Modal.d.ts +1 -0
  30. package/esm/core/Modal/Modal.js +11 -8
  31. package/esm/core/Table/Table.d.ts +23 -0
  32. package/esm/core/Table/Table.js +17 -11
  33. package/esm/core/Table/TableRowMemoized.d.ts +4 -0
  34. package/esm/core/Table/TableRowMemoized.js +15 -3
  35. package/esm/core/Table/cells/EditableCell.js +7 -2
  36. package/esm/core/Table/hooks/index.d.ts +1 -0
  37. package/esm/core/Table/hooks/index.js +1 -0
  38. package/esm/core/Table/hooks/useScrollToRow.d.ts +11 -0
  39. package/esm/core/Table/hooks/useScrollToRow.js +42 -0
  40. package/esm/core/Tree/Tree.d.ts +9 -0
  41. package/esm/core/Tree/Tree.js +68 -20
  42. package/esm/core/Tree/TreeContext.d.ts +4 -0
  43. package/esm/core/Tree/TreeNode.js +8 -9
  44. package/esm/core/Typography/Small/Small.js +1 -1
  45. package/esm/core/utils/components/VirtualScroll.js +2 -2
  46. package/esm/core/utils/hooks/index.d.ts +1 -0
  47. package/esm/core/utils/hooks/index.js +1 -0
  48. package/esm/core/utils/hooks/useLatestRef.d.ts +9 -0
  49. package/esm/core/utils/hooks/useLatestRef.js +19 -0
  50. package/package.json +4 -4
@@ -24,14 +24,25 @@ import { TableCell } from './TableCell';
24
24
  * When adding new features check whether it changes state that affects row. If it does then add equality check to `React.memo`.
25
25
  */
26
26
  export var TableRow = function (props) {
27
- var row = props.row, rowProps = props.rowProps, isLast = props.isLast, onRowInViewport = props.onRowInViewport, onBottomReached = props.onBottomReached, intersectionMargin = props.intersectionMargin, onClick = props.onClick, subComponent = props.subComponent, isDisabled = props.isDisabled, tableHasSubRows = props.tableHasSubRows, tableInstance = props.tableInstance, expanderCell = props.expanderCell;
27
+ var row = props.row, rowProps = props.rowProps, isLast = props.isLast, onRowInViewport = props.onRowInViewport, onBottomReached = props.onBottomReached, intersectionMargin = props.intersectionMargin, onClick = props.onClick, subComponent = props.subComponent, isDisabled = props.isDisabled, tableHasSubRows = props.tableHasSubRows, tableInstance = props.tableInstance, expanderCell = props.expanderCell, bodyRef = props.bodyRef, tableRowRef = props.tableRowRef;
28
28
  var onIntersect = React.useCallback(function () {
29
29
  var _a, _b;
30
30
  (_a = onRowInViewport.current) === null || _a === void 0 ? void 0 : _a.call(onRowInViewport, row.original);
31
31
  isLast && ((_b = onBottomReached.current) === null || _b === void 0 ? void 0 : _b.call(onBottomReached));
32
32
  }, [isLast, onBottomReached, onRowInViewport, row.original]);
33
- var rowRef = useIntersection(onIntersect, {
33
+ var intersectionRoot = React.useMemo(function () {
34
+ var _a, _b;
35
+ var isTableBodyScrollable = ((_a = bodyRef === null || bodyRef === void 0 ? void 0 : bodyRef.scrollHeight) !== null && _a !== void 0 ? _a : 0) > ((_b = bodyRef === null || bodyRef === void 0 ? void 0 : bodyRef.offsetHeight) !== null && _b !== void 0 ? _b : 0);
36
+ // If table body is scrollable, make it the intersection root
37
+ if (isTableBodyScrollable) {
38
+ return bodyRef;
39
+ }
40
+ // Otherwise, make the viewport the intersection root
41
+ return undefined;
42
+ }, [bodyRef]);
43
+ var intersectionRef = useIntersection(onIntersect, {
34
44
  rootMargin: "".concat(intersectionMargin, "px"),
45
+ root: intersectionRoot,
35
46
  });
36
47
  var userRowProps = rowProps === null || rowProps === void 0 ? void 0 : rowProps(row);
37
48
  var mergedProps = __assign(__assign(__assign({}, row.getRowProps({ style: { flex: "0 0 auto", minWidth: '100%' } })), userRowProps), {
@@ -41,7 +52,7 @@ export var TableRow = function (props) {
41
52
  'iui-disabled': isDisabled,
42
53
  }, userRowProps === null || userRowProps === void 0 ? void 0 : userRowProps.className),
43
54
  });
44
- var refs = useMergedRefs(rowRef, mergedProps.ref);
55
+ var refs = useMergedRefs(intersectionRef, mergedProps.ref, tableRowRef);
45
56
  return (React.createElement(React.Fragment, null,
46
57
  React.createElement("div", __assign({}, mergedProps, { ref: refs, onClick: function (event) {
47
58
  var _a;
@@ -90,6 +101,7 @@ export var TableRowMemoized = React.memo(TableRow, function (prevProp, nextProp)
90
101
  prevProp.rowProps === nextProp.rowProps &&
91
102
  prevProp.expanderCell === nextProp.expanderCell &&
92
103
  prevProp.tableHasSubRows === nextProp.tableHasSubRows &&
104
+ prevProp.bodyRef === nextProp.bodyRef &&
93
105
  prevProp.state.columnOrder === nextProp.state.columnOrder &&
94
106
  !nextProp.state.columnResizing.isResizingColumn &&
95
107
  prevProp.state.isTableResizing === nextProp.state.isTableResizing &&
@@ -25,6 +25,7 @@ var __rest = (this && this.__rest) || function (s, e) {
25
25
  * See LICENSE.md in the project root for license terms and full copyright notice.
26
26
  *--------------------------------------------------------------------------------------------*/
27
27
  import React from 'react';
28
+ import { getRandomValue } from '../../utils';
28
29
  /**
29
30
  * Editable cell.
30
31
  * It should be passed to `cellRenderer`.
@@ -47,8 +48,9 @@ export var EditableCell = function (props) {
47
48
  React.useEffect(function () {
48
49
  setValue(sanitizeString(cellProps.value));
49
50
  }, [cellProps.value]);
50
- var _b = React.useState(false), isDirty = _b[0], setIsDirty = _b[1];
51
- return (React.createElement("div", __assign({}, cellElementProps, { contentEditable: true, suppressContentEditableWarning: true }, rest, { onInput: function (e) {
51
+ var _b = React.useState(getRandomValue(10)), key = _b[0], setKey = _b[1];
52
+ var _c = React.useState(false), isDirty = _c[0], setIsDirty = _c[1];
53
+ return (React.createElement("div", __assign({}, cellElementProps, { contentEditable: true, suppressContentEditableWarning: true, key: key }, rest, { onInput: function (e) {
52
54
  var _a;
53
55
  setValue(sanitizeString(e.target.innerText));
54
56
  setIsDirty(true);
@@ -59,6 +61,9 @@ export var EditableCell = function (props) {
59
61
  onCellEdit(cellProps.column.id, value, cellProps.row.original);
60
62
  }
61
63
  (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
64
+ // Prevents error when text is cleared.
65
+ // New key makes React to reattach with the DOM so it won't complain about deleted text node.
66
+ setKey(getRandomValue(10));
62
67
  }, onKeyDown: function (e) {
63
68
  var _a;
64
69
  // Prevents from adding HTML elements (div, br) inside a cell on Enter press
@@ -4,4 +4,5 @@ export { useSubRowFiltering } from './useSubRowFiltering';
4
4
  export { useSubRowSelection } from './useSubRowSelection';
5
5
  export { useResizeColumns } from './useResizeColumns';
6
6
  export { useColumnDragAndDrop } from './useColumnDragAndDrop';
7
+ export { useScrollToRow } from './useScrollToRow';
7
8
  export { useStickyColumns } from './useStickyColumns';
@@ -8,4 +8,5 @@ export { useSubRowFiltering } from './useSubRowFiltering';
8
8
  export { useSubRowSelection } from './useSubRowSelection';
9
9
  export { useResizeColumns } from './useResizeColumns';
10
10
  export { useColumnDragAndDrop } from './useColumnDragAndDrop';
11
+ export { useScrollToRow } from './useScrollToRow';
11
12
  export { useStickyColumns } from './useStickyColumns';
@@ -0,0 +1,11 @@
1
+ import type { Row } from 'react-table';
2
+ import { TableProps } from '../Table';
3
+ declare type ScrollToRow<T extends Record<string, unknown>> = {
4
+ scrollToIndex: number | undefined;
5
+ tableRowRef: (row: Row<T>) => (element: HTMLDivElement) => void;
6
+ };
7
+ declare type ScrollToRowProps<T extends Record<string, unknown>> = TableProps<T> & {
8
+ page: Row<T>[];
9
+ };
10
+ export declare function useScrollToRow<T extends Record<string, unknown>>({ data, enableVirtualization, page, paginatorRenderer, scrollToRow, onBottomReached, }: ScrollToRowProps<T>): ScrollToRow<T>;
11
+ export {};
@@ -0,0 +1,42 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import React from 'react';
6
+ export function useScrollToRow(_a) {
7
+ var data = _a.data, enableVirtualization = _a.enableVirtualization, page = _a.page, paginatorRenderer = _a.paginatorRenderer, scrollToRow = _a.scrollToRow, onBottomReached = _a.onBottomReached;
8
+ var rowRefs = React.useRef({});
9
+ // Refs prevents from having `page` and `data` as dependencies
10
+ // therefore we avoid unnecessary scroll to row.
11
+ var pageRef = React.useRef(page);
12
+ pageRef.current = page;
13
+ var dataRef = React.useRef(data);
14
+ dataRef.current = data;
15
+ // For virtualized tables, all we need to do is pass the index of the item
16
+ // to the VirtualScroll component
17
+ var scrollToIndex = React.useMemo(function () {
18
+ if (!scrollToRow || paginatorRenderer || onBottomReached) {
19
+ return undefined;
20
+ }
21
+ var index = scrollToRow(pageRef.current, dataRef.current);
22
+ return index < 0 ? undefined : index;
23
+ }, [onBottomReached, paginatorRenderer, scrollToRow]);
24
+ // For non-virtualized tables, we need to add a ref to each row
25
+ // and scroll to the element
26
+ React.useEffect(function () {
27
+ var _a;
28
+ if (enableVirtualization ||
29
+ scrollToIndex === undefined ||
30
+ scrollToIndex === null ||
31
+ scrollToIndex < 0) {
32
+ return;
33
+ }
34
+ (_a = rowRefs.current[pageRef.current[scrollToIndex].id]) === null || _a === void 0 ? void 0 : _a.scrollIntoView();
35
+ }, [enableVirtualization, scrollToIndex]);
36
+ var tableRowRef = React.useCallback(function (row) {
37
+ return function (element) {
38
+ rowRefs.current[row.id] = element;
39
+ };
40
+ }, []);
41
+ return { scrollToIndex: scrollToIndex, tableRowRef: tableRowRef };
42
+ }
@@ -68,6 +68,15 @@ export declare type TreeProps<T> = {
68
68
  * }, [expandedNodes]);
69
69
  */
70
70
  getNode: (node: T) => NodeData<T>;
71
+ /**
72
+ * Virtualization is used to have a better performance with a lot of nodes.
73
+ *
74
+ * When enabled, Tree DOM structure will change - it will have a wrapper div
75
+ * to which `className` and `style` will be applied.
76
+ * @default false
77
+ * @beta
78
+ */
79
+ enableVirtualization?: boolean;
71
80
  } & Omit<CommonProps, 'title'>;
72
81
  /**
73
82
  * Tree component used to display a hierarchical structure of `TreeNodes`.
@@ -25,7 +25,7 @@ var __rest = (this && this.__rest) || function (s, e) {
25
25
  * See LICENSE.md in the project root for license terms and full copyright notice.
26
26
  *--------------------------------------------------------------------------------------------*/
27
27
  import React from 'react';
28
- import { useTheme, getFocusableElements } from '../utils';
28
+ import { useTheme, getFocusableElements, useVirtualization, mergeRefs, } from '../utils';
29
29
  import '@itwin/itwinui-css/css/tree.css';
30
30
  import cx from 'classnames';
31
31
  import { TreeContext } from './TreeContext';
@@ -80,7 +80,7 @@ import { TreeContext } from './TreeContext';
80
80
  />
81
81
  */
82
82
  export var Tree = function (props) {
83
- var data = props.data, className = props.className, nodeRenderer = props.nodeRenderer, getNode = props.getNode, rest = __rest(props, ["data", "className", "nodeRenderer", "getNode"]);
83
+ var data = props.data, className = props.className, nodeRenderer = props.nodeRenderer, getNode = props.getNode, _a = props.enableVirtualization, enableVirtualization = _a === void 0 ? false : _a, style = props.style, rest = __rest(props, ["data", "className", "nodeRenderer", "getNode", "enableVirtualization", "style"]);
84
84
  useTheme();
85
85
  var treeRef = React.useRef(null);
86
86
  var focusedIndex = React.useRef(0);
@@ -118,7 +118,7 @@ export var Tree = function (props) {
118
118
  break;
119
119
  }
120
120
  };
121
- var _a = React.useMemo(function () {
121
+ var _b = React.useMemo(function () {
122
122
  var flatList = [];
123
123
  var firstLevelNodes = [];
124
124
  var flattenNodes = function (nodes, depth, parentNode) {
@@ -147,24 +147,72 @@ export var Tree = function (props) {
147
147
  };
148
148
  flattenNodes(data);
149
149
  return [flatList, firstLevelNodes];
150
- }, [data, getNode]), flatNodesList = _a[0], firstLevelNodesList = _a[1];
151
- return (React.createElement("ul", __assign({ className: cx('iui-tree', className), role: 'tree', onKeyDown: handleKeyDown, ref: treeRef, tabIndex: 0, onFocus: function () {
152
- var _a;
153
- var items = getFocusableNodes();
154
- if (items.length > 0) {
155
- (_a = items[focusedIndex.current]) === null || _a === void 0 ? void 0 : _a.focus();
156
- }
157
- } }, rest), flatNodesList.map(function (flatNode) {
150
+ }, [data, getNode]), flatNodesList = _b[0], firstLevelNodesList = _b[1];
151
+ var itemRenderer = React.useCallback(function (index) {
158
152
  var _a, _b, _c, _d;
159
- return (React.createElement(TreeContext.Provider, { key: flatNode.nodeProps.nodeId, value: {
160
- nodeDepth: flatNode.depth,
161
- subNodeIds: flatNode.subNodeIds,
162
- groupSize: flatNode.depth === 0
153
+ var node = flatNodesList[index];
154
+ return (React.createElement(TreeContext.Provider, { key: node.nodeProps.nodeId, value: {
155
+ nodeDepth: node.depth,
156
+ subNodeIds: node.subNodeIds,
157
+ groupSize: node.depth === 0
163
158
  ? firstLevelNodesList.length
164
- : (_c = (_b = (_a = flatNode.parentNode) === null || _a === void 0 ? void 0 : _a.subNodeIds) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0,
165
- indexInGroup: flatNode.indexInGroup,
166
- parentNodeId: (_d = flatNode.parentNode) === null || _d === void 0 ? void 0 : _d.nodeProps.nodeId,
167
- } }, nodeRenderer(flatNode.nodeProps)));
168
- })));
159
+ : (_c = (_b = (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.subNodeIds) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0,
160
+ indexInGroup: node.indexInGroup,
161
+ parentNodeId: (_d = node.parentNode) === null || _d === void 0 ? void 0 : _d.nodeProps.nodeId,
162
+ scrollToParent: node.parentNode
163
+ ? function () {
164
+ var _a;
165
+ var parentNodeId = (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.nodeProps.nodeId;
166
+ var parentNodeIndex = flatNodesList.findIndex(function (n) { return n.nodeProps.nodeId === parentNodeId; });
167
+ setScrollToIndex(parentNodeIndex);
168
+ }
169
+ : undefined,
170
+ } }, nodeRenderer(node.nodeProps)));
171
+ }, [firstLevelNodesList.length, flatNodesList, nodeRenderer]);
172
+ var _c = React.useState(), scrollToIndex = _c[0], setScrollToIndex = _c[1];
173
+ var flatNodesListRef = React.useRef(flatNodesList);
174
+ React.useEffect(function () {
175
+ flatNodesListRef.current = flatNodesList;
176
+ }, [flatNodesList]);
177
+ React.useEffect(function () {
178
+ setTimeout(function () {
179
+ var _a;
180
+ if (scrollToIndex !== undefined) {
181
+ var nodeId = flatNodesListRef.current[scrollToIndex].nodeProps.nodeId;
182
+ var nodeElement = (_a = treeRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument.querySelector("#".concat(nodeId));
183
+ nodeElement === null || nodeElement === void 0 ? void 0 : nodeElement.focus();
184
+ // Need to reset that if navigating with mouse and keyboard,
185
+ // e.g. pressing arrow left to go to parent node and then with mouse
186
+ // clicking some other child node and then pressing arrow left
187
+ setScrollToIndex(undefined);
188
+ }
189
+ });
190
+ }, [scrollToIndex]);
191
+ var handleFocus = function (event) {
192
+ var _a, _b;
193
+ if ((_a = treeRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.relatedTarget)) {
194
+ return;
195
+ }
196
+ var items = getFocusableNodes();
197
+ if (items.length > 0) {
198
+ (_b = items[focusedIndex.current]) === null || _b === void 0 ? void 0 : _b.focus();
199
+ }
200
+ };
201
+ return (React.createElement(React.Fragment, null, enableVirtualization ? (React.createElement(VirtualizedTree, __assign({ flatNodesList: flatNodesList, itemRenderer: itemRenderer, scrollToIndex: scrollToIndex, onFocus: handleFocus, onKeyDown: handleKeyDown, ref: treeRef, className: className, style: style }, rest))) : (React.createElement(TreeElement, __assign({ onKeyDown: handleKeyDown, onFocus: handleFocus, className: className, style: style, ref: treeRef }, rest), flatNodesList.map(function (_, i) { return itemRenderer(i); })))));
169
202
  };
203
+ var TreeElement = React.forwardRef(function (_a, ref) {
204
+ var children = _a.children, className = _a.className, rest = __rest(_a, ["children", "className"]);
205
+ return (React.createElement("ul", __assign({ className: cx('iui-tree', className), role: 'tree', ref: ref, tabIndex: 0 }, rest), children));
206
+ });
207
+ // Having virtualized tree separately prevents from running all virtualization logic
208
+ var VirtualizedTree = React.forwardRef(function (_a, ref) {
209
+ var flatNodesList = _a.flatNodesList, itemRenderer = _a.itemRenderer, scrollToIndex = _a.scrollToIndex, className = _a.className, style = _a.style, rest = __rest(_a, ["flatNodesList", "itemRenderer", "scrollToIndex", "className", "style"]);
210
+ var _b = useVirtualization({
211
+ itemsLength: flatNodesList.length,
212
+ itemRenderer: itemRenderer,
213
+ scrollToIndex: scrollToIndex,
214
+ }), outerProps = _b.outerProps, innerProps = _b.innerProps, visibleChildren = _b.visibleChildren;
215
+ return (React.createElement("div", __assign({}, __assign(__assign({}, outerProps), { className: cx(className, outerProps.className), style: __assign(__assign({}, style), outerProps.style) })),
216
+ React.createElement(TreeElement, __assign({}, innerProps, rest, { ref: mergeRefs(ref, innerProps.ref) }), visibleChildren)));
217
+ });
170
218
  export default Tree;
@@ -20,6 +20,10 @@ export declare type TreeContextProps = {
20
20
  * Node index in the list of nodes under the same parent node or in the root. Used for an accessibility attribute.
21
21
  */
22
22
  indexInGroup: number;
23
+ /**
24
+ * Function that scrolls to the node's parent node.
25
+ */
26
+ scrollToParent?: () => void;
23
27
  };
24
28
  export declare const TreeContext: React.Context<TreeContextProps | undefined>;
25
29
  export declare const useTreeContext: () => TreeContextProps;
@@ -52,7 +52,7 @@ import { useTreeContext } from './TreeContext';
52
52
  export var TreeNode = function (props) {
53
53
  var nodeId = props.nodeId, label = props.label, sublabel = props.sublabel, children = props.children, className = props.className, icon = props.icon, _a = props.hasSubNodes, hasSubNodes = _a === void 0 ? false : _a, _b = props.isDisabled, isDisabled = _b === void 0 ? false : _b, _c = props.isExpanded, isExpanded = _c === void 0 ? false : _c, _d = props.isSelected, isSelected = _d === void 0 ? false : _d, onSelected = props.onSelected, onExpanded = props.onExpanded, checkbox = props.checkbox, expander = props.expander, rest = __rest(props, ["nodeId", "label", "sublabel", "children", "className", "icon", "hasSubNodes", "isDisabled", "isExpanded", "isSelected", "onSelected", "onExpanded", "checkbox", "expander"]);
54
54
  useTheme();
55
- var _e = useTreeContext(), nodeDepth = _e.nodeDepth, _f = _e.subNodeIds, subNodeIds = _f === void 0 ? [] : _f, parentNodeId = _e.parentNodeId, groupSize = _e.groupSize, indexInGroup = _e.indexInGroup;
55
+ var _e = useTreeContext(), nodeDepth = _e.nodeDepth, _f = _e.subNodeIds, subNodeIds = _f === void 0 ? [] : _f, parentNodeId = _e.parentNodeId, scrollToParent = _e.scrollToParent, groupSize = _e.groupSize, indexInGroup = _e.indexInGroup;
56
56
  var _g = React.useState(false), isFocused = _g[0], setIsFocused = _g[1];
57
57
  var nodeRef = React.useRef(null);
58
58
  var styleDepth = React.useMemo(function () {
@@ -62,7 +62,7 @@ export var TreeNode = function (props) {
62
62
  : { marginLeft: nodeDepth ? nodeDepth * 28 : 0 };
63
63
  }, [nodeDepth]);
64
64
  var onKeyDown = function (event) {
65
- var _a, _b, _c, _d, _e, _f, _g;
65
+ var _a, _b, _c, _d, _e, _f;
66
66
  var isNodeFocused = nodeRef.current === ((_a = nodeRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument.activeElement);
67
67
  switch (event.key) {
68
68
  case 'ArrowLeft': {
@@ -73,20 +73,19 @@ export var TreeNode = function (props) {
73
73
  break;
74
74
  }
75
75
  if (parentNodeId) {
76
- var parentNode = (_b = nodeRef.current) === null || _b === void 0 ? void 0 : _b.ownerDocument.querySelector("#".concat(parentNodeId));
77
- parentNode === null || parentNode === void 0 ? void 0 : parentNode.focus();
76
+ scrollToParent === null || scrollToParent === void 0 ? void 0 : scrollToParent();
78
77
  break;
79
78
  }
80
79
  // If it is top level node (doesn't have parent node), then do nothing.
81
80
  break;
82
81
  }
83
82
  var focusableElements = getFocusableElements(nodeRef.current);
84
- var currentIndex = focusableElements.indexOf((_c = nodeRef.current) === null || _c === void 0 ? void 0 : _c.ownerDocument.activeElement);
83
+ var currentIndex = focusableElements.indexOf((_b = nodeRef.current) === null || _b === void 0 ? void 0 : _b.ownerDocument.activeElement);
85
84
  if (currentIndex === 0) {
86
- (_d = nodeRef.current) === null || _d === void 0 ? void 0 : _d.focus();
85
+ (_c = nodeRef.current) === null || _c === void 0 ? void 0 : _c.focus();
87
86
  }
88
87
  else {
89
- (_e = focusableElements[currentIndex - 1]) === null || _e === void 0 ? void 0 : _e.focus();
88
+ (_d = focusableElements[currentIndex - 1]) === null || _d === void 0 ? void 0 : _d.focus();
90
89
  }
91
90
  break;
92
91
  }
@@ -98,10 +97,10 @@ export var TreeNode = function (props) {
98
97
  onExpanded(nodeId, true);
99
98
  break;
100
99
  }
101
- (_f = focusableElements[0]) === null || _f === void 0 ? void 0 : _f.focus();
100
+ (_e = focusableElements[0]) === null || _e === void 0 ? void 0 : _e.focus();
102
101
  break;
103
102
  }
104
- var currentIndex = focusableElements.indexOf((_g = nodeRef.current) === null || _g === void 0 ? void 0 : _g.ownerDocument.activeElement);
103
+ var currentIndex = focusableElements.indexOf((_f = nodeRef.current) === null || _f === void 0 ? void 0 : _f.ownerDocument.activeElement);
105
104
  if (currentIndex < focusableElements.length - 1) {
106
105
  focusableElements[currentIndex + 1].focus();
107
106
  break;
@@ -37,6 +37,6 @@ import '@itwin/itwinui-css/css/text.css';
37
37
  export var Small = React.forwardRef(function (props, ref) {
38
38
  var className = props.className, _a = props.isMuted, isMuted = _a === void 0 ? false : _a, rest = __rest(props, ["className", "isMuted"]);
39
39
  useTheme();
40
- return (React.createElement("p", __assign({ ref: ref, className: cx('iui-text-small', { 'iui-text-muted': isMuted }, className) }, rest)));
40
+ return (React.createElement("small", __assign({ ref: ref, className: cx('iui-text-small', { 'iui-text-muted': isMuted }, className) }, rest)));
41
41
  });
42
42
  export default Small;
@@ -285,11 +285,11 @@ export var useVirtualization = function (props) {
285
285
  updateVirtualScroll();
286
286
  }, [scrollContainerHeight, updateVirtualScroll]);
287
287
  return {
288
- outerProps: __assign({ style: __assign({ overflow: 'hidden', minHeight: itemsLength > 1
288
+ outerProps: __assign({ style: __assign({ minHeight: itemsLength > 1
289
289
  ? Math.max(itemsLength - 2, 0) * childHeight.current.middle +
290
290
  childHeight.current.first +
291
291
  childHeight.current.last
292
- : childHeight.current.middle, width: '100%' }, style) }, rest),
292
+ : childHeight.current.middle, minWidth: '100%' }, style) }, rest),
293
293
  innerProps: {
294
294
  style: { willChange: 'transform' },
295
295
  ref: mergeRefs(parentRef), // convert object ref to callback ref for better types
@@ -7,3 +7,4 @@ export * from './useTheme';
7
7
  export * from './useIntersection';
8
8
  export * from './useMediaQuery';
9
9
  export * from './useSafeContext';
10
+ export * from './useLatestRef';
@@ -11,3 +11,4 @@ export * from './useTheme';
11
11
  export * from './useIntersection';
12
12
  export * from './useMediaQuery';
13
13
  export * from './useSafeContext';
14
+ export * from './useLatestRef';
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ /**
3
+ * Hook that keeps track of the latest value in a ref.
4
+ * @private
5
+ * @example
6
+ * const { value } = props;
7
+ * const valueRef = useLatestRef(value);
8
+ */
9
+ export declare const useLatestRef: <T>(value: T) => React.MutableRefObject<T>;
@@ -0,0 +1,19 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import React from 'react';
6
+ /**
7
+ * Hook that keeps track of the latest value in a ref.
8
+ * @private
9
+ * @example
10
+ * const { value } = props;
11
+ * const valueRef = useLatestRef(value);
12
+ */
13
+ export var useLatestRef = function (value) {
14
+ var valueRef = React.useRef(value);
15
+ React.useEffect(function () {
16
+ valueRef.current = value;
17
+ }, [value]);
18
+ return valueRef;
19
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itwin/itwinui-react",
3
- "version": "1.40.0",
3
+ "version": "1.42.0",
4
4
  "author": "Bentley Systems",
5
5
  "license": "MIT",
6
6
  "main": "cjs/index.js",
@@ -35,15 +35,15 @@
35
35
  "clean:coverage": "rimraf coverage",
36
36
  "test": "jest",
37
37
  "test:watch": "jest --watch",
38
- "createComponent": "node scripts/createComponent.js",
39
38
  "format": "prettier --config .prettierrc **/*.{tsx,ts,js} --ignore-path .gitignore --write",
40
39
  "lint": "eslint \"**/*.{js,ts,tsx}\" --max-warnings=0",
41
40
  "lint:fix": "yarn lint --fix && node ../configs/copyrightLinter.js --fix \"*/**/*.{js,ts,tsx}\"",
42
41
  "copy-files": "cpy \"../../{README,LICENSE}.md\" .",
43
- "dev": "yarn build:watch"
42
+ "dev": "yarn build:watch",
43
+ "createComponent": "node ../../scripts/createComponent.js"
44
44
  },
45
45
  "dependencies": {
46
- "@itwin/itwinui-css": "^0.59.2",
46
+ "@itwin/itwinui-css": "^0.61.0",
47
47
  "@itwin/itwinui-icons-react": "^1.10.1",
48
48
  "@itwin/itwinui-illustrations-react": "^1.3.1",
49
49
  "@tippyjs/react": "^4.2.5",