@itwin/itwinui-react 1.30.0 → 1.32.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 (66) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/cjs/core/Badge/Badge.js +2 -2
  3. package/cjs/core/Checkbox/Checkbox.d.ts +13 -0
  4. package/cjs/core/Checkbox/Checkbox.js +15 -22
  5. package/cjs/core/ColorPicker/ColorBuilder.js +7 -8
  6. package/cjs/core/ColorPicker/ColorSwatch.d.ts +1 -1
  7. package/cjs/core/ColorPicker/ColorSwatch.js +2 -2
  8. package/cjs/core/ComboBox/ComboBox.d.ts +11 -0
  9. package/cjs/core/ComboBox/ComboBox.js +93 -55
  10. package/cjs/core/ExpandableBlock/ExpandableBlock.d.ts +6 -0
  11. package/cjs/core/ExpandableBlock/ExpandableBlock.js +3 -2
  12. package/cjs/core/Menu/Menu.js +3 -3
  13. package/cjs/core/Menu/MenuItem.js +1 -1
  14. package/cjs/core/Radio/Radio.d.ts +13 -0
  15. package/cjs/core/Radio/Radio.js +7 -8
  16. package/cjs/core/Select/Select.js +23 -8
  17. package/cjs/core/Table/TablePaginator.js +7 -9
  18. package/cjs/core/Table/filters/DateRangeFilter/DatePickerInput.js +1 -1
  19. package/cjs/core/Tile/Tile.js +4 -4
  20. package/cjs/core/Tree/Tree.d.ts +123 -0
  21. package/cjs/core/Tree/Tree.js +177 -0
  22. package/cjs/core/Tree/TreeContext.d.ts +25 -0
  23. package/cjs/core/Tree/TreeContext.js +20 -0
  24. package/cjs/core/Tree/TreeNode.d.ts +87 -0
  25. package/cjs/core/Tree/TreeNode.js +169 -0
  26. package/cjs/core/Tree/TreeNodeExpander.d.ts +8 -0
  27. package/cjs/core/Tree/TreeNodeExpander.js +46 -0
  28. package/cjs/core/Tree/index.d.ts +6 -0
  29. package/cjs/core/Tree/index.js +13 -0
  30. package/cjs/core/index.d.ts +2 -0
  31. package/cjs/core/index.js +5 -1
  32. package/cjs/core/utils/components/Popover.js +1 -1
  33. package/cjs/core/utils/functions/focusable.js +6 -2
  34. package/esm/core/Badge/Badge.js +2 -2
  35. package/esm/core/Checkbox/Checkbox.d.ts +13 -0
  36. package/esm/core/Checkbox/Checkbox.js +15 -22
  37. package/esm/core/ColorPicker/ColorBuilder.js +7 -8
  38. package/esm/core/ColorPicker/ColorSwatch.d.ts +1 -1
  39. package/esm/core/ColorPicker/ColorSwatch.js +2 -2
  40. package/esm/core/ComboBox/ComboBox.d.ts +11 -0
  41. package/esm/core/ComboBox/ComboBox.js +94 -56
  42. package/esm/core/ExpandableBlock/ExpandableBlock.d.ts +6 -0
  43. package/esm/core/ExpandableBlock/ExpandableBlock.js +3 -2
  44. package/esm/core/Menu/Menu.js +3 -3
  45. package/esm/core/Menu/MenuItem.js +1 -1
  46. package/esm/core/Radio/Radio.d.ts +13 -0
  47. package/esm/core/Radio/Radio.js +7 -8
  48. package/esm/core/Select/Select.js +23 -8
  49. package/esm/core/Table/TablePaginator.js +7 -9
  50. package/esm/core/Table/filters/DateRangeFilter/DatePickerInput.js +1 -1
  51. package/esm/core/Tile/Tile.js +4 -4
  52. package/esm/core/Tree/Tree.d.ts +123 -0
  53. package/esm/core/Tree/Tree.js +170 -0
  54. package/esm/core/Tree/TreeContext.d.ts +25 -0
  55. package/esm/core/Tree/TreeContext.js +13 -0
  56. package/esm/core/Tree/TreeNode.d.ts +87 -0
  57. package/esm/core/Tree/TreeNode.js +162 -0
  58. package/esm/core/Tree/TreeNodeExpander.d.ts +8 -0
  59. package/esm/core/Tree/TreeNodeExpander.js +39 -0
  60. package/esm/core/Tree/index.d.ts +6 -0
  61. package/esm/core/Tree/index.js +7 -0
  62. package/esm/core/index.d.ts +2 -0
  63. package/esm/core/index.js +1 -0
  64. package/esm/core/utils/components/Popover.js +1 -1
  65. package/esm/core/utils/functions/focusable.js +6 -2
  66. package/package.json +2 -2
@@ -0,0 +1,170 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __rest = (this && this.__rest) || function (s, e) {
13
+ var t = {};
14
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
15
+ t[p] = s[p];
16
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
17
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
18
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
19
+ t[p[i]] = s[p[i]];
20
+ }
21
+ return t;
22
+ };
23
+ /*---------------------------------------------------------------------------------------------
24
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
25
+ * See LICENSE.md in the project root for license terms and full copyright notice.
26
+ *--------------------------------------------------------------------------------------------*/
27
+ import React from 'react';
28
+ import { useTheme, getFocusableElements } from '../utils';
29
+ import '@itwin/itwinui-css/css/tree.css';
30
+ import cx from 'classnames';
31
+ import { TreeContext } from './TreeContext';
32
+ /**
33
+ * Tree component used to display a hierarchical structure of `TreeNodes`.
34
+ * User should control state of expanded, selected and disabled nodes using `getNode` prop.
35
+ * @example
36
+ type DemoData = {
37
+ id: string;
38
+ label: string;
39
+ subItems: DemoData[];
40
+ };
41
+
42
+ const data: Array<DemoData> = [
43
+ {
44
+ id: 'Node-1',
45
+ label: 'Facility 1',
46
+ subItems: [{ id: 'Node-1-1', label: 'Unit 1', subItems: [] }],
47
+ },
48
+ {
49
+ id: 'Node-2',
50
+ label: 'Facility 2',
51
+ subItems: [{ id: 'Node-2-1', label: 'Unit 2', subItems: [] }],
52
+ },
53
+ ];
54
+
55
+ const [expandedNodes, setExpandedNodes] = React.useState<Record<string, boolean>>({});
56
+ const onNodeExpanded = React.useCallback((nodeId: string, isExpanded: boolean) => {
57
+ setExpandedNodes((oldExpanded) => ({ ...oldExpanded, [nodeId]: isExpanded }));
58
+ }, []);
59
+
60
+ const getNode = React.useCallback((node: DemoData): NodeData<DemoData> => {
61
+ return {
62
+ subNodes: node.subItems,
63
+ nodeId: node.id,
64
+ node,
65
+ isExpanded: expandedNodes[node.id],
66
+ hasSubNodes: node.subItems.length > 0,
67
+ };
68
+ }, [expandedNodes]);
69
+
70
+ <Tree<DemoData>
71
+ data={data}
72
+ getNode={getNode}
73
+ nodeRenderer={React.useCallback(({ node, ...rest }) => (
74
+ <TreeNode
75
+ label={node.label}
76
+ onNodeExpanded={onNodeExpanded}
77
+ {...rest}
78
+ />
79
+ ), [onNodeExpanded])}
80
+ />
81
+ */
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"]);
84
+ useTheme();
85
+ var treeRef = React.useRef(null);
86
+ var focusedIndex = React.useRef(0);
87
+ React.useEffect(function () {
88
+ focusedIndex.current = 0;
89
+ }, [data]);
90
+ var getFocusableNodes = React.useCallback(function () {
91
+ var focusableItems = getFocusableElements(treeRef.current);
92
+ // Filter out focusable elements that are inside each node, e.g. checkbox
93
+ return focusableItems.filter(function (i) { return !focusableItems.some(function (p) { return p.contains(i.parentElement); }); });
94
+ }, []);
95
+ var handleKeyDown = function (event) {
96
+ var items = getFocusableNodes();
97
+ if (!(items === null || items === void 0 ? void 0 : items.length)) {
98
+ return;
99
+ }
100
+ var activeIndex = items.findIndex(function (el) { var _a; return el.contains((_a = treeRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument.activeElement); });
101
+ var currentIndex = activeIndex > -1 ? activeIndex : 0;
102
+ switch (event.key) {
103
+ case 'ArrowUp': {
104
+ event.preventDefault();
105
+ var newIndex = Math.max(0, currentIndex - 1);
106
+ items[newIndex].focus();
107
+ focusedIndex.current = newIndex;
108
+ break;
109
+ }
110
+ case 'ArrowDown': {
111
+ event.preventDefault();
112
+ var newIndex = Math.min(items.length - 1, currentIndex + 1);
113
+ items[newIndex].focus();
114
+ focusedIndex.current = newIndex;
115
+ break;
116
+ }
117
+ default:
118
+ break;
119
+ }
120
+ };
121
+ var _a = React.useMemo(function () {
122
+ var flatList = [];
123
+ var firstLevelNodes = [];
124
+ var flattenNodes = function (nodes, depth, parentNode) {
125
+ if (nodes === void 0) { nodes = []; }
126
+ if (depth === void 0) { depth = 0; }
127
+ var nodeIdList = Array();
128
+ nodes.forEach(function (element, index) {
129
+ var _a = getNode(element), subNodes = _a.subNodes, nodeProps = __rest(_a, ["subNodes"]);
130
+ var flatNode = {
131
+ nodeProps: nodeProps,
132
+ depth: depth,
133
+ parentNode: parentNode,
134
+ indexInGroup: index,
135
+ };
136
+ nodeIdList.push(flatNode.nodeProps.nodeId);
137
+ flatList.push(flatNode);
138
+ if (depth === 0) {
139
+ firstLevelNodes.push(flatNode);
140
+ }
141
+ if (flatNode.nodeProps.isExpanded) {
142
+ var subNodeIds = flattenNodes(subNodes, depth + 1, flatNode);
143
+ flatNode.subNodeIds = subNodeIds;
144
+ }
145
+ });
146
+ return nodeIdList;
147
+ };
148
+ flattenNodes(data);
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) {
158
+ 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
163
+ ? 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
+ })));
169
+ };
170
+ export default Tree;
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ export declare type TreeContextProps = {
3
+ /**
4
+ * Depth of the node.
5
+ */
6
+ nodeDepth: number;
7
+ /**
8
+ * List of sub-node IDs. Used for an accessibility attribute and keyboard navigation.
9
+ */
10
+ subNodeIds?: string[];
11
+ /**
12
+ * ID of the parent node. Used for keyboard navigation.
13
+ */
14
+ parentNodeId?: string;
15
+ /**
16
+ * Number of nodes that are under the same parent node or in the root. Used for an accessibility attribute.
17
+ */
18
+ groupSize: number;
19
+ /**
20
+ * Node index in the list of nodes under the same parent node or in the root. Used for an accessibility attribute.
21
+ */
22
+ indexInGroup: number;
23
+ };
24
+ export declare const TreeContext: React.Context<TreeContextProps | undefined>;
25
+ export declare const useTreeContext: () => TreeContextProps;
@@ -0,0 +1,13 @@
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 var TreeContext = React.createContext(undefined);
7
+ export var useTreeContext = function () {
8
+ var context = React.useContext(TreeContext);
9
+ if (context == undefined) {
10
+ throw new Error('TreeContext must be used within a TreeContext.Provider');
11
+ }
12
+ return context;
13
+ };
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import { CommonProps } from '../utils';
3
+ import '@itwin/itwinui-css/css/tree.css';
4
+ export declare type TreeNodeProps = {
5
+ /**
6
+ * Unique id of the node.
7
+ * It has to be compatible with HTML id attribute.
8
+ */
9
+ nodeId: string;
10
+ /**
11
+ * The main text displayed on the node.
12
+ */
13
+ label: React.ReactNode;
14
+ /**
15
+ * Small note displayed below main label.
16
+ */
17
+ sublabel?: React.ReactNode;
18
+ /**
19
+ * Icon shown before label and sublabel content.
20
+ */
21
+ icon?: JSX.Element;
22
+ /**
23
+ * Flag whether the node has child sub-nodes. It is used to show expander icon.
24
+ * @default false
25
+ */
26
+ hasSubNodes?: boolean;
27
+ /**
28
+ * Flag whether the node is disabled.
29
+ * @default false
30
+ */
31
+ isDisabled?: boolean;
32
+ /**
33
+ * Flag whether the node is expanded.
34
+ * @default false
35
+ */
36
+ isExpanded?: boolean;
37
+ /**
38
+ * Flag whether the node is selected.
39
+ * @default false
40
+ */
41
+ isSelected?: boolean;
42
+ /**
43
+ * Callback fired when expanding or closing a TreeNode.
44
+ * Gives nodeId and new isExpanded value of specified node.
45
+ */
46
+ onExpanded: (nodeId: string, isExpanded: boolean) => void;
47
+ /**
48
+ * Callback fired when selecting a TreeNode.
49
+ * Gives nodeId and new isSelected value of specified node.
50
+ */
51
+ onSelected?: (nodeId: string, isSelected: boolean) => void;
52
+ /**
53
+ * Checkbox to be shown at the very beginning of the node.
54
+ * If undefined, checkbox will not be shown.
55
+ * Recommended to use `Checkbox` component.
56
+ */
57
+ checkbox?: React.ReactNode;
58
+ /**
59
+ * Custom expander element. If `hasSubNodes` is false, it won't be shown.
60
+ */
61
+ expander?: React.ReactNode;
62
+ /**
63
+ * Content shown after `TreeNode`.
64
+ */
65
+ children?: React.ReactNode;
66
+ } & Omit<CommonProps, 'id'>;
67
+ /**
68
+ * `TreeNode` component to display node content within a `Tree`.
69
+ * Must be used inside `Tree` component to correctly set node `depth` and `subNodes`.
70
+ * @example
71
+ <TreeNode
72
+ nodeId={props.nodeId}
73
+ label={props.node.label}
74
+ sublabel={props.node.sublabel}
75
+ onExpanded={onExpanded}
76
+ onSelected={onSelectedNodeChange}
77
+ isDisabled={props.isDisabled}
78
+ isExpanded={props.isExpanded}
79
+ isSelected={props.isSelected}
80
+ checkbox={
81
+ <Checkbox variant='eyeball' disabled={props.isDisabled} />
82
+ }
83
+ icon={<SvgPlaceholder />}
84
+ />
85
+ */
86
+ export declare const TreeNode: (props: TreeNodeProps) => JSX.Element;
87
+ export default TreeNode;
@@ -0,0 +1,162 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __rest = (this && this.__rest) || function (s, e) {
13
+ var t = {};
14
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
15
+ t[p] = s[p];
16
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
17
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
18
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
19
+ t[p[i]] = s[p[i]];
20
+ }
21
+ return t;
22
+ };
23
+ /*---------------------------------------------------------------------------------------------
24
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
25
+ * See LICENSE.md in the project root for license terms and full copyright notice.
26
+ *--------------------------------------------------------------------------------------------*/
27
+ import React from 'react';
28
+ import { getFocusableElements, getWindow, useTheme, } from '../utils';
29
+ import '@itwin/itwinui-css/css/tree.css';
30
+ import cx from 'classnames';
31
+ import { TreeNodeExpander } from './TreeNodeExpander';
32
+ import { useTreeContext } from './TreeContext';
33
+ /**
34
+ * `TreeNode` component to display node content within a `Tree`.
35
+ * Must be used inside `Tree` component to correctly set node `depth` and `subNodes`.
36
+ * @example
37
+ <TreeNode
38
+ nodeId={props.nodeId}
39
+ label={props.node.label}
40
+ sublabel={props.node.sublabel}
41
+ onExpanded={onExpanded}
42
+ onSelected={onSelectedNodeChange}
43
+ isDisabled={props.isDisabled}
44
+ isExpanded={props.isExpanded}
45
+ isSelected={props.isSelected}
46
+ checkbox={
47
+ <Checkbox variant='eyeball' disabled={props.isDisabled} />
48
+ }
49
+ icon={<SvgPlaceholder />}
50
+ />
51
+ */
52
+ export var TreeNode = function (props) {
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
+ 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;
56
+ var _g = React.useState(false), isFocused = _g[0], setIsFocused = _g[1];
57
+ var nodeRef = React.useRef(null);
58
+ var styleDepth = React.useMemo(function () {
59
+ var _a, _b, _c;
60
+ return ((_c = (_b = (_a = getWindow()) === null || _a === void 0 ? void 0 : _a.CSS) === null || _b === void 0 ? void 0 : _b.supports) === null || _c === void 0 ? void 0 : _c.call(_b, "--level: " + nodeDepth))
61
+ ? { '--level': nodeDepth }
62
+ : { marginLeft: nodeDepth ? nodeDepth * 28 : 0 };
63
+ }, [nodeDepth]);
64
+ var onKeyDown = function (event) {
65
+ var _a, _b, _c, _d, _e, _f, _g;
66
+ var isNodeFocused = nodeRef.current === ((_a = nodeRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument.activeElement);
67
+ switch (event.key) {
68
+ case 'ArrowLeft': {
69
+ event.preventDefault();
70
+ if (isNodeFocused) {
71
+ if (isExpanded) {
72
+ onExpanded(nodeId, false);
73
+ break;
74
+ }
75
+ if (parentNodeId) {
76
+ var parentNode = (_b = nodeRef.current) === null || _b === void 0 ? void 0 : _b.ownerDocument.querySelector("#" + parentNodeId);
77
+ parentNode === null || parentNode === void 0 ? void 0 : parentNode.focus();
78
+ break;
79
+ }
80
+ // If it is top level node (doesn't have parent node), then do nothing.
81
+ break;
82
+ }
83
+ var focusableElements = getFocusableElements(nodeRef.current);
84
+ var currentIndex = focusableElements.indexOf((_c = nodeRef.current) === null || _c === void 0 ? void 0 : _c.ownerDocument.activeElement);
85
+ if (currentIndex === 0) {
86
+ (_d = nodeRef.current) === null || _d === void 0 ? void 0 : _d.focus();
87
+ }
88
+ else {
89
+ (_e = focusableElements[currentIndex - 1]) === null || _e === void 0 ? void 0 : _e.focus();
90
+ }
91
+ break;
92
+ }
93
+ case 'ArrowRight': {
94
+ event.preventDefault();
95
+ var focusableElements = getFocusableElements(nodeRef.current);
96
+ if (isNodeFocused) {
97
+ if (!isExpanded && hasSubNodes) {
98
+ onExpanded(nodeId, true);
99
+ break;
100
+ }
101
+ (_f = focusableElements[0]) === null || _f === void 0 ? void 0 : _f.focus();
102
+ break;
103
+ }
104
+ var currentIndex = focusableElements.indexOf((_g = nodeRef.current) === null || _g === void 0 ? void 0 : _g.ownerDocument.activeElement);
105
+ if (currentIndex < focusableElements.length - 1) {
106
+ focusableElements[currentIndex + 1].focus();
107
+ break;
108
+ }
109
+ break;
110
+ }
111
+ case ' ':
112
+ case 'Spacebar':
113
+ case 'Enter': {
114
+ // Ignore if it is called on the element inside, e.g. checkbox or expander
115
+ if (event.target !== nodeRef.current) {
116
+ break;
117
+ }
118
+ event.preventDefault();
119
+ if (!isDisabled) {
120
+ onSelected === null || onSelected === void 0 ? void 0 : onSelected(nodeId, !isSelected);
121
+ }
122
+ break;
123
+ }
124
+ default:
125
+ break;
126
+ }
127
+ };
128
+ var onExpanderClick = React.useCallback(function (event) {
129
+ onExpanded(nodeId, !isExpanded);
130
+ event.stopPropagation();
131
+ }, [isExpanded, nodeId, onExpanded]);
132
+ return (React.createElement("li", __assign({ role: 'treeitem', className: cx('iui-tree-item', className), id: nodeId, "aria-expanded": hasSubNodes ? isExpanded : undefined, "aria-disabled": isDisabled, "aria-selected": isSelected, "aria-level": nodeDepth + 1, "aria-setsize": groupSize, "aria-posinset": indexInGroup + 1, tabIndex: -1, onFocus: function (e) {
133
+ setIsFocused(true);
134
+ // Prevents from triggering onFocus on parent Tree
135
+ e.stopPropagation();
136
+ }, onBlur: function () {
137
+ setIsFocused(false);
138
+ }, ref: nodeRef, onKeyDown: onKeyDown }, rest),
139
+ React.createElement("div", { className: cx('iui-tree-node', {
140
+ 'iui-active': isSelected,
141
+ 'iui-disabled': isDisabled,
142
+ }), style: styleDepth, onClick: function () { return !isDisabled && (onSelected === null || onSelected === void 0 ? void 0 : onSelected(nodeId, !isSelected)); } },
143
+ checkbox && React.isValidElement(checkbox)
144
+ ? React.cloneElement(checkbox, {
145
+ className: cx('iui-tree-node-checkbox', checkbox.props.className),
146
+ tabIndex: isFocused ? 0 : -1,
147
+ })
148
+ : checkbox,
149
+ React.createElement("div", { className: 'iui-tree-node-content' },
150
+ hasSubNodes && expander,
151
+ hasSubNodes && !expander && (React.createElement(TreeNodeExpander, { isExpanded: isExpanded, disabled: isDisabled, onClick: onExpanderClick, tabIndex: isFocused ? 0 : -1 })),
152
+ icon &&
153
+ React.cloneElement(icon, {
154
+ className: cx('iui-tree-node-content-icon', icon.props.className),
155
+ }),
156
+ React.createElement("span", { className: 'iui-tree-node-content-label' },
157
+ React.createElement("div", { className: 'iui-tree-node-content-title' }, label),
158
+ sublabel && (React.createElement("div", { className: 'iui-tree-node-content-caption' }, sublabel))),
159
+ children)),
160
+ hasSubNodes && (React.createElement("ul", { className: 'iui-sub-tree', role: 'group', "aria-owns": subNodeIds.join(',') }))));
161
+ };
162
+ export default TreeNode;
@@ -0,0 +1,8 @@
1
+ /// <reference types="react" />
2
+ import { IconButtonProps } from '../Buttons/IconButton';
3
+ import '@itwin/itwinui-css/css/tree.css';
4
+ export declare type TreeNodeExpanderProps = {
5
+ isExpanded?: boolean;
6
+ } & IconButtonProps;
7
+ export declare const TreeNodeExpander: (props: TreeNodeExpanderProps) => JSX.Element;
8
+ export default TreeNodeExpander;
@@ -0,0 +1,39 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __rest = (this && this.__rest) || function (s, e) {
13
+ var t = {};
14
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
15
+ t[p] = s[p];
16
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
17
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
18
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
19
+ t[p[i]] = s[p[i]];
20
+ }
21
+ return t;
22
+ };
23
+ /*---------------------------------------------------------------------------------------------
24
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
25
+ * See LICENSE.md in the project root for license terms and full copyright notice.
26
+ *--------------------------------------------------------------------------------------------*/
27
+ import React from 'react';
28
+ import cx from 'classnames';
29
+ import SvgChevronRight from '@itwin/itwinui-icons-react/cjs/icons/ChevronRight';
30
+ import { IconButton } from '../Buttons/IconButton';
31
+ import '@itwin/itwinui-css/css/tree.css';
32
+ export var TreeNodeExpander = function (props) {
33
+ var isExpanded = props.isExpanded, rest = __rest(props, ["isExpanded"]);
34
+ return (React.createElement(IconButton, __assign({ styleType: 'borderless', size: 'small', "aria-label": isExpanded ? 'Collapse' : 'Expand' }, rest),
35
+ React.createElement(SvgChevronRight, { className: cx('iui-tree-node-content-expander-icon', {
36
+ 'iui-tree-node-content-expander-icon-expanded': isExpanded,
37
+ }) })));
38
+ };
39
+ export default TreeNodeExpander;
@@ -0,0 +1,6 @@
1
+ export { Tree } from './Tree';
2
+ export type { TreeProps, NodeData, NodeRenderProps } from './Tree';
3
+ export { TreeNode } from './TreeNode';
4
+ export type { TreeNodeProps } from './TreeNode';
5
+ export { TreeNodeExpander } from './TreeNodeExpander';
6
+ export type { TreeNodeExpanderProps } from './TreeNodeExpander';
@@ -0,0 +1,7 @@
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
+ export { Tree } from './Tree';
6
+ export { TreeNode } from './TreeNode';
7
+ export { TreeNodeExpander } from './TreeNodeExpander';
@@ -80,6 +80,8 @@ export { ToggleSwitch } from './ToggleSwitch';
80
80
  export type { ToggleSwitchProps } from './ToggleSwitch';
81
81
  export { Tooltip } from './Tooltip';
82
82
  export type { TooltipProps } from './Tooltip';
83
+ export { Tree, TreeNode, TreeNodeExpander } from './Tree';
84
+ export type { TreeProps, TreeNodeProps, TreeNodeExpanderProps, NodeData, NodeRenderProps, } from './Tree';
83
85
  export { Anchor, Body, Headline, Leading, Small, Subheading, Title, Blockquote, Code, Kbd, KbdKeys, Text, } from './Typography';
84
86
  export type { BodyProps, HeadlineProps, LeadingProps, SmallProps, SubheadingProps, TitleProps, BlockquoteProps, CodeProps, KbdProps, TextProps, } from './Typography';
85
87
  export { UserIcon } from './UserIcon';
package/esm/core/index.js CHANGED
@@ -43,6 +43,7 @@ export { default as toaster } from './Toast';
43
43
  export { ThemeProvider } from './ThemeProvider';
44
44
  export { ToggleSwitch } from './ToggleSwitch';
45
45
  export { Tooltip } from './Tooltip';
46
+ export { Tree, TreeNode, TreeNodeExpander } from './Tree';
46
47
  export { Anchor, Body, Headline, Leading, Small, Subheading, Title, Blockquote, Code, Kbd, KbdKeys, Text, } from './Typography';
47
48
  export { UserIcon } from './UserIcon';
48
49
  export { UserIconGroup } from './UserIconGroup';
@@ -53,7 +53,7 @@ export var Popover = React.forwardRef(function (props, ref) {
53
53
  },
54
54
  }); },
55
55
  };
56
- var computedProps = __assign(__assign({ allowHTML: true, animation: false, appendTo: 'parent', arrow: false, duration: 0, interactive: true, role: undefined, offset: [0, 0], maxWidth: '' }, props), { className: cx('iui-popover', props.className), plugins: __spreadArray([
56
+ var computedProps = __assign(__assign({ allowHTML: true, animation: false, appendTo: function (el) { return el.ownerDocument.body; }, arrow: false, duration: 0, interactive: true, role: undefined, offset: [0, 0], maxWidth: '', zIndex: 99999 }, props), { className: cx('iui-popover', props.className), plugins: __spreadArray([
57
57
  lazyLoad,
58
58
  removeTabIndex,
59
59
  hideOnEscOrTab
@@ -12,7 +12,9 @@ export var getTabbableElements = function (container) {
12
12
  }
13
13
  var elements = container.querySelectorAll(tabbableElementsSelector);
14
14
  return Array.from(elements).filter(function (el) {
15
- return !el.hasAttribute('disabled') && !el.classList.contains('iui-disabled');
15
+ return !el.hasAttribute('disabled') &&
16
+ !el.classList.contains('iui-disabled') &&
17
+ el.getAttribute('aria-disabled') !== 'true';
16
18
  });
17
19
  };
18
20
  /**
@@ -24,6 +26,8 @@ export var getFocusableElements = function (container) {
24
26
  }
25
27
  var elements = container.querySelectorAll(tabbableElementsSelector + ", [tabindex=\"-1\"]");
26
28
  return Array.from(elements).filter(function (el) {
27
- return !el.hasAttribute('disabled') && !el.classList.contains('iui-disabled');
29
+ return !el.hasAttribute('disabled') &&
30
+ !el.classList.contains('iui-disabled') &&
31
+ el.getAttribute('aria-disabled') !== 'true';
28
32
  });
29
33
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itwin/itwinui-react",
3
- "version": "1.30.0",
3
+ "version": "1.32.0",
4
4
  "author": "Bentley Systems",
5
5
  "license": "MIT",
6
6
  "main": "cjs/index.js",
@@ -40,7 +40,7 @@
40
40
  "build-storybook": "build-storybook"
41
41
  },
42
42
  "dependencies": {
43
- "@itwin/itwinui-css": "^0.45.0",
43
+ "@itwin/itwinui-css": "^0.48.2",
44
44
  "@itwin/itwinui-icons-react": "^1.5.0",
45
45
  "@itwin/itwinui-illustrations-react": "^1.0.1",
46
46
  "@tippyjs/react": "^4.2.5",