@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.
- package/CHANGELOG.md +34 -0
- package/cjs/core/ComboBox/ComboBox.js +22 -18
- package/cjs/core/ErrorPage/ErrorPage.d.ts +3 -1
- package/cjs/core/ErrorPage/ErrorPage.js +31 -1
- package/cjs/core/Modal/Modal.d.ts +1 -0
- package/cjs/core/Modal/Modal.js +11 -8
- package/cjs/core/Table/Table.d.ts +23 -0
- package/cjs/core/Table/Table.js +15 -9
- package/cjs/core/Table/TableRowMemoized.d.ts +4 -0
- package/cjs/core/Table/TableRowMemoized.js +15 -3
- package/cjs/core/Table/cells/EditableCell.js +7 -2
- package/cjs/core/Table/hooks/index.d.ts +1 -0
- package/cjs/core/Table/hooks/index.js +3 -1
- package/cjs/core/Table/hooks/useScrollToRow.d.ts +11 -0
- package/cjs/core/Table/hooks/useScrollToRow.js +49 -0
- package/cjs/core/Tree/Tree.d.ts +9 -0
- package/cjs/core/Tree/Tree.js +67 -19
- package/cjs/core/Tree/TreeContext.d.ts +4 -0
- package/cjs/core/Tree/TreeNode.js +8 -9
- package/cjs/core/Typography/Small/Small.js +1 -1
- package/cjs/core/utils/components/VirtualScroll.js +2 -2
- package/cjs/core/utils/hooks/index.d.ts +1 -0
- package/cjs/core/utils/hooks/index.js +1 -0
- package/cjs/core/utils/hooks/useLatestRef.d.ts +9 -0
- package/cjs/core/utils/hooks/useLatestRef.js +26 -0
- package/esm/core/ComboBox/ComboBox.js +23 -19
- package/esm/core/ErrorPage/ErrorPage.d.ts +3 -1
- package/esm/core/ErrorPage/ErrorPage.js +31 -1
- package/esm/core/Modal/Modal.d.ts +1 -0
- package/esm/core/Modal/Modal.js +11 -8
- package/esm/core/Table/Table.d.ts +23 -0
- package/esm/core/Table/Table.js +17 -11
- package/esm/core/Table/TableRowMemoized.d.ts +4 -0
- package/esm/core/Table/TableRowMemoized.js +15 -3
- package/esm/core/Table/cells/EditableCell.js +7 -2
- package/esm/core/Table/hooks/index.d.ts +1 -0
- package/esm/core/Table/hooks/index.js +1 -0
- package/esm/core/Table/hooks/useScrollToRow.d.ts +11 -0
- package/esm/core/Table/hooks/useScrollToRow.js +42 -0
- package/esm/core/Tree/Tree.d.ts +9 -0
- package/esm/core/Tree/Tree.js +68 -20
- package/esm/core/Tree/TreeContext.d.ts +4 -0
- package/esm/core/Tree/TreeNode.js +8 -9
- package/esm/core/Typography/Small/Small.js +1 -1
- package/esm/core/utils/components/VirtualScroll.js +2 -2
- package/esm/core/utils/hooks/index.d.ts +1 -0
- package/esm/core/utils/hooks/index.js +1 -0
- package/esm/core/utils/hooks/useLatestRef.d.ts +9 -0
- package/esm/core/utils/hooks/useLatestRef.js +19 -0
- package/package.json +4 -4
package/cjs/core/Tree/Tree.js
CHANGED
|
@@ -86,7 +86,7 @@ var TreeContext_1 = require("./TreeContext");
|
|
|
86
86
|
/>
|
|
87
87
|
*/
|
|
88
88
|
var Tree = function (props) {
|
|
89
|
-
var data = props.data, className = props.className, nodeRenderer = props.nodeRenderer, getNode = props.getNode, rest = __rest(props, ["data", "className", "nodeRenderer", "getNode"]);
|
|
89
|
+
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"]);
|
|
90
90
|
(0, utils_1.useTheme)();
|
|
91
91
|
var treeRef = react_1.default.useRef(null);
|
|
92
92
|
var focusedIndex = react_1.default.useRef(0);
|
|
@@ -124,7 +124,7 @@ var Tree = function (props) {
|
|
|
124
124
|
break;
|
|
125
125
|
}
|
|
126
126
|
};
|
|
127
|
-
var
|
|
127
|
+
var _b = react_1.default.useMemo(function () {
|
|
128
128
|
var flatList = [];
|
|
129
129
|
var firstLevelNodes = [];
|
|
130
130
|
var flattenNodes = function (nodes, depth, parentNode) {
|
|
@@ -153,25 +153,73 @@ var Tree = function (props) {
|
|
|
153
153
|
};
|
|
154
154
|
flattenNodes(data);
|
|
155
155
|
return [flatList, firstLevelNodes];
|
|
156
|
-
}, [data, getNode]), flatNodesList =
|
|
157
|
-
|
|
158
|
-
var _a;
|
|
159
|
-
var items = getFocusableNodes();
|
|
160
|
-
if (items.length > 0) {
|
|
161
|
-
(_a = items[focusedIndex.current]) === null || _a === void 0 ? void 0 : _a.focus();
|
|
162
|
-
}
|
|
163
|
-
} }, rest), flatNodesList.map(function (flatNode) {
|
|
156
|
+
}, [data, getNode]), flatNodesList = _b[0], firstLevelNodesList = _b[1];
|
|
157
|
+
var itemRenderer = react_1.default.useCallback(function (index) {
|
|
164
158
|
var _a, _b, _c, _d;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
159
|
+
var node = flatNodesList[index];
|
|
160
|
+
return (react_1.default.createElement(TreeContext_1.TreeContext.Provider, { key: node.nodeProps.nodeId, value: {
|
|
161
|
+
nodeDepth: node.depth,
|
|
162
|
+
subNodeIds: node.subNodeIds,
|
|
163
|
+
groupSize: node.depth === 0
|
|
169
164
|
? firstLevelNodesList.length
|
|
170
|
-
: (_c = (_b = (_a =
|
|
171
|
-
indexInGroup:
|
|
172
|
-
parentNodeId: (_d =
|
|
173
|
-
|
|
174
|
-
|
|
165
|
+
: (_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,
|
|
166
|
+
indexInGroup: node.indexInGroup,
|
|
167
|
+
parentNodeId: (_d = node.parentNode) === null || _d === void 0 ? void 0 : _d.nodeProps.nodeId,
|
|
168
|
+
scrollToParent: node.parentNode
|
|
169
|
+
? function () {
|
|
170
|
+
var _a;
|
|
171
|
+
var parentNodeId = (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.nodeProps.nodeId;
|
|
172
|
+
var parentNodeIndex = flatNodesList.findIndex(function (n) { return n.nodeProps.nodeId === parentNodeId; });
|
|
173
|
+
setScrollToIndex(parentNodeIndex);
|
|
174
|
+
}
|
|
175
|
+
: undefined,
|
|
176
|
+
} }, nodeRenderer(node.nodeProps)));
|
|
177
|
+
}, [firstLevelNodesList.length, flatNodesList, nodeRenderer]);
|
|
178
|
+
var _c = react_1.default.useState(), scrollToIndex = _c[0], setScrollToIndex = _c[1];
|
|
179
|
+
var flatNodesListRef = react_1.default.useRef(flatNodesList);
|
|
180
|
+
react_1.default.useEffect(function () {
|
|
181
|
+
flatNodesListRef.current = flatNodesList;
|
|
182
|
+
}, [flatNodesList]);
|
|
183
|
+
react_1.default.useEffect(function () {
|
|
184
|
+
setTimeout(function () {
|
|
185
|
+
var _a;
|
|
186
|
+
if (scrollToIndex !== undefined) {
|
|
187
|
+
var nodeId = flatNodesListRef.current[scrollToIndex].nodeProps.nodeId;
|
|
188
|
+
var nodeElement = (_a = treeRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument.querySelector("#".concat(nodeId));
|
|
189
|
+
nodeElement === null || nodeElement === void 0 ? void 0 : nodeElement.focus();
|
|
190
|
+
// Need to reset that if navigating with mouse and keyboard,
|
|
191
|
+
// e.g. pressing arrow left to go to parent node and then with mouse
|
|
192
|
+
// clicking some other child node and then pressing arrow left
|
|
193
|
+
setScrollToIndex(undefined);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}, [scrollToIndex]);
|
|
197
|
+
var handleFocus = function (event) {
|
|
198
|
+
var _a, _b;
|
|
199
|
+
if ((_a = treeRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.relatedTarget)) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
var items = getFocusableNodes();
|
|
203
|
+
if (items.length > 0) {
|
|
204
|
+
(_b = items[focusedIndex.current]) === null || _b === void 0 ? void 0 : _b.focus();
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
return (react_1.default.createElement(react_1.default.Fragment, null, enableVirtualization ? (react_1.default.createElement(VirtualizedTree, __assign({ flatNodesList: flatNodesList, itemRenderer: itemRenderer, scrollToIndex: scrollToIndex, onFocus: handleFocus, onKeyDown: handleKeyDown, ref: treeRef, className: className, style: style }, rest))) : (react_1.default.createElement(TreeElement, __assign({ onKeyDown: handleKeyDown, onFocus: handleFocus, className: className, style: style, ref: treeRef }, rest), flatNodesList.map(function (_, i) { return itemRenderer(i); })))));
|
|
175
208
|
};
|
|
176
209
|
exports.Tree = Tree;
|
|
210
|
+
var TreeElement = react_1.default.forwardRef(function (_a, ref) {
|
|
211
|
+
var children = _a.children, className = _a.className, rest = __rest(_a, ["children", "className"]);
|
|
212
|
+
return (react_1.default.createElement("ul", __assign({ className: (0, classnames_1.default)('iui-tree', className), role: 'tree', ref: ref, tabIndex: 0 }, rest), children));
|
|
213
|
+
});
|
|
214
|
+
// Having virtualized tree separately prevents from running all virtualization logic
|
|
215
|
+
var VirtualizedTree = react_1.default.forwardRef(function (_a, ref) {
|
|
216
|
+
var flatNodesList = _a.flatNodesList, itemRenderer = _a.itemRenderer, scrollToIndex = _a.scrollToIndex, className = _a.className, style = _a.style, rest = __rest(_a, ["flatNodesList", "itemRenderer", "scrollToIndex", "className", "style"]);
|
|
217
|
+
var _b = (0, utils_1.useVirtualization)({
|
|
218
|
+
itemsLength: flatNodesList.length,
|
|
219
|
+
itemRenderer: itemRenderer,
|
|
220
|
+
scrollToIndex: scrollToIndex,
|
|
221
|
+
}), outerProps = _b.outerProps, innerProps = _b.innerProps, visibleChildren = _b.visibleChildren;
|
|
222
|
+
return (react_1.default.createElement("div", __assign({}, __assign(__assign({}, outerProps), { className: (0, classnames_1.default)(className, outerProps.className), style: __assign(__assign({}, style), outerProps.style) })),
|
|
223
|
+
react_1.default.createElement(TreeElement, __assign({}, innerProps, rest, { ref: (0, utils_1.mergeRefs)(ref, innerProps.ref) }), visibleChildren)));
|
|
224
|
+
});
|
|
177
225
|
exports.default = exports.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;
|
|
@@ -58,7 +58,7 @@ var TreeContext_1 = require("./TreeContext");
|
|
|
58
58
|
var TreeNode = function (props) {
|
|
59
59
|
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"]);
|
|
60
60
|
(0, utils_1.useTheme)();
|
|
61
|
-
var _e = (0, TreeContext_1.useTreeContext)(), nodeDepth = _e.nodeDepth, _f = _e.subNodeIds, subNodeIds = _f === void 0 ? [] : _f, parentNodeId = _e.parentNodeId, groupSize = _e.groupSize, indexInGroup = _e.indexInGroup;
|
|
61
|
+
var _e = (0, TreeContext_1.useTreeContext)(), nodeDepth = _e.nodeDepth, _f = _e.subNodeIds, subNodeIds = _f === void 0 ? [] : _f, parentNodeId = _e.parentNodeId, scrollToParent = _e.scrollToParent, groupSize = _e.groupSize, indexInGroup = _e.indexInGroup;
|
|
62
62
|
var _g = react_1.default.useState(false), isFocused = _g[0], setIsFocused = _g[1];
|
|
63
63
|
var nodeRef = react_1.default.useRef(null);
|
|
64
64
|
var styleDepth = react_1.default.useMemo(function () {
|
|
@@ -68,7 +68,7 @@ var TreeNode = function (props) {
|
|
|
68
68
|
: { marginLeft: nodeDepth ? nodeDepth * 28 : 0 };
|
|
69
69
|
}, [nodeDepth]);
|
|
70
70
|
var onKeyDown = function (event) {
|
|
71
|
-
var _a, _b, _c, _d, _e, _f
|
|
71
|
+
var _a, _b, _c, _d, _e, _f;
|
|
72
72
|
var isNodeFocused = nodeRef.current === ((_a = nodeRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument.activeElement);
|
|
73
73
|
switch (event.key) {
|
|
74
74
|
case 'ArrowLeft': {
|
|
@@ -79,20 +79,19 @@ var TreeNode = function (props) {
|
|
|
79
79
|
break;
|
|
80
80
|
}
|
|
81
81
|
if (parentNodeId) {
|
|
82
|
-
|
|
83
|
-
parentNode === null || parentNode === void 0 ? void 0 : parentNode.focus();
|
|
82
|
+
scrollToParent === null || scrollToParent === void 0 ? void 0 : scrollToParent();
|
|
84
83
|
break;
|
|
85
84
|
}
|
|
86
85
|
// If it is top level node (doesn't have parent node), then do nothing.
|
|
87
86
|
break;
|
|
88
87
|
}
|
|
89
88
|
var focusableElements = (0, utils_1.getFocusableElements)(nodeRef.current);
|
|
90
|
-
var currentIndex = focusableElements.indexOf((
|
|
89
|
+
var currentIndex = focusableElements.indexOf((_b = nodeRef.current) === null || _b === void 0 ? void 0 : _b.ownerDocument.activeElement);
|
|
91
90
|
if (currentIndex === 0) {
|
|
92
|
-
(
|
|
91
|
+
(_c = nodeRef.current) === null || _c === void 0 ? void 0 : _c.focus();
|
|
93
92
|
}
|
|
94
93
|
else {
|
|
95
|
-
(
|
|
94
|
+
(_d = focusableElements[currentIndex - 1]) === null || _d === void 0 ? void 0 : _d.focus();
|
|
96
95
|
}
|
|
97
96
|
break;
|
|
98
97
|
}
|
|
@@ -104,10 +103,10 @@ var TreeNode = function (props) {
|
|
|
104
103
|
onExpanded(nodeId, true);
|
|
105
104
|
break;
|
|
106
105
|
}
|
|
107
|
-
(
|
|
106
|
+
(_e = focusableElements[0]) === null || _e === void 0 ? void 0 : _e.focus();
|
|
108
107
|
break;
|
|
109
108
|
}
|
|
110
|
-
var currentIndex = focusableElements.indexOf((
|
|
109
|
+
var currentIndex = focusableElements.indexOf((_f = nodeRef.current) === null || _f === void 0 ? void 0 : _f.ownerDocument.activeElement);
|
|
111
110
|
if (currentIndex < focusableElements.length - 1) {
|
|
112
111
|
focusableElements[currentIndex + 1].focus();
|
|
113
112
|
break;
|
|
@@ -43,6 +43,6 @@ require("@itwin/itwinui-css/css/text.css");
|
|
|
43
43
|
exports.Small = react_1.default.forwardRef(function (props, ref) {
|
|
44
44
|
var className = props.className, _a = props.isMuted, isMuted = _a === void 0 ? false : _a, rest = __rest(props, ["className", "isMuted"]);
|
|
45
45
|
(0, utils_1.useTheme)();
|
|
46
|
-
return (react_1.default.createElement("
|
|
46
|
+
return (react_1.default.createElement("small", __assign({ ref: ref, className: (0, classnames_1.default)('iui-text-small', { 'iui-text-muted': isMuted }, className) }, rest)));
|
|
47
47
|
});
|
|
48
48
|
exports.default = exports.Small;
|
|
@@ -291,11 +291,11 @@ var useVirtualization = function (props) {
|
|
|
291
291
|
updateVirtualScroll();
|
|
292
292
|
}, [scrollContainerHeight, updateVirtualScroll]);
|
|
293
293
|
return {
|
|
294
|
-
outerProps: __assign({ style: __assign({
|
|
294
|
+
outerProps: __assign({ style: __assign({ minHeight: itemsLength > 1
|
|
295
295
|
? Math.max(itemsLength - 2, 0) * childHeight.current.middle +
|
|
296
296
|
childHeight.current.first +
|
|
297
297
|
childHeight.current.last
|
|
298
|
-
: childHeight.current.middle,
|
|
298
|
+
: childHeight.current.middle, minWidth: '100%' }, style) }, rest),
|
|
299
299
|
innerProps: {
|
|
300
300
|
style: { willChange: 'transform' },
|
|
301
301
|
ref: (0, hooks_1.mergeRefs)(parentRef), // convert object ref to callback ref for better types
|
|
@@ -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,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.useLatestRef = void 0;
|
|
7
|
+
/*---------------------------------------------------------------------------------------------
|
|
8
|
+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
9
|
+
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
10
|
+
*--------------------------------------------------------------------------------------------*/
|
|
11
|
+
var react_1 = __importDefault(require("react"));
|
|
12
|
+
/**
|
|
13
|
+
* Hook that keeps track of the latest value in a ref.
|
|
14
|
+
* @private
|
|
15
|
+
* @example
|
|
16
|
+
* const { value } = props;
|
|
17
|
+
* const valueRef = useLatestRef(value);
|
|
18
|
+
*/
|
|
19
|
+
var useLatestRef = function (value) {
|
|
20
|
+
var valueRef = react_1.default.useRef(value);
|
|
21
|
+
react_1.default.useEffect(function () {
|
|
22
|
+
valueRef.current = value;
|
|
23
|
+
}, [value]);
|
|
24
|
+
return valueRef;
|
|
25
|
+
};
|
|
26
|
+
exports.useLatestRef = useLatestRef;
|
|
@@ -28,7 +28,7 @@ import React from 'react';
|
|
|
28
28
|
import cx from 'classnames';
|
|
29
29
|
import { MenuExtraContent } from '../Menu';
|
|
30
30
|
import { Text } from '../Typography';
|
|
31
|
-
import { useTheme, getRandomValue, mergeRefs, } from '../utils';
|
|
31
|
+
import { useTheme, getRandomValue, mergeRefs, useLatestRef, } from '../utils';
|
|
32
32
|
import 'tippy.js/animations/shift-away.css';
|
|
33
33
|
import { ComboBoxActionContext, comboBoxReducer, ComboBoxRefsContext, ComboBoxStateContext, } from './helpers';
|
|
34
34
|
import { ComboBoxDropdown } from './ComboBoxDropdown';
|
|
@@ -68,11 +68,10 @@ export var ComboBox = function (props) {
|
|
|
68
68
|
var inputRef = React.useRef(null);
|
|
69
69
|
var menuRef = React.useRef(null);
|
|
70
70
|
var toggleButtonRef = React.useRef(null);
|
|
71
|
-
|
|
72
|
-
var
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}, [onChange]);
|
|
71
|
+
var mounted = React.useRef(false);
|
|
72
|
+
var valuePropRef = useLatestRef(valueProp);
|
|
73
|
+
var onChangeProp = useLatestRef(onChange);
|
|
74
|
+
var optionsRef = useLatestRef(options);
|
|
76
75
|
// Record to store all extra information (e.g. original indexes), where the key is the id of the option
|
|
77
76
|
var optionsExtraInfoRef = React.useRef({});
|
|
78
77
|
// Clear the extra info when the options change so that it can be reinitialized below
|
|
@@ -91,7 +90,9 @@ export var ComboBox = function (props) {
|
|
|
91
90
|
// Reducer where all the component-wide state is stored
|
|
92
91
|
var _e = React.useReducer(comboBoxReducer, {
|
|
93
92
|
isOpen: false,
|
|
94
|
-
selectedIndex:
|
|
93
|
+
selectedIndex: valueProp
|
|
94
|
+
? optionsRef.current.findIndex(function (option) { return option.value === valueProp; })
|
|
95
|
+
: -1,
|
|
95
96
|
focusedIndex: -1,
|
|
96
97
|
}), _f = _e[0], isOpen = _f.isOpen, selectedIndex = _f.selectedIndex, focusedIndex = _f.focusedIndex, dispatch = _e[1];
|
|
97
98
|
React.useLayoutEffect(function () {
|
|
@@ -99,7 +100,7 @@ export var ComboBox = function (props) {
|
|
|
99
100
|
// When the dropdown opens
|
|
100
101
|
if (isOpen) {
|
|
101
102
|
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); // Focus the input
|
|
102
|
-
setFilteredOptions(
|
|
103
|
+
setFilteredOptions(optionsRef.current); // Reset the filtered list
|
|
103
104
|
dispatch(['focus']);
|
|
104
105
|
}
|
|
105
106
|
// When the dropdown closes
|
|
@@ -108,10 +109,10 @@ export var ComboBox = function (props) {
|
|
|
108
109
|
dispatch(['focus']);
|
|
109
110
|
// Reset the input value
|
|
110
111
|
setInputValue(selectedIndex != undefined && selectedIndex >= 0
|
|
111
|
-
? (_b =
|
|
112
|
+
? (_b = optionsRef.current[selectedIndex]) === null || _b === void 0 ? void 0 : _b.label
|
|
112
113
|
: '');
|
|
113
114
|
}
|
|
114
|
-
}, [isOpen,
|
|
115
|
+
}, [isOpen, optionsRef, selectedIndex]);
|
|
115
116
|
// Set min-width of menu to be same as input
|
|
116
117
|
var _g = React.useState(0), minWidth = _g[0], setMinWidth = _g[1];
|
|
117
118
|
React.useEffect(function () {
|
|
@@ -142,14 +143,14 @@ export var ComboBox = function (props) {
|
|
|
142
143
|
var value = event.currentTarget.value;
|
|
143
144
|
setInputValue(value);
|
|
144
145
|
dispatch(['open']); // reopen when typing
|
|
145
|
-
setFilteredOptions((_a = filterFunction === null || filterFunction === void 0 ? void 0 : filterFunction(
|
|
146
|
+
setFilteredOptions((_a = filterFunction === null || filterFunction === void 0 ? void 0 : filterFunction(optionsRef.current, value)) !== null && _a !== void 0 ? _a : optionsRef.current.filter(function (option) {
|
|
146
147
|
return option.label.toLowerCase().includes(value.toLowerCase());
|
|
147
148
|
}));
|
|
148
149
|
if (focusedIndex != -1) {
|
|
149
150
|
dispatch(['focus', -1]);
|
|
150
151
|
}
|
|
151
152
|
(_b = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onChange) === null || _b === void 0 ? void 0 : _b.call(inputProps, event);
|
|
152
|
-
}, [filterFunction, focusedIndex, inputProps,
|
|
153
|
+
}, [filterFunction, focusedIndex, inputProps, optionsRef]);
|
|
153
154
|
// When the value prop changes, update the selectedIndex
|
|
154
155
|
React.useEffect(function () {
|
|
155
156
|
dispatch([
|
|
@@ -160,14 +161,17 @@ export var ComboBox = function (props) {
|
|
|
160
161
|
// Call user-defined onChange when the value actually changes
|
|
161
162
|
React.useEffect(function () {
|
|
162
163
|
var _a, _b;
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
// Prevent user-defined onChange to be called on mount
|
|
165
|
+
if (!mounted.current) {
|
|
166
|
+
mounted.current = true;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
var currentValue = (_a = optionsRef.current[selectedIndex]) === null || _a === void 0 ? void 0 : _a.value;
|
|
170
|
+
if (currentValue === valuePropRef.current || selectedIndex === -1) {
|
|
171
|
+
return;
|
|
169
172
|
}
|
|
170
|
-
|
|
173
|
+
(_b = onChangeProp.current) === null || _b === void 0 ? void 0 : _b.call(onChangeProp, currentValue);
|
|
174
|
+
}, [onChangeProp, optionsRef, selectedIndex, valuePropRef]);
|
|
171
175
|
var getMenuItem = React.useCallback(function (option, filteredIndex) {
|
|
172
176
|
var optionId = getOptionId(option, id);
|
|
173
177
|
var __originalIndex = optionsExtraInfoRef.current[optionId].__originalIndex;
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { CommonProps } from '../utils';
|
|
3
3
|
import '@itwin/itwinui-css/css/non-ideal-state.css';
|
|
4
|
-
export declare type ErrorPageType = '401' | '403' | '404' | '500' | '502' | '503' | 'generic';
|
|
4
|
+
export declare type ErrorPageType = '300' | '301' | '302' | '303' | '304' | '305' | '307' | '308' | '401' | '403' | '404' | '408' | '500' | '502' | '503' | '504' | 'generic';
|
|
5
5
|
export declare type ErrorTypeTranslations = {
|
|
6
6
|
badGateway: string;
|
|
7
7
|
error: string;
|
|
8
8
|
forbidden: string;
|
|
9
9
|
internalServerError: string;
|
|
10
|
+
redirect?: string;
|
|
10
11
|
pageNotFound: string;
|
|
11
12
|
serviceUnavailable: string;
|
|
13
|
+
timedOut?: string;
|
|
12
14
|
unauthorized: string;
|
|
13
15
|
};
|
|
14
16
|
export declare type ErrorPageProps = {
|
|
@@ -31,6 +31,8 @@ import Svg500 from '@itwin/itwinui-illustrations-react/cjs/illustrations/500';
|
|
|
31
31
|
import Svg502 from '@itwin/itwinui-illustrations-react/cjs/illustrations/502';
|
|
32
32
|
import Svg503 from '@itwin/itwinui-illustrations-react/cjs/illustrations/503';
|
|
33
33
|
import SvgError from '@itwin/itwinui-illustrations-react/cjs/illustrations/Error';
|
|
34
|
+
import SvgRedirect from '@itwin/itwinui-illustrations-react/cjs/illustrations/Redirect';
|
|
35
|
+
import SvgTimedOut from '@itwin/itwinui-illustrations-react/cjs/illustrations/TimedOut';
|
|
34
36
|
import React from 'react';
|
|
35
37
|
import { Button } from '../Buttons/Button';
|
|
36
38
|
import { useTheme } from '../utils';
|
|
@@ -44,9 +46,19 @@ import '@itwin/itwinui-css/css/non-ideal-state.css';
|
|
|
44
46
|
export var ErrorPage = function (props) {
|
|
45
47
|
var errorType = props.errorType, errorName = props.errorName, errorMessage = props.errorMessage, primaryButtonHandle = props.primaryButtonHandle, primaryButtonLabel = props.primaryButtonLabel, secondaryButtonHandle = props.secondaryButtonHandle, secondaryButtonLabel = props.secondaryButtonLabel, translatedErrorMessages = props.translatedErrorMessages, className = props.className, rest = __rest(props, ["errorType", "errorName", "errorMessage", "primaryButtonHandle", "primaryButtonLabel", "secondaryButtonHandle", "secondaryButtonLabel", "translatedErrorMessages", "className"]);
|
|
46
48
|
useTheme();
|
|
47
|
-
var defaultErrorMessages = __assign({ badGateway: 'Bad gateway', error: 'Error', forbidden: 'Forbidden', internalServerError: 'Internal server error', pageNotFound: 'Page not found', serviceUnavailable: 'Service unavailable', unauthorized: 'Unauthorized' }, translatedErrorMessages);
|
|
49
|
+
var defaultErrorMessages = __assign({ badGateway: 'Bad gateway', error: 'Error', forbidden: 'Forbidden', internalServerError: 'Internal server error', redirect: 'Redirect', pageNotFound: 'Page not found', serviceUnavailable: 'Service unavailable', timedOut: 'Timed out', unauthorized: 'Unauthorized' }, translatedErrorMessages);
|
|
48
50
|
function getErrorIcon() {
|
|
49
51
|
switch (errorType) {
|
|
52
|
+
case '300':
|
|
53
|
+
case '301':
|
|
54
|
+
case '302':
|
|
55
|
+
case '303':
|
|
56
|
+
case '304':
|
|
57
|
+
case '305':
|
|
58
|
+
case '307':
|
|
59
|
+
case '308': {
|
|
60
|
+
return React.createElement(SvgRedirect, { className: 'iui-non-ideal-state-illustration' });
|
|
61
|
+
}
|
|
50
62
|
case '401': {
|
|
51
63
|
return React.createElement(Svg401, { className: 'iui-non-ideal-state-illustration' });
|
|
52
64
|
}
|
|
@@ -56,6 +68,10 @@ export var ErrorPage = function (props) {
|
|
|
56
68
|
case '404': {
|
|
57
69
|
return React.createElement(Svg404, { className: 'iui-non-ideal-state-illustration' });
|
|
58
70
|
}
|
|
71
|
+
case '408':
|
|
72
|
+
case '504': {
|
|
73
|
+
return React.createElement(SvgTimedOut, { className: 'iui-non-ideal-state-illustration' });
|
|
74
|
+
}
|
|
59
75
|
case '500': {
|
|
60
76
|
return React.createElement(Svg500, { className: 'iui-non-ideal-state-illustration' });
|
|
61
77
|
}
|
|
@@ -76,6 +92,16 @@ export var ErrorPage = function (props) {
|
|
|
76
92
|
return errorName;
|
|
77
93
|
}
|
|
78
94
|
switch (errorType) {
|
|
95
|
+
case '300':
|
|
96
|
+
case '301':
|
|
97
|
+
case '302':
|
|
98
|
+
case '303':
|
|
99
|
+
case '304':
|
|
100
|
+
case '305':
|
|
101
|
+
case '307':
|
|
102
|
+
case '308': {
|
|
103
|
+
return defaultErrorMessages.redirect || '';
|
|
104
|
+
}
|
|
79
105
|
case '401': {
|
|
80
106
|
return defaultErrorMessages.unauthorized;
|
|
81
107
|
}
|
|
@@ -85,6 +111,10 @@ export var ErrorPage = function (props) {
|
|
|
85
111
|
case '404': {
|
|
86
112
|
return defaultErrorMessages.pageNotFound;
|
|
87
113
|
}
|
|
114
|
+
case '408':
|
|
115
|
+
case '504': {
|
|
116
|
+
return defaultErrorMessages.timedOut || '';
|
|
117
|
+
}
|
|
88
118
|
case '500': {
|
|
89
119
|
return defaultErrorMessages.internalServerError;
|
|
90
120
|
}
|
package/esm/core/Modal/Modal.js
CHANGED
|
@@ -30,6 +30,7 @@ import cx from 'classnames';
|
|
|
30
30
|
import SvgClose from '@itwin/itwinui-icons-react/cjs/icons/Close';
|
|
31
31
|
import { useTheme, getContainer, getDocument, FocusTrap, } from '../utils';
|
|
32
32
|
import '@itwin/itwinui-css/css/dialog.css';
|
|
33
|
+
import '@itwin/itwinui-css/css/backdrop.css';
|
|
33
34
|
import { IconButton } from '../Buttons/IconButton';
|
|
34
35
|
import { CSSTransition } from 'react-transition-group';
|
|
35
36
|
/**
|
|
@@ -112,14 +113,16 @@ export var Modal = function (props) {
|
|
|
112
113
|
onClose(event);
|
|
113
114
|
}
|
|
114
115
|
};
|
|
115
|
-
return !!container ? (ReactDOM.createPortal(React.createElement(
|
|
116
|
+
return !!container ? (ReactDOM.createPortal(React.createElement(React.Fragment, null,
|
|
117
|
+
React.createElement("div", { className: cx('iui-backdrop', { 'iui-backdrop-visible': isOpen }), tabIndex: -1, onKeyDown: handleKeyDown, ref: overlayRef, onMouseDown: handleMouseDown }),
|
|
116
118
|
React.createElement(FocusTrap, null,
|
|
117
|
-
React.createElement("div",
|
|
118
|
-
React.createElement(
|
|
119
|
-
React.createElement("div", { className: 'iui-dialog-
|
|
120
|
-
React.createElement("div", { className: 'iui-dialog-title' },
|
|
121
|
-
|
|
122
|
-
React.createElement(
|
|
123
|
-
|
|
119
|
+
React.createElement("div", null,
|
|
120
|
+
React.createElement(CSSTransition, { in: isOpen, classNames: 'iui-dialog-animation', timeout: { exit: 600 }, unmountOnExit: true },
|
|
121
|
+
React.createElement("div", __assign({ className: cx('iui-dialog', { 'iui-dialog-default': styleType === 'default' }, { 'iui-dialog-full-page': styleType === 'fullPage' }, { 'iui-dialog-visible': isOpen }, className), id: id, style: style, role: 'dialog', "aria-modal": 'true' }, rest),
|
|
122
|
+
React.createElement("div", { className: 'iui-dialog-title-bar' },
|
|
123
|
+
React.createElement("div", { className: 'iui-dialog-title' }, title),
|
|
124
|
+
isDismissible && (React.createElement(IconButton, { size: 'small', styleType: 'borderless', onClick: onClose, "aria-label": 'Close' },
|
|
125
|
+
React.createElement(SvgClose, null)))),
|
|
126
|
+
children))))), container)) : (React.createElement(React.Fragment, null));
|
|
124
127
|
};
|
|
125
128
|
export default Modal;
|
|
@@ -182,6 +182,29 @@ export declare type TableProps<T extends Record<string, unknown> = Record<string
|
|
|
182
182
|
* @default false
|
|
183
183
|
*/
|
|
184
184
|
enableColumnReordering?: boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Function that returns index of the row that you want to scroll to.
|
|
187
|
+
*
|
|
188
|
+
* It doesn't work with paginated tables and with lazy-loading.
|
|
189
|
+
* @beta
|
|
190
|
+
* @example
|
|
191
|
+
* <Table
|
|
192
|
+
* scrollToRow={React.useCallback(
|
|
193
|
+
* (rows, data) => rows.findIndex((row) => row.original === data[250]),
|
|
194
|
+
* []
|
|
195
|
+
* )}
|
|
196
|
+
* {...restProps}
|
|
197
|
+
* />
|
|
198
|
+
* @example
|
|
199
|
+
* <Table
|
|
200
|
+
* scrollToRow={React.useCallback(
|
|
201
|
+
* (rows, data) => rows.findIndex((row) => row.original.id === data[250].id),
|
|
202
|
+
* []
|
|
203
|
+
* )}
|
|
204
|
+
* {...restProps}
|
|
205
|
+
* />
|
|
206
|
+
*/
|
|
207
|
+
scrollToRow?: (rows: Row<T>[], data: T[]) => number;
|
|
185
208
|
} & Omit<CommonProps, 'title'>;
|
|
186
209
|
/**
|
|
187
210
|
* Table based on [react-table](https://react-table.tanstack.com/docs/api/overview).
|
package/esm/core/Table/Table.js
CHANGED
|
@@ -28,7 +28,7 @@ import React from 'react';
|
|
|
28
28
|
import cx from 'classnames';
|
|
29
29
|
import { actions as TableActions, useFlexLayout, useFilters, useRowSelect, useSortBy, useTable, useExpanded, usePagination, useColumnOrder, } from 'react-table';
|
|
30
30
|
import { ProgressRadial } from '../ProgressIndicators';
|
|
31
|
-
import { useTheme, useResizeObserver } from '../utils';
|
|
31
|
+
import { useTheme, useResizeObserver, mergeRefs } from '../utils';
|
|
32
32
|
import '@itwin/itwinui-css/css/table.css';
|
|
33
33
|
import SvgSortDown from '@itwin/itwinui-icons-react/cjs/icons/SortDown';
|
|
34
34
|
import SvgSortUp from '@itwin/itwinui-icons-react/cjs/icons/SortUp';
|
|
@@ -36,7 +36,7 @@ import { getCellStyle, getStickyStyle } from './utils';
|
|
|
36
36
|
import { TableRowMemoized } from './TableRowMemoized';
|
|
37
37
|
import { FilterToggle } from './filters';
|
|
38
38
|
import { customFilterFunctions } from './filters/customFilterFunctions';
|
|
39
|
-
import { useExpanderCell, useSelectionCell, useSubRowFiltering, useSubRowSelection, useResizeColumns, useColumnDragAndDrop, useStickyColumns, } from './hooks';
|
|
39
|
+
import { useExpanderCell, useSelectionCell, useSubRowFiltering, useSubRowSelection, useResizeColumns, useColumnDragAndDrop, useScrollToRow, useStickyColumns, } from './hooks';
|
|
40
40
|
import { onExpandHandler, onFilterHandler, onSelectHandler, onSingleSelectHandler, onTableResizeEnd, onTableResizeStart, } from './actionHandlers';
|
|
41
41
|
import VirtualScroll from '../utils/components/VirtualScroll';
|
|
42
42
|
import { SELECTION_CELL_ID } from './columns';
|
|
@@ -234,6 +234,7 @@ export var Table = function (props) {
|
|
|
234
234
|
state.pageIndex,
|
|
235
235
|
state.pageSize,
|
|
236
236
|
]);
|
|
237
|
+
var _r = useScrollToRow(__assign(__assign({}, props), { page: page })), scrollToIndex = _r.scrollToIndex, tableRowRef = _r.tableRowRef;
|
|
237
238
|
var columnRefs = React.useRef({});
|
|
238
239
|
var previousTableWidth = React.useRef(0);
|
|
239
240
|
var onTableResize = React.useCallback(function (_a) {
|
|
@@ -269,22 +270,27 @@ export var Table = function (props) {
|
|
|
269
270
|
});
|
|
270
271
|
var headerRef = React.useRef(null);
|
|
271
272
|
var bodyRef = React.useRef(null);
|
|
273
|
+
// Using `useState` to rerender rows when table body ref is available
|
|
274
|
+
var _s = React.useState(null), bodyRefState = _s[0], setBodyRefState = _s[1];
|
|
272
275
|
var getPreparedRow = React.useCallback(function (index) {
|
|
273
276
|
var row = page[index];
|
|
274
277
|
prepareRow(row);
|
|
275
|
-
return (React.createElement(TableRowMemoized, { row: row, rowProps: rowProps, isLast: index === page.length - 1, onRowInViewport: onRowInViewportRef, onBottomReached: onBottomReachedRef, intersectionMargin: intersectionMargin, state: state, key: row.getRowProps().key, onClick: onRowClickHandler, subComponent: subComponent, isDisabled: !!(isRowDisabled === null || isRowDisabled === void 0 ? void 0 : isRowDisabled(row.original)), tableHasSubRows: hasAnySubRows, tableInstance: instance, expanderCell: expanderCell }));
|
|
278
|
+
return (React.createElement(TableRowMemoized, { row: row, rowProps: rowProps, isLast: index === page.length - 1, onRowInViewport: onRowInViewportRef, onBottomReached: onBottomReachedRef, intersectionMargin: intersectionMargin, state: state, key: row.getRowProps().key, onClick: onRowClickHandler, subComponent: subComponent, isDisabled: !!(isRowDisabled === null || isRowDisabled === void 0 ? void 0 : isRowDisabled(row.original)), tableHasSubRows: hasAnySubRows, tableInstance: instance, expanderCell: expanderCell, bodyRef: bodyRefState, tableRowRef: enableVirtualization ? undefined : tableRowRef(row) }));
|
|
276
279
|
}, [
|
|
277
280
|
page,
|
|
278
|
-
expanderCell,
|
|
279
|
-
hasAnySubRows,
|
|
280
|
-
instance,
|
|
281
|
-
intersectionMargin,
|
|
282
|
-
isRowDisabled,
|
|
283
|
-
onRowClickHandler,
|
|
284
281
|
prepareRow,
|
|
285
282
|
rowProps,
|
|
283
|
+
intersectionMargin,
|
|
286
284
|
state,
|
|
285
|
+
onRowClickHandler,
|
|
287
286
|
subComponent,
|
|
287
|
+
isRowDisabled,
|
|
288
|
+
hasAnySubRows,
|
|
289
|
+
instance,
|
|
290
|
+
expanderCell,
|
|
291
|
+
bodyRefState,
|
|
292
|
+
enableVirtualization,
|
|
293
|
+
tableRowRef,
|
|
288
294
|
]);
|
|
289
295
|
var virtualizedItemRenderer = React.useCallback(function (index) { return getPreparedRow(index); }, [getPreparedRow]);
|
|
290
296
|
var updateStickyState = function () {
|
|
@@ -360,13 +366,13 @@ export var Table = function (props) {
|
|
|
360
366
|
'iui-zebra-striping': styleType === 'zebra-rows',
|
|
361
367
|
}),
|
|
362
368
|
style: { outline: 0 },
|
|
363
|
-
}), { ref: bodyRef, onScroll: function () {
|
|
369
|
+
}), { ref: mergeRefs(bodyRef, setBodyRefState), onScroll: function () {
|
|
364
370
|
if (headerRef.current && bodyRef.current) {
|
|
365
371
|
headerRef.current.scrollLeft = bodyRef.current.scrollLeft;
|
|
366
372
|
updateStickyState();
|
|
367
373
|
}
|
|
368
374
|
}, tabIndex: -1 }),
|
|
369
|
-
data.length !== 0 && (React.createElement(React.Fragment, null, enableVirtualization ? (React.createElement(VirtualScroll, { itemsLength: page.length, itemRenderer: virtualizedItemRenderer })) : (page.map(function (_, index) { return getPreparedRow(index); })))),
|
|
375
|
+
data.length !== 0 && (React.createElement(React.Fragment, null, enableVirtualization ? (React.createElement(VirtualScroll, { itemsLength: page.length, itemRenderer: virtualizedItemRenderer, scrollToIndex: scrollToIndex })) : (page.map(function (_, index) { return getPreparedRow(index); })))),
|
|
370
376
|
isLoading && data.length === 0 && (React.createElement("div", { className: 'iui-table-empty' },
|
|
371
377
|
React.createElement(ProgressRadial, { indeterminate: true }))),
|
|
372
378
|
isLoading && data.length !== 0 && (React.createElement("div", { className: 'iui-row' },
|
|
@@ -20,6 +20,8 @@ export declare const TableRow: <T extends Record<string, unknown>>(props: {
|
|
|
20
20
|
tableHasSubRows: boolean;
|
|
21
21
|
tableInstance: TableInstance<T>;
|
|
22
22
|
expanderCell?: ((cellProps: CellProps<T, any>) => React.ReactNode) | undefined;
|
|
23
|
+
bodyRef: HTMLDivElement | null;
|
|
24
|
+
tableRowRef?: React.Ref<HTMLDivElement> | undefined;
|
|
23
25
|
}) => JSX.Element;
|
|
24
26
|
export declare const TableRowMemoized: <T extends Record<string, unknown>>(props: {
|
|
25
27
|
row: Row<T>;
|
|
@@ -35,4 +37,6 @@ export declare const TableRowMemoized: <T extends Record<string, unknown>>(props
|
|
|
35
37
|
tableHasSubRows: boolean;
|
|
36
38
|
tableInstance: TableInstance<T>;
|
|
37
39
|
expanderCell?: ((cellProps: CellProps<T, any>) => React.ReactNode) | undefined;
|
|
40
|
+
bodyRef: HTMLDivElement | null;
|
|
41
|
+
tableRowRef?: React.Ref<HTMLDivElement> | undefined;
|
|
38
42
|
}) => JSX.Element;
|