react-native-tree-multi-select 1.5.0-beta.2 → 1.5.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/README.md +21 -2
- package/lib/commonjs/components/NodeList.js +3 -3
- package/lib/commonjs/components/NodeList.js.map +1 -1
- package/lib/commonjs/helpers/expandCollapse.helper.js +40 -95
- package/lib/commonjs/helpers/expandCollapse.helper.js.map +1 -1
- package/lib/commonjs/helpers/toggleCheckbox.helper.js +123 -109
- package/lib/commonjs/helpers/toggleCheckbox.helper.js.map +1 -1
- package/lib/module/components/NodeList.js +3 -3
- package/lib/module/components/NodeList.js.map +1 -1
- package/lib/module/helpers/expandCollapse.helper.js +40 -95
- package/lib/module/helpers/expandCollapse.helper.js.map +1 -1
- package/lib/module/helpers/toggleCheckbox.helper.js +123 -109
- package/lib/module/helpers/toggleCheckbox.helper.js.map +1 -1
- package/lib/typescript/helpers/expandCollapse.helper.d.ts +4 -4
- package/lib/typescript/helpers/expandCollapse.helper.d.ts.map +1 -1
- package/lib/typescript/helpers/toggleCheckbox.helper.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/NodeList.tsx +2 -2
- package/src/helpers/expandCollapse.helper.ts +51 -102
- package/src/helpers/toggleCheckbox.helper.ts +133 -110
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
⚡️Super-fast Tree view with multi-selection capabilities, using checkboxes and search filtering.
|
|
4
4
|
|
|
5
|
-
[](https://badge.fury.io/js/react-native-tree-multi-select) [](https://github.com/JairajJangle/react-native-tree-multi-select/blob/main/LICENSE) [](https://github.com/JairajJangle/react-native-tree-multi-select/actions/workflows/ci.yml) [](https://github.com/JairajJangle/react-native-tree-multi-select/actions/workflows/ci.yml)    [](https://github.com/JairajJangle/react-native-tree-multi-select/issues?q=is%3Aopen+is%3Aissue)  [](https://snack.expo.dev/@futurejj/react-native-tree-multi-select-example)
|
|
5
|
+
[](https://badge.fury.io/js/react-native-tree-multi-select) [](https://github.com/JairajJangle/react-native-tree-multi-select/blob/main/LICENSE) [](https://github.com/JairajJangle/react-native-tree-multi-select/actions/workflows/ci.yml) [](https://github.com/JairajJangle/react-native-tree-multi-select/actions/workflows/ci.yml)    [](https://github.com/JairajJangle/react-native-tree-multi-select/issues?q=is%3Aopen+is%3Aissue)  [](https://snyk.io/test/github/jairajjangle/react-native-tree-multi-select) [](https://snack.expo.dev/@futurejj/react-native-tree-multi-select-example)
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
@@ -35,6 +35,18 @@ Dependencies that need to be installed for this library to work:
|
|
|
35
35
|
|
|
36
36
|
Make sure to follow the native-related installation instructions for these dependencies.
|
|
37
37
|
|
|
38
|
+
## **Highlighted Features**
|
|
39
|
+
|
|
40
|
+
- ⚡ **Fast**: Designed with performance in mind for smooth scrolling and quick selections.
|
|
41
|
+
- 🛠️ **Highly Customizable**: Modify styles, behavior, and use your custom list component to suit your application's needs.
|
|
42
|
+
- 🔍 **Filterable**: Quickly filter through tree nodes and option to select and un-select only the filtered tree nodes.
|
|
43
|
+
- ✅ **Well Tested**: Comprehensive test coverage to ensure reliability and stability.
|
|
44
|
+
- 📚 **Well Documented**: Detailed documentation to get you started and an example app to demo all the features.
|
|
45
|
+
- 🌳 **Multi-Level Selection**: Select individual nodes or entire branches with ease.
|
|
46
|
+
- 📦 **Supports Large Datasets**: Efficiently handles large trees without much performance degradation.
|
|
47
|
+
- 🔒 **TypeScript Support**: Full TypeScript support for better developer experience.
|
|
48
|
+
- 💻 **Cross-Platform**: Works seamlessly across iOS, Android, and web (with React Native Web).
|
|
49
|
+
|
|
38
50
|
## Usage
|
|
39
51
|
|
|
40
52
|
```tsx
|
|
@@ -242,6 +254,13 @@ If you do not see what you want in the planned feature list, raise a feature req
|
|
|
242
254
|
|
|
243
255
|
---
|
|
244
256
|
|
|
257
|
+
### 💡 Some Expo Snack Examples
|
|
258
|
+
|
|
259
|
+
1. Radio button like selection in tree view: [Snack link](https://snack.expo.dev/@futurejj/react-native-tree-multi-select-radio-button-example)
|
|
260
|
+
2. Display count of number of checked nodes: [Snack link](https://snack.expo.dev/@futurejj/react-native-tree-multi-select-example)
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
245
264
|
## Contributing
|
|
246
265
|
|
|
247
266
|
See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
|
|
@@ -250,7 +269,7 @@ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the
|
|
|
250
269
|
|
|
251
270
|
MIT
|
|
252
271
|
|
|
253
|
-
## Support the project
|
|
272
|
+
## 🙏 Support the project
|
|
254
273
|
|
|
255
274
|
<p align="center" valign="center">
|
|
256
275
|
<a href="https://liberapay.com/FutureJJ/donate">
|
|
@@ -71,11 +71,11 @@ function _NodeList(props) {
|
|
|
71
71
|
removeClippedSubviews: true,
|
|
72
72
|
keyboardShouldPersistTaps: "handled",
|
|
73
73
|
drawDistance: 50,
|
|
74
|
-
data: flattenedFilteredNodes,
|
|
75
|
-
renderItem: nodeRenderer,
|
|
76
74
|
ListHeaderComponent: /*#__PURE__*/(0, _jsxRuntime.jsx)(HeaderFooterView, {}),
|
|
77
75
|
ListFooterComponent: /*#__PURE__*/(0, _jsxRuntime.jsx)(HeaderFooterView, {}),
|
|
78
|
-
...treeFlashListProps
|
|
76
|
+
...treeFlashListProps,
|
|
77
|
+
data: flattenedFilteredNodes,
|
|
78
|
+
renderItem: nodeRenderer
|
|
79
79
|
});
|
|
80
80
|
}
|
|
81
81
|
;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","_flashList","_treeView","_helpers","_CheckboxView","_CustomExpandCollapseIcon","_treeView2","_shallow","_jsxRuntime","e","__esModule","default","NodeList","React","memo","_NodeList","_default","exports","props","treeFlashListProps","checkBoxViewStyleProps","indentationMultiplier","CheckboxComponent","ExpandCollapseIconComponent","ExpandCollapseTouchableComponent","CustomNodeRowComponent","expanded","initialTreeViewData","updateInnerMostChildrenIds","searchKeys","searchText","useTreeViewStore","useShallow","state","filteredTree","useMemo","getFilteredTreeData","trim","toLowerCase","flattenedFilteredNodes","getFlattenedTreeData","useEffect","updatedInnerMostChildrenIds","getInnerMostChildrenIdsInTree","nodeRenderer","useCallback","item","jsx","Node","node","level","FlashList","estimatedItemSize","removeClippedSubviews","keyboardShouldPersistTaps","drawDistance","
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","_flashList","_treeView","_helpers","_CheckboxView","_CustomExpandCollapseIcon","_treeView2","_shallow","_jsxRuntime","e","__esModule","default","NodeList","React","memo","_NodeList","_default","exports","props","treeFlashListProps","checkBoxViewStyleProps","indentationMultiplier","CheckboxComponent","ExpandCollapseIconComponent","ExpandCollapseTouchableComponent","CustomNodeRowComponent","expanded","initialTreeViewData","updateInnerMostChildrenIds","searchKeys","searchText","useTreeViewStore","useShallow","state","filteredTree","useMemo","getFilteredTreeData","trim","toLowerCase","flattenedFilteredNodes","getFlattenedTreeData","useEffect","updatedInnerMostChildrenIds","getInnerMostChildrenIdsInTree","nodeRenderer","useCallback","item","jsx","Node","node","level","FlashList","estimatedItemSize","removeClippedSubviews","keyboardShouldPersistTaps","drawDistance","ListHeaderComponent","HeaderFooterView","ListFooterComponent","data","renderItem","View","style","styles","defaultHeaderFooter","getValue","isChecked","isIndeterminate","_Node","defaultIndentationMultiplier","CustomExpandCollapseIcon","CheckboxView","TouchableOpacity","isExpanded","value","has","id","checked","indeterminate","_onToggleExpand","handleToggleExpand","_onCheck","toggleCheckboxes","jsxs","nodeCheckboxAndArrowRow","paddingStart","children","text","name","onValueChange","length","nodeExpandableArrowTouchable","onPress","checkedValue","onCheck","onExpand","StyleSheet","create","padding","flex","flexDirection","alignItems","minWidth"],"sourceRoot":"../../../src","sources":["components/NodeList.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -19,52 +19,37 @@ var _treeView = require("../store/treeView.store");
|
|
|
19
19
|
*/
|
|
20
20
|
function handleToggleExpand(id) {
|
|
21
21
|
const {
|
|
22
|
-
initialTreeViewData,
|
|
23
22
|
expanded,
|
|
24
|
-
updateExpanded
|
|
23
|
+
updateExpanded,
|
|
24
|
+
nodeMap
|
|
25
25
|
} = _treeView.useTreeViewStore.getState();
|
|
26
26
|
|
|
27
27
|
// Create a new Set based on the current expanded state
|
|
28
28
|
const newExpanded = new Set(expanded);
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Recursively deletes a node and its descendants from the expanded set.
|
|
32
|
-
*
|
|
33
|
-
* @param node - The tree node to start deleting from.
|
|
34
|
-
*/
|
|
35
|
-
function deleteChildrenFromExpanded(node) {
|
|
36
|
-
if (node.children) {
|
|
37
|
-
for (let child of node.children) {
|
|
38
|
-
newExpanded.delete(child.id);
|
|
39
|
-
deleteChildrenFromExpanded(child);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Find the node to expand or collapse
|
|
45
|
-
const node = findNode(initialTreeViewData, id);
|
|
46
29
|
if (expanded.has(id)) {
|
|
47
30
|
// If the node is currently expanded, collapse it and its descendants
|
|
48
31
|
newExpanded.delete(id);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
32
|
+
|
|
33
|
+
// Use an iterative approach to remove all descendants from the expanded set
|
|
34
|
+
const stack = [id];
|
|
35
|
+
while (stack.length > 0) {
|
|
36
|
+
const currentId = stack.pop();
|
|
37
|
+
const node = nodeMap.get(currentId);
|
|
38
|
+
if (node && node.children) {
|
|
39
|
+
for (const child of node.children) {
|
|
40
|
+
newExpanded.delete(child.id);
|
|
41
|
+
stack.push(child.id);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
58
44
|
}
|
|
59
45
|
} else {
|
|
60
46
|
// If the node is currently collapsed, expand it
|
|
61
47
|
newExpanded.add(id);
|
|
62
48
|
}
|
|
63
49
|
|
|
64
|
-
//
|
|
50
|
+
// Update the expanded state
|
|
65
51
|
updateExpanded(newExpanded);
|
|
66
52
|
}
|
|
67
|
-
;
|
|
68
53
|
|
|
69
54
|
/**
|
|
70
55
|
* Expand all nodes in the tree.
|
|
@@ -78,7 +63,6 @@ function expandAll() {
|
|
|
78
63
|
const newExpanded = new Set(nodeMap.keys());
|
|
79
64
|
updateExpanded(newExpanded);
|
|
80
65
|
}
|
|
81
|
-
;
|
|
82
66
|
|
|
83
67
|
/**
|
|
84
68
|
* Collapse all nodes in the tree.
|
|
@@ -87,16 +71,14 @@ function collapseAll() {
|
|
|
87
71
|
const {
|
|
88
72
|
updateExpanded
|
|
89
73
|
} = _treeView.useTreeViewStore.getState();
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
updateExpanded(newExpanded);
|
|
74
|
+
// Clear the expanded state
|
|
75
|
+
updateExpanded(new Set());
|
|
93
76
|
}
|
|
94
|
-
;
|
|
95
77
|
|
|
96
78
|
/**
|
|
97
79
|
* Expand tree nodes of given ids. If the id is of a child, it also expands
|
|
98
|
-
*
|
|
99
|
-
* @param ids Ids of nodes to expand.
|
|
80
|
+
* its ancestors up to the root.
|
|
81
|
+
* @param ids - Ids of nodes to expand.
|
|
100
82
|
*/
|
|
101
83
|
function expandNodes(ids) {
|
|
102
84
|
const {
|
|
@@ -105,29 +87,13 @@ function expandNodes(ids) {
|
|
|
105
87
|
childToParentMap
|
|
106
88
|
} = _treeView.useTreeViewStore.getState();
|
|
107
89
|
const newExpanded = new Set(expanded);
|
|
108
|
-
const
|
|
109
|
-
|
|
90
|
+
const processedIds = new Set();
|
|
110
91
|
ids.forEach(id => {
|
|
111
|
-
newExpanded.add(id); // Start by adding the node ID to the set
|
|
112
92
|
let currentId = id;
|
|
113
|
-
while (currentId &&
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
ignore because this condition is just added to satisfy
|
|
118
|
-
typescript type check as parentId will never be undefined if it is already in
|
|
119
|
-
childToParentMap Map
|
|
120
|
-
*/
|
|
121
|
-
if (parentId) {
|
|
122
|
-
/* istanbul ignore else: nothing to be done in else block */
|
|
123
|
-
if (!newExpanded.has(parentId)) {
|
|
124
|
-
newExpanded.add(parentId); // Add the parent ID only if not already processed
|
|
125
|
-
processedParents.add(parentId);
|
|
126
|
-
}
|
|
127
|
-
currentId = parentId; // Move up to the next parent
|
|
128
|
-
} else {
|
|
129
|
-
break; // Break the loop if there's no further parent
|
|
130
|
-
}
|
|
93
|
+
while (currentId && !processedIds.has(currentId)) {
|
|
94
|
+
newExpanded.add(currentId);
|
|
95
|
+
processedIds.add(currentId);
|
|
96
|
+
currentId = childToParentMap.get(currentId);
|
|
131
97
|
}
|
|
132
98
|
});
|
|
133
99
|
updateExpanded(newExpanded);
|
|
@@ -135,8 +101,8 @@ function expandNodes(ids) {
|
|
|
135
101
|
|
|
136
102
|
/**
|
|
137
103
|
* Collapse tree nodes of given ids. If the id is of a parent, it also collapses
|
|
138
|
-
*
|
|
139
|
-
* @param ids Ids of nodes to collapse.
|
|
104
|
+
* its descendants.
|
|
105
|
+
* @param ids - Ids of nodes to collapse.
|
|
140
106
|
*/
|
|
141
107
|
function collapseNodes(ids) {
|
|
142
108
|
const {
|
|
@@ -146,46 +112,25 @@ function collapseNodes(ids) {
|
|
|
146
112
|
} = _treeView.useTreeViewStore.getState();
|
|
147
113
|
const newExpanded = new Set(expanded);
|
|
148
114
|
|
|
149
|
-
//
|
|
150
|
-
const deleteChildrenFromExpanded =
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
});
|
|
115
|
+
// Use an iterative approach to remove all descendants from the expanded set
|
|
116
|
+
const deleteChildrenFromExpanded = nodeId => {
|
|
117
|
+
const stack = [nodeId];
|
|
118
|
+
while (stack.length > 0) {
|
|
119
|
+
const currentId = stack.pop();
|
|
120
|
+
const node = nodeMap.get(currentId);
|
|
121
|
+
if (node && node.children) {
|
|
122
|
+
for (const child of node.children) {
|
|
123
|
+
newExpanded.delete(child.id);
|
|
124
|
+
stack.push(child.id);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
163
128
|
};
|
|
164
129
|
ids.forEach(id => {
|
|
165
|
-
// Remove the node ID from the set and all its
|
|
130
|
+
// Remove the node ID from the set and all its descendants
|
|
166
131
|
newExpanded.delete(id);
|
|
167
132
|
deleteChildrenFromExpanded(id);
|
|
168
133
|
});
|
|
169
134
|
updateExpanded(newExpanded);
|
|
170
135
|
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Finds a node in the tree by its ID.
|
|
174
|
-
*
|
|
175
|
-
* @param nodes - The array of tree nodes to search through.
|
|
176
|
-
* @returns The found tree node, or undefined if not found.
|
|
177
|
-
*/
|
|
178
|
-
function findNode(nodes, parentId) {
|
|
179
|
-
for (let node of nodes) {
|
|
180
|
-
if (node.id === parentId) {
|
|
181
|
-
return node;
|
|
182
|
-
} else if (node.children) {
|
|
183
|
-
const found = findNode(node.children, parentId);
|
|
184
|
-
if (found) {
|
|
185
|
-
return found;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return undefined;
|
|
190
|
-
}
|
|
191
136
|
//# sourceMappingURL=expandCollapse.helper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_treeView","require","handleToggleExpand","id","
|
|
1
|
+
{"version":3,"names":["_treeView","require","handleToggleExpand","id","expanded","updateExpanded","nodeMap","useTreeViewStore","getState","newExpanded","Set","has","delete","stack","length","currentId","pop","node","get","children","child","push","add","expandAll","keys","collapseAll","expandNodes","ids","childToParentMap","processedIds","forEach","collapseNodes","deleteChildrenFromExpanded","nodeId"],"sourceRoot":"../../../src","sources":["helpers/expandCollapse.helper.ts"],"mappings":";;;;;;;;;;AAAA,IAAAA,SAAA,GAAAC,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,kBAAkBA,CAACC,EAAU,EAAE;EAC3C,MAAM;IACFC,QAAQ;IACRC,cAAc;IACdC;EACJ,CAAC,GAAGC,0BAAgB,CAACC,QAAQ,CAAC,CAAC;;EAE/B;EACA,MAAMC,WAAW,GAAG,IAAIC,GAAG,CAACN,QAAQ,CAAC;EAErC,IAAIA,QAAQ,CAACO,GAAG,CAACR,EAAE,CAAC,EAAE;IAClB;IACAM,WAAW,CAACG,MAAM,CAACT,EAAE,CAAC;;IAEtB;IACA,MAAMU,KAAK,GAAG,CAACV,EAAE,CAAC;IAElB,OAAOU,KAAK,CAACC,MAAM,GAAG,CAAC,EAAE;MACrB,MAAMC,SAAS,GAAGF,KAAK,CAACG,GAAG,CAAC,CAAE;MAC9B,MAAMC,IAAI,GAAGX,OAAO,CAACY,GAAG,CAACH,SAAS,CAAC;MAEnC,IAAIE,IAAI,IAAIA,IAAI,CAACE,QAAQ,EAAE;QACvB,KAAK,MAAMC,KAAK,IAAIH,IAAI,CAACE,QAAQ,EAAE;UAC/BV,WAAW,CAACG,MAAM,CAACQ,KAAK,CAACjB,EAAE,CAAC;UAC5BU,KAAK,CAACQ,IAAI,CAACD,KAAK,CAACjB,EAAE,CAAC;QACxB;MACJ;IACJ;EACJ,CAAC,MAAM;IACH;IACAM,WAAW,CAACa,GAAG,CAACnB,EAAE,CAAC;EACvB;;EAEA;EACAE,cAAc,CAACI,WAAW,CAAC;AAC/B;;AAEA;AACA;AACA;AACO,SAASc,SAASA,CAAA,EAAG;EACxB,MAAM;IAAEjB,OAAO;IAAED;EAAe,CAAC,GAAGE,0BAAgB,CAACC,QAAQ,CAAC,CAAC;EAC/D;EACA,MAAMC,WAAW,GAAG,IAAIC,GAAG,CAACJ,OAAO,CAACkB,IAAI,CAAC,CAAC,CAAC;EAC3CnB,cAAc,CAACI,WAAW,CAAC;AAC/B;;AAEA;AACA;AACA;AACO,SAASgB,WAAWA,CAAA,EAAG;EAC1B,MAAM;IAAEpB;EAAe,CAAC,GAAGE,0BAAgB,CAACC,QAAQ,CAAC,CAAC;EACtD;EACAH,cAAc,CAAC,IAAIK,GAAG,CAAS,CAAC,CAAC;AACrC;;AAEA;AACA;AACA;AACA;AACA;AACO,SAASgB,WAAWA,CAACC,GAAa,EAAE;EACvC,MAAM;IAAEvB,QAAQ;IAAEC,cAAc;IAAEuB;EAAiB,CAAC,GAAGrB,0BAAgB,CAACC,QAAQ,CAAC,CAAC;EAClF,MAAMC,WAAW,GAAG,IAAIC,GAAG,CAACN,QAAQ,CAAC;EACrC,MAAMyB,YAAY,GAAG,IAAInB,GAAG,CAAS,CAAC;EAEtCiB,GAAG,CAACG,OAAO,CAAE3B,EAAE,IAAK;IAChB,IAAIY,SAA6B,GAAGZ,EAAE;IACtC,OAAOY,SAAS,IAAI,CAACc,YAAY,CAAClB,GAAG,CAACI,SAAS,CAAC,EAAE;MAC9CN,WAAW,CAACa,GAAG,CAACP,SAAS,CAAC;MAC1Bc,YAAY,CAACP,GAAG,CAACP,SAAS,CAAC;MAC3BA,SAAS,GAAGa,gBAAgB,CAACV,GAAG,CAACH,SAAS,CAAC;IAC/C;EACJ,CAAC,CAAC;EAEFV,cAAc,CAACI,WAAW,CAAC;AAC/B;;AAEA;AACA;AACA;AACA;AACA;AACO,SAASsB,aAAaA,CAACJ,GAAa,EAAE;EACzC,MAAM;IAAEvB,QAAQ;IAAEC,cAAc;IAAEC;EAAQ,CAAC,GAAGC,0BAAgB,CAACC,QAAQ,CAAC,CAAC;EACzE,MAAMC,WAAW,GAAG,IAAIC,GAAG,CAACN,QAAQ,CAAC;;EAErC;EACA,MAAM4B,0BAA0B,GAAIC,MAAc,IAAK;IACnD,MAAMpB,KAAK,GAAG,CAACoB,MAAM,CAAC;IAEtB,OAAOpB,KAAK,CAACC,MAAM,GAAG,CAAC,EAAE;MACrB,MAAMC,SAAS,GAAGF,KAAK,CAACG,GAAG,CAAC,CAAE;MAC9B,MAAMC,IAAI,GAAGX,OAAO,CAACY,GAAG,CAACH,SAAS,CAAC;MAEnC,IAAIE,IAAI,IAAIA,IAAI,CAACE,QAAQ,EAAE;QACvB,KAAK,MAAMC,KAAK,IAAIH,IAAI,CAACE,QAAQ,EAAE;UAC/BV,WAAW,CAACG,MAAM,CAACQ,KAAK,CAACjB,EAAE,CAAC;UAC5BU,KAAK,CAACQ,IAAI,CAACD,KAAK,CAACjB,EAAE,CAAC;QACxB;MACJ;IACJ;EACJ,CAAC;EAEDwB,GAAG,CAACG,OAAO,CAAE3B,EAAE,IAAK;IAChB;IACAM,WAAW,CAACG,MAAM,CAACT,EAAE,CAAC;IACtB6B,0BAA0B,CAAC7B,EAAE,CAAC;EAClC,CAAC,CAAC;EAEFE,cAAc,CAACI,WAAW,CAAC;AAC/B","ignoreList":[]}
|
|
@@ -9,7 +9,7 @@ var _treeView = require("../store/treeView.store");
|
|
|
9
9
|
* Function to toggle checkbox state for a tree structure.
|
|
10
10
|
* It sets the checked and indeterminate state for all affected nodes in the tree after an action to check/uncheck is made.
|
|
11
11
|
* @param {string[]} ids - The ids of nodes that need to be checked or unchecked.
|
|
12
|
-
* @param {boolean} [forceCheck] - Optional. If provided, will force the check state of the nodes to be this value.
|
|
12
|
+
* @param {boolean} [forceCheck] - Optional. If provided, will force the check state of the nodes to be this value.
|
|
13
13
|
* If not provided, the check state will be toggled based on the current state.
|
|
14
14
|
*/
|
|
15
15
|
function toggleCheckboxes(ids, forceCheck) {
|
|
@@ -31,142 +31,156 @@ function toggleCheckboxes(ids, forceCheck) {
|
|
|
31
31
|
const tempChecked = new Set(checked);
|
|
32
32
|
const tempIndeterminate = new Set(indeterminate);
|
|
33
33
|
|
|
34
|
-
//
|
|
35
|
-
const
|
|
36
|
-
const memoAnyDescendantsChecked = new Map();
|
|
34
|
+
// Keep track of nodes that have been toggled or affected.
|
|
35
|
+
const affectedNodes = new Set();
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
* It uses memoization to avoid redundant calculations.
|
|
41
|
-
* @param {string} nodeId - The id of the node to be checked.
|
|
42
|
-
* @returns {boolean} - Whether all descendants of the node are checked.
|
|
43
|
-
*/
|
|
44
|
-
const areAllDescendantsChecked = nodeId => {
|
|
45
|
-
// If the result for this node is already in the map, return it.
|
|
46
|
-
if (memoAllDescendantsChecked.has(nodeId)) {
|
|
47
|
-
return memoAllDescendantsChecked.get(nodeId);
|
|
48
|
-
}
|
|
49
|
-
const node = nodeMap.get(nodeId);
|
|
50
|
-
let allChecked = true;
|
|
51
|
-
if (node?.children) {
|
|
52
|
-
// If the node has children, recursively check all children.
|
|
53
|
-
for (const childNode of node.children) {
|
|
54
|
-
allChecked = allChecked && areAllDescendantsChecked(childNode.id);
|
|
55
|
-
}
|
|
56
|
-
} else {
|
|
57
|
-
// If the node has no children, its state is equal to whether it is in the checked set.
|
|
58
|
-
allChecked = tempChecked.has(nodeId);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Store the result in the map and return it.
|
|
62
|
-
memoAllDescendantsChecked.set(nodeId, allChecked);
|
|
63
|
-
return allChecked;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Updated function to check if any descendants of a node are checked.
|
|
68
|
-
* It uses memoization to avoid redundant calculations and avoids unnecessarily deep recursion.
|
|
69
|
-
* @param {string} nodeId - The id of the node to be checked.
|
|
70
|
-
* @returns {boolean} - Whether any descendants of the node are checked.
|
|
71
|
-
*/
|
|
72
|
-
const areAnyDescendantsChecked = nodeId => {
|
|
73
|
-
// If the result for this node is already in the map, return it.
|
|
74
|
-
if (memoAnyDescendantsChecked.has(nodeId)) {
|
|
75
|
-
return memoAnyDescendantsChecked.get(nodeId);
|
|
76
|
-
}
|
|
77
|
-
const node = nodeMap.get(nodeId);
|
|
78
|
-
let anyChecked = false;
|
|
79
|
-
if (node?.children) {
|
|
80
|
-
// Check if any direct child is checked, without requiring all descendants.
|
|
81
|
-
for (const childNode of node.children) {
|
|
82
|
-
if (tempChecked.has(childNode.id) || areAnyDescendantsChecked(childNode.id)) {
|
|
83
|
-
anyChecked = true;
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
} else {
|
|
88
|
-
// If the node has no children, its state is equal to whether it is in the checked set.
|
|
89
|
-
anyChecked = tempChecked.has(nodeId);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Store the result in the map and return it.
|
|
93
|
-
memoAnyDescendantsChecked.set(nodeId, anyChecked);
|
|
94
|
-
return anyChecked;
|
|
95
|
-
};
|
|
37
|
+
// Memoization maps for node depths.
|
|
38
|
+
const nodeDepths = new Map();
|
|
96
39
|
|
|
97
|
-
// Toggle the clicked nodes and their children.
|
|
40
|
+
// Step 1: Toggle the clicked nodes and their children without updating parents yet.
|
|
98
41
|
ids.forEach(id => {
|
|
42
|
+
const node = nodeMap.get(id);
|
|
43
|
+
if (!node) {
|
|
44
|
+
// Node does not exist; skip processing this ID
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
99
47
|
const isChecked = tempChecked.has(id);
|
|
100
48
|
const newCheckedState = forceCheck === undefined ? !isChecked : forceCheck;
|
|
101
49
|
if (newCheckedState) {
|
|
102
50
|
tempChecked.add(id);
|
|
103
51
|
tempIndeterminate.delete(id);
|
|
52
|
+
affectedNodes.add(id);
|
|
104
53
|
if (toChildren) {
|
|
105
|
-
|
|
54
|
+
updateChildrenIteratively(id, true);
|
|
106
55
|
}
|
|
107
56
|
} else {
|
|
108
57
|
tempChecked.delete(id);
|
|
109
58
|
tempIndeterminate.delete(id);
|
|
59
|
+
affectedNodes.add(id);
|
|
110
60
|
if (toChildren) {
|
|
111
|
-
|
|
61
|
+
updateChildrenIteratively(id, false);
|
|
112
62
|
}
|
|
113
63
|
}
|
|
114
|
-
|
|
115
|
-
// Skip updating parent nodes if toParents is false
|
|
116
|
-
if (toParents) {
|
|
117
|
-
updateParentNodes(id);
|
|
118
|
-
}
|
|
119
64
|
});
|
|
120
65
|
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
66
|
+
// Step 2: Collect all affected parent nodes.
|
|
67
|
+
const nodesToUpdate = new Set();
|
|
68
|
+
if (toParents) {
|
|
69
|
+
affectedNodes.forEach(id => {
|
|
70
|
+
let currentNodeId = id;
|
|
71
|
+
while (currentNodeId) {
|
|
72
|
+
const parentNodeId = childToParentMap.get(currentNodeId);
|
|
73
|
+
if (parentNodeId) {
|
|
74
|
+
nodesToUpdate.add(parentNodeId);
|
|
75
|
+
currentNodeId = parentNodeId;
|
|
129
76
|
} else {
|
|
130
|
-
|
|
131
|
-
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Step 3: Update parent nodes in bottom-up order.
|
|
84
|
+
if (toParents && nodesToUpdate.size > 0) {
|
|
85
|
+
// Convert the set to an array and sort nodes by depth (deepest first).
|
|
86
|
+
const sortedNodes = Array.from(nodesToUpdate).sort((a, b) => {
|
|
87
|
+
return getNodeDepth(b) - getNodeDepth(a);
|
|
88
|
+
});
|
|
89
|
+
sortedNodes.forEach(nodeId => {
|
|
90
|
+
updateNodeState(nodeId);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Function to iteratively update children nodes as per childrenChecked value.
|
|
96
|
+
* @param rootId - The ID of the root node to start updating from.
|
|
97
|
+
* @param childrenChecked - The desired checked state for children.
|
|
98
|
+
*/
|
|
99
|
+
function updateChildrenIteratively(rootId, childrenChecked) {
|
|
100
|
+
const stack = [rootId];
|
|
101
|
+
while (stack.length > 0) {
|
|
102
|
+
const nodeId = stack.pop();
|
|
103
|
+
const node = nodeMap.get(nodeId);
|
|
104
|
+
if (!node) continue; // Node does not exist; skip
|
|
105
|
+
|
|
106
|
+
if (childrenChecked) {
|
|
107
|
+
tempChecked.add(nodeId);
|
|
108
|
+
tempIndeterminate.delete(nodeId);
|
|
109
|
+
} else {
|
|
110
|
+
tempChecked.delete(nodeId);
|
|
111
|
+
tempIndeterminate.delete(nodeId);
|
|
112
|
+
}
|
|
113
|
+
affectedNodes.add(nodeId);
|
|
114
|
+
if (node.children && node.children.length > 0) {
|
|
115
|
+
for (const childNode of node.children) {
|
|
116
|
+
stack.push(childNode.id);
|
|
132
117
|
}
|
|
133
|
-
|
|
134
|
-
});
|
|
118
|
+
}
|
|
135
119
|
}
|
|
136
120
|
}
|
|
137
121
|
|
|
138
|
-
|
|
139
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Function to get the depth of a node for sorting purposes, with memoization.
|
|
124
|
+
* @param nodeId - The ID of the node to get the depth for.
|
|
125
|
+
* @returns The depth of the node.
|
|
126
|
+
*/
|
|
127
|
+
function getNodeDepth(nodeId) {
|
|
128
|
+
if (nodeDepths.has(nodeId)) {
|
|
129
|
+
return nodeDepths.get(nodeId);
|
|
130
|
+
}
|
|
131
|
+
let depth = 0;
|
|
140
132
|
let currentNodeId = nodeId;
|
|
141
133
|
while (currentNodeId) {
|
|
142
134
|
const parentNodeId = childToParentMap.get(currentNodeId);
|
|
143
135
|
if (parentNodeId) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
tempChecked.delete(parentNodeId);
|
|
149
|
-
tempIndeterminate.add(parentNodeId);
|
|
150
|
-
}
|
|
151
|
-
} else if (tempIndeterminate.has(parentNodeId)) {
|
|
152
|
-
// If the parent node is currently in an indeterminate state,
|
|
153
|
-
// then check if all descendants are checked
|
|
154
|
-
if (areAllDescendantsChecked(parentNodeId)) {
|
|
155
|
-
tempIndeterminate.delete(parentNodeId);
|
|
156
|
-
tempChecked.add(parentNodeId);
|
|
157
|
-
} else if (!areAnyDescendantsChecked(parentNodeId)) {
|
|
158
|
-
// If no descendants are checked, remove from indeterminate set
|
|
159
|
-
tempIndeterminate.delete(parentNodeId);
|
|
160
|
-
}
|
|
161
|
-
} else {
|
|
162
|
-
// If the parent node is not checked or indeterminate,
|
|
163
|
-
// check if any descendants are checked and update appropriately
|
|
164
|
-
if (areAnyDescendantsChecked(parentNodeId)) {
|
|
165
|
-
tempIndeterminate.add(parentNodeId);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
136
|
+
depth++;
|
|
137
|
+
currentNodeId = parentNodeId;
|
|
138
|
+
} else {
|
|
139
|
+
break;
|
|
168
140
|
}
|
|
169
|
-
|
|
141
|
+
}
|
|
142
|
+
nodeDepths.set(nodeId, depth);
|
|
143
|
+
return depth;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Function to update the state of a node based on its children's states.
|
|
148
|
+
* @param nodeId - The ID of the node to update.
|
|
149
|
+
*/
|
|
150
|
+
function updateNodeState(nodeId) {
|
|
151
|
+
const node = nodeMap.get(nodeId);
|
|
152
|
+
if (!node || !node.children || node.children.length === 0) {
|
|
153
|
+
// Leaf nodes are already updated.
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
let allChildrenChecked = true;
|
|
157
|
+
let anyChildCheckedOrIndeterminate = false;
|
|
158
|
+
for (const child of node.children) {
|
|
159
|
+
const isChecked = tempChecked.has(child.id);
|
|
160
|
+
const isIndeterminate = tempIndeterminate.has(child.id);
|
|
161
|
+
if (isChecked) {
|
|
162
|
+
anyChildCheckedOrIndeterminate = true;
|
|
163
|
+
} else if (isIndeterminate) {
|
|
164
|
+
anyChildCheckedOrIndeterminate = true;
|
|
165
|
+
allChildrenChecked = false;
|
|
166
|
+
} else {
|
|
167
|
+
allChildrenChecked = false;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// If both conditions are met, we can break early.
|
|
171
|
+
if (!allChildrenChecked && anyChildCheckedOrIndeterminate) {
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (allChildrenChecked) {
|
|
176
|
+
tempChecked.add(nodeId);
|
|
177
|
+
tempIndeterminate.delete(nodeId);
|
|
178
|
+
} else if (anyChildCheckedOrIndeterminate) {
|
|
179
|
+
tempChecked.delete(nodeId);
|
|
180
|
+
tempIndeterminate.add(nodeId);
|
|
181
|
+
} else {
|
|
182
|
+
tempChecked.delete(nodeId);
|
|
183
|
+
tempIndeterminate.delete(nodeId);
|
|
170
184
|
}
|
|
171
185
|
}
|
|
172
186
|
|