@react-fabric/data 1.0.0-beta.26 → 1.0.0-beta.28
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/dist/cjs/tree/TreeNode.js +16 -3
- package/dist/cjs/tree/TreePanel.js +7 -4
- package/dist/cjs/tree/useTree.js +73 -11
- package/dist/cjs/tree/utils.js +8 -1
- package/dist/esm/tree/TreeNode.js +16 -3
- package/dist/esm/tree/TreePanel.js +7 -4
- package/dist/esm/tree/useTree.js +74 -12
- package/dist/esm/tree/utils.js +8 -1
- package/dist/types/tree/TreePanel.d.ts +1 -1
- package/dist/types/tree/types.d.ts +4 -0
- package/dist/types/tree/useTree.d.ts +1 -1
- package/package.json +6 -6
- package/src/tree/TreeNode.tsx +63 -45
- package/src/tree/TreePanel.tsx +3 -0
- package/src/tree/types.ts +4 -0
- package/src/tree/useTree.ts +75 -13
- package/src/tree/utils.ts +8 -1
|
@@ -5,6 +5,7 @@ var core = require('@react-fabric/core');
|
|
|
5
5
|
var utilities = require('@react-fabric/utilities');
|
|
6
6
|
var classNames = require('classnames');
|
|
7
7
|
var react = require('react');
|
|
8
|
+
var reactI18next = require('react-i18next');
|
|
8
9
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
10
|
|
|
10
11
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
@@ -24,6 +25,8 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
24
25
|
children = _ref.children,
|
|
25
26
|
leafClassName = _ref.leafClassName,
|
|
26
27
|
nodeClassName = _ref.nodeClassName;
|
|
28
|
+
var _useTranslation = reactI18next.useTranslation("data"),
|
|
29
|
+
t = _useTranslation.t;
|
|
27
30
|
var badgeProps = react.useMemo(function () {
|
|
28
31
|
return core.getBadgeProps(node.badge);
|
|
29
32
|
}, [node.badge]);
|
|
@@ -63,7 +66,14 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
63
66
|
className: classNames("flex flex-nowrap items-center", node.leaf ? leafClassName : nodeClassName),
|
|
64
67
|
"data-testid": node["data-testid"],
|
|
65
68
|
"data-test-value": node["data-test-value"],
|
|
66
|
-
children: [filler,
|
|
69
|
+
children: [filler, node.loading && /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
70
|
+
className: "flex-initial w-6",
|
|
71
|
+
children: /*#__PURE__*/jsxRuntime.jsx(core.Icon, {
|
|
72
|
+
rtlFlip: true,
|
|
73
|
+
icon: core.CoreIcons.spinner,
|
|
74
|
+
className: "animate-spin text-muted"
|
|
75
|
+
})
|
|
76
|
+
}), !node.leaf && !node.childFiltered && !node.loading && /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
67
77
|
className: "flex-initial w-6",
|
|
68
78
|
children: /*#__PURE__*/jsxRuntime.jsx(core.Icon, {
|
|
69
79
|
rtlFlip: true,
|
|
@@ -82,9 +92,9 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
82
92
|
icon: node.checked === 2 ? core.CoreIcons.checkboxInt : node.checked === 1 ? core.CoreIcons.checkboxOn : core.CoreIcons.checkboxOff,
|
|
83
93
|
className: classNames(node.disabled ? "text-muted" : "text-primary-500 hover:text-primary-600")
|
|
84
94
|
})
|
|
85
|
-
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
95
|
+
}), !node.empty && /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
86
96
|
role: "none",
|
|
87
|
-
className: classNames("group data-[selected]:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none", node.childSelected && "font-medium", (canSelect || _onClick) && "hover:bg-primary-50 cursor-pointer"),
|
|
97
|
+
className: classNames("group/tool data-[selected]:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none", node.childSelected && "font-medium", (canSelect || _onClick) && "hover:bg-primary-50 cursor-pointer"),
|
|
88
98
|
"data-selected": node.selected,
|
|
89
99
|
onClick: function onClick() {
|
|
90
100
|
_onClick === null || _onClick === void 0 || _onClick(node.id, node.data);
|
|
@@ -108,6 +118,9 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
108
118
|
}), !utilities.isEmpty(node.badge) && /*#__PURE__*/jsxRuntime.jsx(core.Badge, _objectSpread(_objectSpread({}, badgeProps), {}, {
|
|
109
119
|
className: classNames("me-1 self-center flex-content bg-opacity-50", badgeProps.className)
|
|
110
120
|
}))]
|
|
121
|
+
}), node.empty && /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
122
|
+
className: "text-muted text-sm select-none",
|
|
123
|
+
children: t("tree.noItems")
|
|
111
124
|
})]
|
|
112
125
|
});
|
|
113
126
|
};
|
|
@@ -11,7 +11,7 @@ var types = require('./types.js');
|
|
|
11
11
|
var useTree = require('./useTree.js');
|
|
12
12
|
var jsxRuntime = require('react/jsx-runtime');
|
|
13
13
|
|
|
14
|
-
var _excluded = ["ref", "items", "selected", "checked", "checkable", "noLines", "renderer", "searchable", "selectable", "matcher", "filterPlaceholder", "defaultLeafIcon", "defaultNodeIcon", "expander", "onChecked", "onLoad", "onSelect", "onClick", "sorter", "makeLabel", "makeIcon", "defaultExpanded", "onExpandToggle", "leafClassName", "nodeClassName"];
|
|
14
|
+
var _excluded = ["ref", "items", "selected", "checked", "checkable", "noLines", "renderer", "searchable", "selectable", "matcher", "filterPlaceholder", "defaultLeafIcon", "defaultNodeIcon", "expander", "onChecked", "onLoad", "onQuery", "onSelect", "onClick", "sorter", "makeLabel", "makeIcon", "defaultExpanded", "onExpandToggle", "leafClassName", "nodeClassName"];
|
|
15
15
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
16
16
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
17
17
|
var TreePanel = function TreePanel(_ref) {
|
|
@@ -31,9 +31,10 @@ var TreePanel = function TreePanel(_ref) {
|
|
|
31
31
|
defaultNodeIcon = _ref.defaultNodeIcon,
|
|
32
32
|
_ref$expander = _ref.expander,
|
|
33
33
|
expander = _ref$expander === void 0 ? "box" : _ref$expander,
|
|
34
|
-
onChecked = _ref.onChecked
|
|
35
|
-
_ref.onLoad
|
|
36
|
-
|
|
34
|
+
onChecked = _ref.onChecked,
|
|
35
|
+
onLoad = _ref.onLoad,
|
|
36
|
+
onQuery = _ref.onQuery,
|
|
37
|
+
onSelect = _ref.onSelect,
|
|
37
38
|
onClick = _ref.onClick,
|
|
38
39
|
sorter = _ref.sorter,
|
|
39
40
|
makeLabel = _ref.makeLabel,
|
|
@@ -49,6 +50,8 @@ var TreePanel = function TreePanel(_ref) {
|
|
|
49
50
|
selected: selected,
|
|
50
51
|
matcher: matcher,
|
|
51
52
|
sorter: sorter,
|
|
53
|
+
onLoad: onLoad,
|
|
54
|
+
onQuery: onQuery,
|
|
52
55
|
onSelect: onSelect,
|
|
53
56
|
onChecked: onChecked,
|
|
54
57
|
defaultExpanded: defaultExpanded,
|
package/dist/cjs/tree/useTree.js
CHANGED
|
@@ -21,6 +21,8 @@ var useTree = function useTree(_ref) {
|
|
|
21
21
|
selected = _ref.selected,
|
|
22
22
|
sorter = _ref.sorter,
|
|
23
23
|
matcher = _ref.matcher,
|
|
24
|
+
onLoad = _ref.onLoad,
|
|
25
|
+
onQuery = _ref.onQuery,
|
|
24
26
|
onSelect = _ref.onSelect,
|
|
25
27
|
onChecked = _ref.onChecked,
|
|
26
28
|
defaultExpanded = _ref.defaultExpanded,
|
|
@@ -29,6 +31,7 @@ var useTree = function useTree(_ref) {
|
|
|
29
31
|
onSelect: onSelect,
|
|
30
32
|
onChecked: onChecked
|
|
31
33
|
});
|
|
34
|
+
var intialExpand = react.useRef(defaultExpanded !== null && defaultExpanded !== void 0 ? defaultExpanded : utilities.EMPTY_ARRAY);
|
|
32
35
|
var itemList = createItemList(items);
|
|
33
36
|
var fireExpandToggle = react.useCallback(function (itemMap) {
|
|
34
37
|
var expandedList = itemMap.filter(function (node) {
|
|
@@ -38,6 +41,41 @@ var useTree = function useTree(_ref) {
|
|
|
38
41
|
});
|
|
39
42
|
onExpandToggle === null || onExpandToggle === void 0 || onExpandToggle(expandedList);
|
|
40
43
|
}, [onExpandToggle]);
|
|
44
|
+
var loadChildren = react.useCallback(function (node) {
|
|
45
|
+
var _node$children;
|
|
46
|
+
if (node.open && !node.leaf && !((_node$children = node.children) !== null && _node$children !== void 0 && _node$children.length)) {
|
|
47
|
+
node.loading = true;
|
|
48
|
+
void Promise.resolve(onLoad === null || onLoad === void 0 ? void 0 : onLoad(node.id)).then(function () {
|
|
49
|
+
var resp = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : utilities.EMPTY_ARRAY;
|
|
50
|
+
node.children = utils.refactorTree(resp, {
|
|
51
|
+
sorter: sorter,
|
|
52
|
+
defaultExpanded: defaultExpanded
|
|
53
|
+
}, {
|
|
54
|
+
level: node.level + 1,
|
|
55
|
+
parent: node.id
|
|
56
|
+
});
|
|
57
|
+
})["finally"](function () {
|
|
58
|
+
var _intialExpand$current;
|
|
59
|
+
node.loading = false;
|
|
60
|
+
dispatch({
|
|
61
|
+
type: "loaded"
|
|
62
|
+
});
|
|
63
|
+
((_intialExpand$current = intialExpand.current) === null || _intialExpand$current === void 0 ? void 0 : _intialExpand$current.length) > 0 && dispatch({
|
|
64
|
+
type: "expand",
|
|
65
|
+
id: intialExpand.current.shift()
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
var _intialExpand$current2;
|
|
70
|
+
dispatch({
|
|
71
|
+
type: "loaded"
|
|
72
|
+
});
|
|
73
|
+
((_intialExpand$current2 = intialExpand.current) === null || _intialExpand$current2 === void 0 ? void 0 : _intialExpand$current2.length) > 0 && dispatch({
|
|
74
|
+
type: "expand",
|
|
75
|
+
id: intialExpand.current.shift()
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}, [onLoad]);
|
|
41
79
|
var _useReducer = react.useReducer(function (state, action) {
|
|
42
80
|
if (action.type === "load") {
|
|
43
81
|
state.items = utils.refactorTree(action.items, {
|
|
@@ -50,23 +88,37 @@ var useTree = function useTree(_ref) {
|
|
|
50
88
|
}
|
|
51
89
|
if (action.type === "toggleExpand") {
|
|
52
90
|
var node = state.itemMap.get(action.id);
|
|
53
|
-
|
|
91
|
+
if (node && !node.leaf) {
|
|
92
|
+
node && (node.open = !node.open);
|
|
93
|
+
loadChildren(node);
|
|
94
|
+
return _objectSpread({}, state);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (action.type === "loaded") {
|
|
98
|
+
state.itemMap = utils.makeTreeMap(state.items);
|
|
54
99
|
fireExpandToggle(Array.from(state.itemMap.values()));
|
|
55
100
|
state.tree = utils.flattenTree(state.items);
|
|
101
|
+
state.selected && utils.updateSelection(state.itemMap, state.selected, true);
|
|
56
102
|
return _objectSpread({}, state);
|
|
57
103
|
}
|
|
58
104
|
if (action.type === "expand") {
|
|
59
|
-
// TODO: check if children available, if not call onLoad to fetch node children
|
|
60
105
|
var _node = state.itemMap.get(action.id);
|
|
61
|
-
_node &&
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
106
|
+
if (_node && !_node.leaf) {
|
|
107
|
+
_node.open = true;
|
|
108
|
+
var parentId = _node.parent;
|
|
109
|
+
while (parentId) {
|
|
110
|
+
var _node2 = state.itemMap.get(parentId);
|
|
111
|
+
_node2 && (_node2.open = true);
|
|
112
|
+
parentId = _node2 === null || _node2 === void 0 ? void 0 : _node2.parent;
|
|
113
|
+
}
|
|
114
|
+
loadChildren(_node);
|
|
115
|
+
return _objectSpread({}, state);
|
|
116
|
+
}
|
|
65
117
|
}
|
|
66
118
|
if (action.type === "expandAll") {
|
|
67
|
-
// TODO: prevent opening dynamic nodes that dont have children
|
|
68
119
|
state.itemMap.forEach(function (node) {
|
|
69
|
-
|
|
120
|
+
var _node$children2;
|
|
121
|
+
!node.leaf && ((_node$children2 = node.children) === null || _node$children2 === void 0 ? void 0 : _node$children2.length) && (node.open = true);
|
|
70
122
|
});
|
|
71
123
|
fireExpandToggle(Array.from(state.itemMap.values()));
|
|
72
124
|
state.tree = utils.flattenTree(state.items);
|
|
@@ -81,9 +133,14 @@ var useTree = function useTree(_ref) {
|
|
|
81
133
|
return _objectSpread({}, state);
|
|
82
134
|
}
|
|
83
135
|
if (action.type === "filter") {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
136
|
+
if (onQuery) {
|
|
137
|
+
var _action$query;
|
|
138
|
+
onQuery((_action$query = action.query) !== null && _action$query !== void 0 ? _action$query : "");
|
|
139
|
+
} else {
|
|
140
|
+
utils.filterTree(state.itemMap, action.query, matcher);
|
|
141
|
+
state.tree = utils.flattenTree(state.items);
|
|
142
|
+
return _objectSpread({}, state);
|
|
143
|
+
}
|
|
87
144
|
}
|
|
88
145
|
if (action.type === "select") {
|
|
89
146
|
var _componentEvents$curr, _componentEvents$curr2, _state$itemMap$get;
|
|
@@ -134,10 +191,15 @@ var useTree = function useTree(_ref) {
|
|
|
134
191
|
};
|
|
135
192
|
}, [onSelect, onChecked]);
|
|
136
193
|
react.useEffect(function () {
|
|
194
|
+
var _intialExpand$current3;
|
|
137
195
|
dispatch({
|
|
138
196
|
type: "load",
|
|
139
197
|
items: itemList
|
|
140
198
|
});
|
|
199
|
+
itemList.length && ((_intialExpand$current3 = intialExpand.current) === null || _intialExpand$current3 === void 0 ? void 0 : _intialExpand$current3.length) > 0 && dispatch({
|
|
200
|
+
type: "expand",
|
|
201
|
+
id: intialExpand.current.shift()
|
|
202
|
+
});
|
|
141
203
|
}, [itemList]);
|
|
142
204
|
react.useEffect(function () {
|
|
143
205
|
selected && dispatch({
|
package/dist/cjs/tree/utils.js
CHANGED
|
@@ -40,8 +40,9 @@ var refactorTree = function refactorTree(nodes, _ref) {
|
|
|
40
40
|
var list = [];
|
|
41
41
|
if (sorter !== false) nodes = nodes.sort(sorter);
|
|
42
42
|
nodes.forEach(function (node) {
|
|
43
|
+
var _node$children;
|
|
43
44
|
list.push(_objectSpread(_objectSpread({
|
|
44
|
-
open: defaultExpanded.includes(node.id),
|
|
45
|
+
open: defaultExpanded.includes(node.id) && !!((_node$children = node.children) !== null && _node$children !== void 0 && _node$children.length),
|
|
45
46
|
level: options.level,
|
|
46
47
|
parent: options.parent,
|
|
47
48
|
checked: 0,
|
|
@@ -80,11 +81,17 @@ var flattenTree = function flattenTree(nodes) {
|
|
|
80
81
|
return !node.filtered;
|
|
81
82
|
});
|
|
82
83
|
filtered.forEach(function (node, idx) {
|
|
84
|
+
var _node$children2;
|
|
83
85
|
node.lines = [].concat(_toConsumableArray(lines), [idx === filtered.length - 1 ? 2 : 3]);
|
|
84
86
|
list.push(node);
|
|
85
87
|
(node.open || node.childFiltered) && node.children && list.push.apply(list, _toConsumableArray(flattenTree(node.children.filter(function (child) {
|
|
86
88
|
return !child.filtered;
|
|
87
89
|
}), [].concat(_toConsumableArray(lines), [idx === filtered.length - 1 ? 0 : 1]))));
|
|
90
|
+
node.open && ((_node$children2 = node.children) === null || _node$children2 === void 0 ? void 0 : _node$children2.length) === 0 && list.push({
|
|
91
|
+
empty: true,
|
|
92
|
+
leaf: true,
|
|
93
|
+
lines: [].concat(_toConsumableArray(lines), [idx === filtered.length - 1 ? 0 : 1, 2])
|
|
94
|
+
});
|
|
88
95
|
});
|
|
89
96
|
return list;
|
|
90
97
|
};
|
|
@@ -5,6 +5,7 @@ import { getBadgeProps, Icon, CoreIcons, Badge } from '@react-fabric/core';
|
|
|
5
5
|
import { isString, isEmpty } from '@react-fabric/utilities';
|
|
6
6
|
import classNames from 'classnames';
|
|
7
7
|
import { useMemo, isValidElement } from 'react';
|
|
8
|
+
import { useTranslation } from 'react-i18next';
|
|
8
9
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
9
10
|
|
|
10
11
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
@@ -24,6 +25,8 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
24
25
|
children = _ref.children,
|
|
25
26
|
leafClassName = _ref.leafClassName,
|
|
26
27
|
nodeClassName = _ref.nodeClassName;
|
|
28
|
+
var _useTranslation = useTranslation("data"),
|
|
29
|
+
t = _useTranslation.t;
|
|
27
30
|
var badgeProps = useMemo(function () {
|
|
28
31
|
return getBadgeProps(node.badge);
|
|
29
32
|
}, [node.badge]);
|
|
@@ -63,7 +66,14 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
63
66
|
className: classNames("flex flex-nowrap items-center", node.leaf ? leafClassName : nodeClassName),
|
|
64
67
|
"data-testid": node["data-testid"],
|
|
65
68
|
"data-test-value": node["data-test-value"],
|
|
66
|
-
children: [filler,
|
|
69
|
+
children: [filler, node.loading && /*#__PURE__*/jsx("div", {
|
|
70
|
+
className: "flex-initial w-6",
|
|
71
|
+
children: /*#__PURE__*/jsx(Icon, {
|
|
72
|
+
rtlFlip: true,
|
|
73
|
+
icon: CoreIcons.spinner,
|
|
74
|
+
className: "animate-spin text-muted"
|
|
75
|
+
})
|
|
76
|
+
}), !node.leaf && !node.childFiltered && !node.loading && /*#__PURE__*/jsx("div", {
|
|
67
77
|
className: "flex-initial w-6",
|
|
68
78
|
children: /*#__PURE__*/jsx(Icon, {
|
|
69
79
|
rtlFlip: true,
|
|
@@ -82,9 +92,9 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
82
92
|
icon: node.checked === 2 ? CoreIcons.checkboxInt : node.checked === 1 ? CoreIcons.checkboxOn : CoreIcons.checkboxOff,
|
|
83
93
|
className: classNames(node.disabled ? "text-muted" : "text-primary-500 hover:text-primary-600")
|
|
84
94
|
})
|
|
85
|
-
}), /*#__PURE__*/jsxs("div", {
|
|
95
|
+
}), !node.empty && /*#__PURE__*/jsxs("div", {
|
|
86
96
|
role: "none",
|
|
87
|
-
className: classNames("group data-[selected]:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none", node.childSelected && "font-medium", (canSelect || _onClick) && "hover:bg-primary-50 cursor-pointer"),
|
|
97
|
+
className: classNames("group/tool data-[selected]:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none", node.childSelected && "font-medium", (canSelect || _onClick) && "hover:bg-primary-50 cursor-pointer"),
|
|
88
98
|
"data-selected": node.selected,
|
|
89
99
|
onClick: function onClick() {
|
|
90
100
|
_onClick === null || _onClick === void 0 || _onClick(node.id, node.data);
|
|
@@ -108,6 +118,9 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
108
118
|
}), !isEmpty(node.badge) && /*#__PURE__*/jsx(Badge, _objectSpread(_objectSpread({}, badgeProps), {}, {
|
|
109
119
|
className: classNames("me-1 self-center flex-content bg-opacity-50", badgeProps.className)
|
|
110
120
|
}))]
|
|
121
|
+
}), node.empty && /*#__PURE__*/jsx("div", {
|
|
122
|
+
className: "text-muted text-sm select-none",
|
|
123
|
+
children: t("tree.noItems")
|
|
111
124
|
})]
|
|
112
125
|
});
|
|
113
126
|
};
|
|
@@ -11,7 +11,7 @@ import { iconExpandAll, iconCollapseAll } from './types.js';
|
|
|
11
11
|
import { useTree } from './useTree.js';
|
|
12
12
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
13
13
|
|
|
14
|
-
var _excluded = ["ref", "items", "selected", "checked", "checkable", "noLines", "renderer", "searchable", "selectable", "matcher", "filterPlaceholder", "defaultLeafIcon", "defaultNodeIcon", "expander", "onChecked", "onLoad", "onSelect", "onClick", "sorter", "makeLabel", "makeIcon", "defaultExpanded", "onExpandToggle", "leafClassName", "nodeClassName"];
|
|
14
|
+
var _excluded = ["ref", "items", "selected", "checked", "checkable", "noLines", "renderer", "searchable", "selectable", "matcher", "filterPlaceholder", "defaultLeafIcon", "defaultNodeIcon", "expander", "onChecked", "onLoad", "onQuery", "onSelect", "onClick", "sorter", "makeLabel", "makeIcon", "defaultExpanded", "onExpandToggle", "leafClassName", "nodeClassName"];
|
|
15
15
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
16
16
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
17
17
|
var TreePanel = function TreePanel(_ref) {
|
|
@@ -31,9 +31,10 @@ var TreePanel = function TreePanel(_ref) {
|
|
|
31
31
|
defaultNodeIcon = _ref.defaultNodeIcon,
|
|
32
32
|
_ref$expander = _ref.expander,
|
|
33
33
|
expander = _ref$expander === void 0 ? "box" : _ref$expander,
|
|
34
|
-
onChecked = _ref.onChecked
|
|
35
|
-
_ref.onLoad
|
|
36
|
-
|
|
34
|
+
onChecked = _ref.onChecked,
|
|
35
|
+
onLoad = _ref.onLoad,
|
|
36
|
+
onQuery = _ref.onQuery,
|
|
37
|
+
onSelect = _ref.onSelect,
|
|
37
38
|
onClick = _ref.onClick,
|
|
38
39
|
sorter = _ref.sorter,
|
|
39
40
|
makeLabel = _ref.makeLabel,
|
|
@@ -49,6 +50,8 @@ var TreePanel = function TreePanel(_ref) {
|
|
|
49
50
|
selected: selected,
|
|
50
51
|
matcher: matcher,
|
|
51
52
|
sorter: sorter,
|
|
53
|
+
onLoad: onLoad,
|
|
54
|
+
onQuery: onQuery,
|
|
52
55
|
onSelect: onSelect,
|
|
53
56
|
onChecked: onChecked,
|
|
54
57
|
defaultExpanded: defaultExpanded,
|
package/dist/esm/tree/useTree.js
CHANGED
|
@@ -6,7 +6,7 @@ import { useDebounce } from '@react-fabric/core';
|
|
|
6
6
|
import { EMPTY_ARRAY } from '@react-fabric/utilities';
|
|
7
7
|
import memoizeOne from 'memoize-one';
|
|
8
8
|
import { useRef, useCallback, useReducer, useEffect } from 'react';
|
|
9
|
-
import { refactorTree, makeTreeMap, flattenTree,
|
|
9
|
+
import { refactorTree, makeTreeMap, flattenTree, updateSelection, filterTree, updateChecked } from './utils.js';
|
|
10
10
|
|
|
11
11
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
12
12
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -21,6 +21,8 @@ var useTree = function useTree(_ref) {
|
|
|
21
21
|
selected = _ref.selected,
|
|
22
22
|
sorter = _ref.sorter,
|
|
23
23
|
matcher = _ref.matcher,
|
|
24
|
+
onLoad = _ref.onLoad,
|
|
25
|
+
onQuery = _ref.onQuery,
|
|
24
26
|
onSelect = _ref.onSelect,
|
|
25
27
|
onChecked = _ref.onChecked,
|
|
26
28
|
defaultExpanded = _ref.defaultExpanded,
|
|
@@ -29,6 +31,7 @@ var useTree = function useTree(_ref) {
|
|
|
29
31
|
onSelect: onSelect,
|
|
30
32
|
onChecked: onChecked
|
|
31
33
|
});
|
|
34
|
+
var intialExpand = useRef(defaultExpanded !== null && defaultExpanded !== void 0 ? defaultExpanded : EMPTY_ARRAY);
|
|
32
35
|
var itemList = createItemList(items);
|
|
33
36
|
var fireExpandToggle = useCallback(function (itemMap) {
|
|
34
37
|
var expandedList = itemMap.filter(function (node) {
|
|
@@ -38,6 +41,41 @@ var useTree = function useTree(_ref) {
|
|
|
38
41
|
});
|
|
39
42
|
onExpandToggle === null || onExpandToggle === void 0 || onExpandToggle(expandedList);
|
|
40
43
|
}, [onExpandToggle]);
|
|
44
|
+
var loadChildren = useCallback(function (node) {
|
|
45
|
+
var _node$children;
|
|
46
|
+
if (node.open && !node.leaf && !((_node$children = node.children) !== null && _node$children !== void 0 && _node$children.length)) {
|
|
47
|
+
node.loading = true;
|
|
48
|
+
void Promise.resolve(onLoad === null || onLoad === void 0 ? void 0 : onLoad(node.id)).then(function () {
|
|
49
|
+
var resp = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : EMPTY_ARRAY;
|
|
50
|
+
node.children = refactorTree(resp, {
|
|
51
|
+
sorter: sorter,
|
|
52
|
+
defaultExpanded: defaultExpanded
|
|
53
|
+
}, {
|
|
54
|
+
level: node.level + 1,
|
|
55
|
+
parent: node.id
|
|
56
|
+
});
|
|
57
|
+
})["finally"](function () {
|
|
58
|
+
var _intialExpand$current;
|
|
59
|
+
node.loading = false;
|
|
60
|
+
dispatch({
|
|
61
|
+
type: "loaded"
|
|
62
|
+
});
|
|
63
|
+
((_intialExpand$current = intialExpand.current) === null || _intialExpand$current === void 0 ? void 0 : _intialExpand$current.length) > 0 && dispatch({
|
|
64
|
+
type: "expand",
|
|
65
|
+
id: intialExpand.current.shift()
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
var _intialExpand$current2;
|
|
70
|
+
dispatch({
|
|
71
|
+
type: "loaded"
|
|
72
|
+
});
|
|
73
|
+
((_intialExpand$current2 = intialExpand.current) === null || _intialExpand$current2 === void 0 ? void 0 : _intialExpand$current2.length) > 0 && dispatch({
|
|
74
|
+
type: "expand",
|
|
75
|
+
id: intialExpand.current.shift()
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}, [onLoad]);
|
|
41
79
|
var _useReducer = useReducer(function (state, action) {
|
|
42
80
|
if (action.type === "load") {
|
|
43
81
|
state.items = refactorTree(action.items, {
|
|
@@ -50,23 +88,37 @@ var useTree = function useTree(_ref) {
|
|
|
50
88
|
}
|
|
51
89
|
if (action.type === "toggleExpand") {
|
|
52
90
|
var node = state.itemMap.get(action.id);
|
|
53
|
-
|
|
91
|
+
if (node && !node.leaf) {
|
|
92
|
+
node && (node.open = !node.open);
|
|
93
|
+
loadChildren(node);
|
|
94
|
+
return _objectSpread({}, state);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (action.type === "loaded") {
|
|
98
|
+
state.itemMap = makeTreeMap(state.items);
|
|
54
99
|
fireExpandToggle(Array.from(state.itemMap.values()));
|
|
55
100
|
state.tree = flattenTree(state.items);
|
|
101
|
+
state.selected && updateSelection(state.itemMap, state.selected, true);
|
|
56
102
|
return _objectSpread({}, state);
|
|
57
103
|
}
|
|
58
104
|
if (action.type === "expand") {
|
|
59
|
-
// TODO: check if children available, if not call onLoad to fetch node children
|
|
60
105
|
var _node = state.itemMap.get(action.id);
|
|
61
|
-
_node &&
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
106
|
+
if (_node && !_node.leaf) {
|
|
107
|
+
_node.open = true;
|
|
108
|
+
var parentId = _node.parent;
|
|
109
|
+
while (parentId) {
|
|
110
|
+
var _node2 = state.itemMap.get(parentId);
|
|
111
|
+
_node2 && (_node2.open = true);
|
|
112
|
+
parentId = _node2 === null || _node2 === void 0 ? void 0 : _node2.parent;
|
|
113
|
+
}
|
|
114
|
+
loadChildren(_node);
|
|
115
|
+
return _objectSpread({}, state);
|
|
116
|
+
}
|
|
65
117
|
}
|
|
66
118
|
if (action.type === "expandAll") {
|
|
67
|
-
// TODO: prevent opening dynamic nodes that dont have children
|
|
68
119
|
state.itemMap.forEach(function (node) {
|
|
69
|
-
|
|
120
|
+
var _node$children2;
|
|
121
|
+
!node.leaf && ((_node$children2 = node.children) === null || _node$children2 === void 0 ? void 0 : _node$children2.length) && (node.open = true);
|
|
70
122
|
});
|
|
71
123
|
fireExpandToggle(Array.from(state.itemMap.values()));
|
|
72
124
|
state.tree = flattenTree(state.items);
|
|
@@ -81,9 +133,14 @@ var useTree = function useTree(_ref) {
|
|
|
81
133
|
return _objectSpread({}, state);
|
|
82
134
|
}
|
|
83
135
|
if (action.type === "filter") {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
136
|
+
if (onQuery) {
|
|
137
|
+
var _action$query;
|
|
138
|
+
onQuery((_action$query = action.query) !== null && _action$query !== void 0 ? _action$query : "");
|
|
139
|
+
} else {
|
|
140
|
+
filterTree(state.itemMap, action.query, matcher);
|
|
141
|
+
state.tree = flattenTree(state.items);
|
|
142
|
+
return _objectSpread({}, state);
|
|
143
|
+
}
|
|
87
144
|
}
|
|
88
145
|
if (action.type === "select") {
|
|
89
146
|
var _componentEvents$curr, _componentEvents$curr2, _state$itemMap$get;
|
|
@@ -134,10 +191,15 @@ var useTree = function useTree(_ref) {
|
|
|
134
191
|
};
|
|
135
192
|
}, [onSelect, onChecked]);
|
|
136
193
|
useEffect(function () {
|
|
194
|
+
var _intialExpand$current3;
|
|
137
195
|
dispatch({
|
|
138
196
|
type: "load",
|
|
139
197
|
items: itemList
|
|
140
198
|
});
|
|
199
|
+
itemList.length && ((_intialExpand$current3 = intialExpand.current) === null || _intialExpand$current3 === void 0 ? void 0 : _intialExpand$current3.length) > 0 && dispatch({
|
|
200
|
+
type: "expand",
|
|
201
|
+
id: intialExpand.current.shift()
|
|
202
|
+
});
|
|
141
203
|
}, [itemList]);
|
|
142
204
|
useEffect(function () {
|
|
143
205
|
selected && dispatch({
|
package/dist/esm/tree/utils.js
CHANGED
|
@@ -40,8 +40,9 @@ var refactorTree = function refactorTree(nodes, _ref) {
|
|
|
40
40
|
var list = [];
|
|
41
41
|
if (sorter !== false) nodes = nodes.sort(sorter);
|
|
42
42
|
nodes.forEach(function (node) {
|
|
43
|
+
var _node$children;
|
|
43
44
|
list.push(_objectSpread(_objectSpread({
|
|
44
|
-
open: defaultExpanded.includes(node.id),
|
|
45
|
+
open: defaultExpanded.includes(node.id) && !!((_node$children = node.children) !== null && _node$children !== void 0 && _node$children.length),
|
|
45
46
|
level: options.level,
|
|
46
47
|
parent: options.parent,
|
|
47
48
|
checked: 0,
|
|
@@ -80,11 +81,17 @@ var flattenTree = function flattenTree(nodes) {
|
|
|
80
81
|
return !node.filtered;
|
|
81
82
|
});
|
|
82
83
|
filtered.forEach(function (node, idx) {
|
|
84
|
+
var _node$children2;
|
|
83
85
|
node.lines = [].concat(_toConsumableArray(lines), [idx === filtered.length - 1 ? 2 : 3]);
|
|
84
86
|
list.push(node);
|
|
85
87
|
(node.open || node.childFiltered) && node.children && list.push.apply(list, _toConsumableArray(flattenTree(node.children.filter(function (child) {
|
|
86
88
|
return !child.filtered;
|
|
87
89
|
}), [].concat(_toConsumableArray(lines), [idx === filtered.length - 1 ? 0 : 1]))));
|
|
90
|
+
node.open && ((_node$children2 = node.children) === null || _node$children2 === void 0 ? void 0 : _node$children2.length) === 0 && list.push({
|
|
91
|
+
empty: true,
|
|
92
|
+
leaf: true,
|
|
93
|
+
lines: [].concat(_toConsumableArray(lines), [idx === filtered.length - 1 ? 0 : 1, 2])
|
|
94
|
+
});
|
|
88
95
|
});
|
|
89
96
|
return list;
|
|
90
97
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type TreePanelProps } from "./types";
|
|
2
|
-
export declare const TreePanel: <T extends KeyValue<any>>({ ref, items, selected, checked, checkable, noLines, renderer, searchable, selectable, matcher, filterPlaceholder, defaultLeafIcon, defaultNodeIcon, expander, onChecked, onLoad, onSelect, onClick, sorter, makeLabel, makeIcon, defaultExpanded, onExpandToggle, leafClassName, nodeClassName, ...aria }: TreePanelProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare const TreePanel: <T extends KeyValue<any>>({ ref, items, selected, checked, checkable, noLines, renderer, searchable, selectable, matcher, filterPlaceholder, defaultLeafIcon, defaultNodeIcon, expander, onChecked, onLoad, onQuery, onSelect, onClick, sorter, makeLabel, makeIcon, defaultExpanded, onExpandToggle, leafClassName, nodeClassName, ...aria }: TreePanelProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -125,6 +125,10 @@ export interface TreePanelProps<T extends KeyValue = KeyValue> extends TestProps
|
|
|
125
125
|
* callback for lazy loading tree items
|
|
126
126
|
*/
|
|
127
127
|
onLoad?: (id: string) => Promise<Array<TreeNodeType<T>> | undefined> | Array<TreeNodeType<T>> | undefined;
|
|
128
|
+
/**
|
|
129
|
+
* callback to load tree using search query
|
|
130
|
+
*/
|
|
131
|
+
onQuery?: (query: string) => void;
|
|
128
132
|
/**
|
|
129
133
|
* callback on click of tree node
|
|
130
134
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type InternalNode, type TreePanelProps } from "./types";
|
|
2
|
-
export declare const useTree: <T extends KeyValue<any>>({ items, checked, selected, sorter, matcher, onSelect, onChecked, defaultExpanded, onExpandToggle, }: Partial<TreePanelProps<T>>) => {
|
|
2
|
+
export declare const useTree: <T extends KeyValue<any>>({ items, checked, selected, sorter, matcher, onLoad, onQuery, onSelect, onChecked, defaultExpanded, onExpandToggle, }: Partial<TreePanelProps<T>>) => {
|
|
3
3
|
tree: InternalNode[];
|
|
4
4
|
toggleExpand: (id: string) => void;
|
|
5
5
|
expandAll: () => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-fabric/data",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.28",
|
|
4
4
|
"description": "RUF: Data package",
|
|
5
5
|
"author": "Adarsh Pastakia <adarshpastakia@outlook.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"watch": "npm-run-all -p watch:rollup watch:dts"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@react-fabric/core": "^1.0.0-beta.
|
|
37
|
-
"@react-fabric/date": "^1.0.0-beta.
|
|
38
|
-
"@react-fabric/form": "^1.0.0-beta.
|
|
39
|
-
"@react-fabric/utilities": "^1.0.0-beta.
|
|
36
|
+
"@react-fabric/core": "^1.0.0-beta.28",
|
|
37
|
+
"@react-fabric/date": "^1.0.0-beta.28",
|
|
38
|
+
"@react-fabric/form": "^1.0.0-beta.28",
|
|
39
|
+
"@react-fabric/utilities": "^1.0.0-beta.28",
|
|
40
40
|
"@tanstack/react-virtual": "^3.8.6",
|
|
41
41
|
"classnames": "^2.5.1",
|
|
42
42
|
"color": "^4.2.3",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"node": ">=18.12.0",
|
|
53
53
|
"npm": ">=8.19.0"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "80f9d8a9f96dbd0e7a4287087e23996682bf2c0a"
|
|
56
56
|
}
|
package/src/tree/TreeNode.tsx
CHANGED
|
@@ -25,6 +25,7 @@ import { Badge, CoreIcons, getBadgeProps, Icon } from "@react-fabric/core";
|
|
|
25
25
|
import { isEmpty, isString } from "@react-fabric/utilities";
|
|
26
26
|
import classNames from "classnames";
|
|
27
27
|
import { isValidElement, useMemo } from "react";
|
|
28
|
+
import { useTranslation } from "react-i18next";
|
|
28
29
|
import { type TreeNodeProps } from "./types";
|
|
29
30
|
|
|
30
31
|
export const TreeNode = ({
|
|
@@ -43,6 +44,7 @@ export const TreeNode = ({
|
|
|
43
44
|
leafClassName,
|
|
44
45
|
nodeClassName,
|
|
45
46
|
}: TreeNodeProps) => {
|
|
47
|
+
const { t } = useTranslation("data");
|
|
46
48
|
const badgeProps = useMemo(() => {
|
|
47
49
|
return getBadgeProps(node.badge);
|
|
48
50
|
}, [node.badge]);
|
|
@@ -103,7 +105,16 @@ export const TreeNode = ({
|
|
|
103
105
|
data-test-value={node["data-test-value"]}
|
|
104
106
|
>
|
|
105
107
|
{filler}
|
|
106
|
-
{
|
|
108
|
+
{node.loading && (
|
|
109
|
+
<div className="flex-initial w-6">
|
|
110
|
+
<Icon
|
|
111
|
+
rtlFlip
|
|
112
|
+
icon={CoreIcons.spinner}
|
|
113
|
+
className="animate-spin text-muted"
|
|
114
|
+
/>
|
|
115
|
+
</div>
|
|
116
|
+
)}
|
|
117
|
+
{!node.leaf && !node.childFiltered && !node.loading && (
|
|
107
118
|
<div className="flex-initial w-6">
|
|
108
119
|
<Icon
|
|
109
120
|
rtlFlip
|
|
@@ -132,52 +143,59 @@ export const TreeNode = ({
|
|
|
132
143
|
/>
|
|
133
144
|
</div>
|
|
134
145
|
)}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
onClick
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
146
|
+
{!node.empty && (
|
|
147
|
+
<div
|
|
148
|
+
role="none"
|
|
149
|
+
className={classNames(
|
|
150
|
+
"group/tool data-[selected]:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none",
|
|
151
|
+
node.childSelected && "font-medium",
|
|
152
|
+
(canSelect || onClick) && "hover:bg-primary-50 cursor-pointer",
|
|
153
|
+
)}
|
|
154
|
+
data-selected={node.selected}
|
|
155
|
+
onClick={() => {
|
|
156
|
+
onClick?.(node.id, node.data);
|
|
157
|
+
canSelect
|
|
158
|
+
? onSelect(node.id)
|
|
159
|
+
: canCheck
|
|
160
|
+
? onChecked(node.id)
|
|
161
|
+
: onToggle(node.id);
|
|
162
|
+
}}
|
|
163
|
+
>
|
|
164
|
+
{nodeIcon && (
|
|
165
|
+
<div className="flex-content w-6 self-center leading-none">
|
|
166
|
+
{isValidElement(nodeIcon) && nodeIcon}
|
|
167
|
+
{isString(nodeIcon) && (
|
|
168
|
+
<Icon
|
|
169
|
+
icon={nodeIcon}
|
|
170
|
+
bg={node.iconBg}
|
|
171
|
+
color={node.iconColor}
|
|
172
|
+
rtlFlip={node.rtlFlip}
|
|
173
|
+
/>
|
|
174
|
+
)}
|
|
175
|
+
</div>
|
|
176
|
+
)}
|
|
177
|
+
{node.childSelected && !node.open && (
|
|
178
|
+
<span className=" flex-content text-primary-500">•</span>
|
|
179
|
+
)}
|
|
180
|
+
<div role="none" className="flex-1 truncate">
|
|
181
|
+
{children}
|
|
163
182
|
</div>
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
183
|
+
{!isEmpty(node.badge) && (
|
|
184
|
+
<Badge
|
|
185
|
+
{...badgeProps}
|
|
186
|
+
className={classNames(
|
|
187
|
+
"me-1 self-center flex-content bg-opacity-50",
|
|
188
|
+
badgeProps.className,
|
|
189
|
+
)}
|
|
190
|
+
/>
|
|
191
|
+
)}
|
|
170
192
|
</div>
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
)}
|
|
178
|
-
/>
|
|
179
|
-
)}
|
|
180
|
-
</div>
|
|
193
|
+
)}
|
|
194
|
+
{node.empty && (
|
|
195
|
+
<div className="text-muted text-sm select-none">
|
|
196
|
+
{t("tree.noItems")}
|
|
197
|
+
</div>
|
|
198
|
+
)}
|
|
181
199
|
</div>
|
|
182
200
|
);
|
|
183
201
|
};
|
package/src/tree/TreePanel.tsx
CHANGED
|
@@ -55,6 +55,7 @@ export const TreePanel = <T extends KeyValue>({
|
|
|
55
55
|
expander = "box",
|
|
56
56
|
onChecked,
|
|
57
57
|
onLoad,
|
|
58
|
+
onQuery,
|
|
58
59
|
onSelect,
|
|
59
60
|
onClick,
|
|
60
61
|
sorter,
|
|
@@ -81,6 +82,8 @@ export const TreePanel = <T extends KeyValue>({
|
|
|
81
82
|
selected,
|
|
82
83
|
matcher,
|
|
83
84
|
sorter,
|
|
85
|
+
onLoad,
|
|
86
|
+
onQuery,
|
|
84
87
|
onSelect,
|
|
85
88
|
onChecked,
|
|
86
89
|
defaultExpanded,
|
package/src/tree/types.ts
CHANGED
|
@@ -174,6 +174,10 @@ export interface TreePanelProps<T extends KeyValue = KeyValue>
|
|
|
174
174
|
| Promise<Array<TreeNodeType<T>> | undefined>
|
|
175
175
|
| Array<TreeNodeType<T>>
|
|
176
176
|
| undefined;
|
|
177
|
+
/**
|
|
178
|
+
* callback to load tree using search query
|
|
179
|
+
*/
|
|
180
|
+
onQuery?: (query: string) => void;
|
|
177
181
|
/**
|
|
178
182
|
* callback on click of tree node
|
|
179
183
|
*/
|
package/src/tree/useTree.ts
CHANGED
|
@@ -75,7 +75,11 @@ type TreeActions =
|
|
|
75
75
|
/**
|
|
76
76
|
* collapse all nodes
|
|
77
77
|
*/
|
|
78
|
-
| { type: "collapseAll" }
|
|
78
|
+
| { type: "collapseAll" }
|
|
79
|
+
/**
|
|
80
|
+
* loaded dynamic nodes
|
|
81
|
+
*/
|
|
82
|
+
| { type: "loaded" };
|
|
79
83
|
|
|
80
84
|
interface TreeState {
|
|
81
85
|
items: InternalNode[];
|
|
@@ -93,13 +97,15 @@ export const useTree = <T extends KeyValue>({
|
|
|
93
97
|
selected,
|
|
94
98
|
sorter,
|
|
95
99
|
matcher,
|
|
100
|
+
onLoad,
|
|
101
|
+
onQuery,
|
|
96
102
|
onSelect,
|
|
97
103
|
onChecked,
|
|
98
104
|
defaultExpanded,
|
|
99
105
|
onExpandToggle,
|
|
100
106
|
}: Partial<TreePanelProps<T>>) => {
|
|
101
107
|
const componentEvents = useRef({ onSelect, onChecked });
|
|
102
|
-
|
|
108
|
+
const intialExpand = useRef(defaultExpanded ?? EMPTY_ARRAY);
|
|
103
109
|
const itemList = createItemList(items);
|
|
104
110
|
|
|
105
111
|
const fireExpandToggle = useCallback(
|
|
@@ -112,6 +118,39 @@ export const useTree = <T extends KeyValue>({
|
|
|
112
118
|
[onExpandToggle],
|
|
113
119
|
);
|
|
114
120
|
|
|
121
|
+
const loadChildren = useCallback(
|
|
122
|
+
(node: InternalNode) => {
|
|
123
|
+
if (node.open && !node.leaf && !node.children?.length) {
|
|
124
|
+
node.loading = true;
|
|
125
|
+
void Promise.resolve(onLoad?.(node.id))
|
|
126
|
+
.then((resp = EMPTY_ARRAY) => {
|
|
127
|
+
node.children = refactorTree(
|
|
128
|
+
resp,
|
|
129
|
+
{ sorter, defaultExpanded },
|
|
130
|
+
{ level: node.level + 1, parent: node.id },
|
|
131
|
+
);
|
|
132
|
+
})
|
|
133
|
+
.finally(() => {
|
|
134
|
+
node.loading = false;
|
|
135
|
+
dispatch({ type: "loaded" });
|
|
136
|
+
intialExpand.current?.length > 0 &&
|
|
137
|
+
dispatch({
|
|
138
|
+
type: "expand",
|
|
139
|
+
id: intialExpand.current.shift() as unknown as string,
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
} else {
|
|
143
|
+
dispatch({ type: "loaded" });
|
|
144
|
+
intialExpand.current?.length > 0 &&
|
|
145
|
+
dispatch({
|
|
146
|
+
type: "expand",
|
|
147
|
+
id: intialExpand.current.shift() as unknown as string,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
[onLoad],
|
|
152
|
+
);
|
|
153
|
+
|
|
115
154
|
const [state, dispatch] = useReducer(
|
|
116
155
|
(state: TreeState, action: TreeActions) => {
|
|
117
156
|
if (action.type === "load") {
|
|
@@ -122,23 +161,36 @@ export const useTree = <T extends KeyValue>({
|
|
|
122
161
|
}
|
|
123
162
|
if (action.type === "toggleExpand") {
|
|
124
163
|
const node = state.itemMap.get(action.id);
|
|
125
|
-
|
|
164
|
+
if (node && !node.leaf) {
|
|
165
|
+
node && (node.open = !node.open);
|
|
166
|
+
loadChildren(node);
|
|
167
|
+
return { ...state };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (action.type === "loaded") {
|
|
171
|
+
state.itemMap = makeTreeMap(state.items);
|
|
126
172
|
fireExpandToggle(Array.from(state.itemMap.values()));
|
|
127
173
|
state.tree = flattenTree(state.items);
|
|
174
|
+
state.selected && updateSelection(state.itemMap, state.selected, true);
|
|
128
175
|
return { ...state };
|
|
129
176
|
}
|
|
130
177
|
if (action.type === "expand") {
|
|
131
|
-
// TODO: check if children available, if not call onLoad to fetch node children
|
|
132
178
|
const node = state.itemMap.get(action.id);
|
|
133
|
-
node &&
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
179
|
+
if (node && !node.leaf) {
|
|
180
|
+
node.open = true;
|
|
181
|
+
let parentId = node.parent;
|
|
182
|
+
while (parentId) {
|
|
183
|
+
const node = state.itemMap.get(parentId);
|
|
184
|
+
node && (node.open = true);
|
|
185
|
+
parentId = node?.parent;
|
|
186
|
+
}
|
|
187
|
+
loadChildren(node);
|
|
188
|
+
return { ...state };
|
|
189
|
+
}
|
|
137
190
|
}
|
|
138
191
|
if (action.type === "expandAll") {
|
|
139
|
-
// TODO: prevent opening dynamic nodes that dont have children
|
|
140
192
|
state.itemMap.forEach((node) => {
|
|
141
|
-
!node.leaf && (node.open = true);
|
|
193
|
+
!node.leaf && node.children?.length && (node.open = true);
|
|
142
194
|
});
|
|
143
195
|
fireExpandToggle(Array.from(state.itemMap.values()));
|
|
144
196
|
state.tree = flattenTree(state.items);
|
|
@@ -153,9 +205,13 @@ export const useTree = <T extends KeyValue>({
|
|
|
153
205
|
return { ...state };
|
|
154
206
|
}
|
|
155
207
|
if (action.type === "filter") {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
208
|
+
if (onQuery) {
|
|
209
|
+
onQuery(action.query ?? "");
|
|
210
|
+
} else {
|
|
211
|
+
filterTree(state.itemMap, action.query, matcher);
|
|
212
|
+
state.tree = flattenTree(state.items);
|
|
213
|
+
return { ...state };
|
|
214
|
+
}
|
|
159
215
|
}
|
|
160
216
|
if (action.type === "select") {
|
|
161
217
|
if (state.selected) {
|
|
@@ -198,6 +254,12 @@ export const useTree = <T extends KeyValue>({
|
|
|
198
254
|
|
|
199
255
|
useEffect(() => {
|
|
200
256
|
dispatch({ type: "load", items: itemList });
|
|
257
|
+
itemList.length &&
|
|
258
|
+
intialExpand.current?.length > 0 &&
|
|
259
|
+
dispatch({
|
|
260
|
+
type: "expand",
|
|
261
|
+
id: intialExpand.current.shift() as unknown as string,
|
|
262
|
+
});
|
|
201
263
|
}, [itemList]);
|
|
202
264
|
|
|
203
265
|
useEffect(() => {
|
package/src/tree/utils.ts
CHANGED
|
@@ -58,7 +58,7 @@ export const refactorTree = (
|
|
|
58
58
|
if (sorter !== false) nodes = nodes.sort(sorter);
|
|
59
59
|
nodes.forEach((node) => {
|
|
60
60
|
list.push({
|
|
61
|
-
open: defaultExpanded.includes(node.id),
|
|
61
|
+
open: defaultExpanded.includes(node.id) && !!node.children?.length,
|
|
62
62
|
level: options.level,
|
|
63
63
|
parent: options.parent,
|
|
64
64
|
checked: 0,
|
|
@@ -114,6 +114,13 @@ export const flattenTree = (
|
|
|
114
114
|
[...lines, idx === filtered.length - 1 ? 0 : 1],
|
|
115
115
|
),
|
|
116
116
|
);
|
|
117
|
+
node.open &&
|
|
118
|
+
node.children?.length === 0 &&
|
|
119
|
+
list.push({
|
|
120
|
+
empty: true,
|
|
121
|
+
leaf: true,
|
|
122
|
+
lines: [...lines, idx === filtered.length - 1 ? 0 : 1, 2],
|
|
123
|
+
} as any);
|
|
117
124
|
});
|
|
118
125
|
return list;
|
|
119
126
|
};
|