react-native-tree-multi-select 1.5.0-beta.2 → 1.5.0-beta.3
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 +14 -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
|
@@ -111,11 +111,11 @@ function _NodeList(props: NodeListProps) {
|
|
|
111
111
|
removeClippedSubviews={true}
|
|
112
112
|
keyboardShouldPersistTaps="handled"
|
|
113
113
|
drawDistance={50}
|
|
114
|
-
data={flattenedFilteredNodes}
|
|
115
|
-
renderItem={nodeRenderer}
|
|
116
114
|
ListHeaderComponent={<HeaderFooterView />}
|
|
117
115
|
ListFooterComponent={<HeaderFooterView />}
|
|
118
116
|
{...treeFlashListProps}
|
|
117
|
+
data={flattenedFilteredNodes}
|
|
118
|
+
renderItem={nodeRenderer}
|
|
119
119
|
/>
|
|
120
120
|
);
|
|
121
121
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { TreeNode } from "../types/treeView.types";
|
|
2
1
|
import { useTreeViewStore } from "../store/treeView.store";
|
|
3
2
|
|
|
4
3
|
/**
|
|
@@ -11,52 +10,40 @@ import { useTreeViewStore } from "../store/treeView.store";
|
|
|
11
10
|
*/
|
|
12
11
|
export function handleToggleExpand(id: string) {
|
|
13
12
|
const {
|
|
14
|
-
initialTreeViewData,
|
|
15
13
|
expanded,
|
|
16
|
-
updateExpanded
|
|
14
|
+
updateExpanded,
|
|
15
|
+
nodeMap
|
|
17
16
|
} = useTreeViewStore.getState();
|
|
18
17
|
|
|
19
18
|
// Create a new Set based on the current expanded state
|
|
20
19
|
const newExpanded = new Set(expanded);
|
|
21
20
|
|
|
22
|
-
/**
|
|
23
|
-
* Recursively deletes a node and its descendants from the expanded set.
|
|
24
|
-
*
|
|
25
|
-
* @param node - The tree node to start deleting from.
|
|
26
|
-
*/
|
|
27
|
-
function deleteChildrenFromExpanded(node: TreeNode) {
|
|
28
|
-
if (node.children) {
|
|
29
|
-
for (let child of node.children) {
|
|
30
|
-
newExpanded.delete(child.id);
|
|
31
|
-
deleteChildrenFromExpanded(child);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Find the node to expand or collapse
|
|
37
|
-
const node = findNode(initialTreeViewData, id);
|
|
38
|
-
|
|
39
21
|
if (expanded.has(id)) {
|
|
40
22
|
// If the node is currently expanded, collapse it and its descendants
|
|
41
23
|
newExpanded.delete(id);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
24
|
+
|
|
25
|
+
// Use an iterative approach to remove all descendants from the expanded set
|
|
26
|
+
const stack = [id];
|
|
27
|
+
|
|
28
|
+
while (stack.length > 0) {
|
|
29
|
+
const currentId = stack.pop()!;
|
|
30
|
+
const node = nodeMap.get(currentId);
|
|
31
|
+
|
|
32
|
+
if (node && node.children) {
|
|
33
|
+
for (const child of node.children) {
|
|
34
|
+
newExpanded.delete(child.id);
|
|
35
|
+
stack.push(child.id);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
51
38
|
}
|
|
52
39
|
} else {
|
|
53
40
|
// If the node is currently collapsed, expand it
|
|
54
41
|
newExpanded.add(id);
|
|
55
42
|
}
|
|
56
43
|
|
|
57
|
-
//
|
|
44
|
+
// Update the expanded state
|
|
58
45
|
updateExpanded(newExpanded);
|
|
59
|
-
}
|
|
46
|
+
}
|
|
60
47
|
|
|
61
48
|
/**
|
|
62
49
|
* Expand all nodes in the tree.
|
|
@@ -66,51 +53,33 @@ export function expandAll() {
|
|
|
66
53
|
// Create a new Set containing the IDs of all nodes
|
|
67
54
|
const newExpanded = new Set(nodeMap.keys());
|
|
68
55
|
updateExpanded(newExpanded);
|
|
69
|
-
}
|
|
56
|
+
}
|
|
70
57
|
|
|
71
58
|
/**
|
|
72
59
|
* Collapse all nodes in the tree.
|
|
73
60
|
*/
|
|
74
61
|
export function collapseAll() {
|
|
75
62
|
const { updateExpanded } = useTreeViewStore.getState();
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
};
|
|
63
|
+
// Clear the expanded state
|
|
64
|
+
updateExpanded(new Set<string>());
|
|
65
|
+
}
|
|
80
66
|
|
|
81
67
|
/**
|
|
82
68
|
* Expand tree nodes of given ids. If the id is of a child, it also expands
|
|
83
|
-
*
|
|
84
|
-
* @param ids Ids of nodes to expand.
|
|
69
|
+
* its ancestors up to the root.
|
|
70
|
+
* @param ids - Ids of nodes to expand.
|
|
85
71
|
*/
|
|
86
72
|
export function expandNodes(ids: string[]) {
|
|
87
73
|
const { expanded, updateExpanded, childToParentMap } = useTreeViewStore.getState();
|
|
88
74
|
const newExpanded = new Set(expanded);
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
ids.forEach(id => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
/*
|
|
98
|
-
istanbul ignore else:
|
|
99
|
-
|
|
100
|
-
ignore because this condition is just added to satisfy
|
|
101
|
-
typescript type check as parentId will never be undefined if it is already in
|
|
102
|
-
childToParentMap Map
|
|
103
|
-
*/
|
|
104
|
-
if (parentId) {
|
|
105
|
-
/* istanbul ignore else: nothing to be done in else block */
|
|
106
|
-
if (!newExpanded.has(parentId)) {
|
|
107
|
-
newExpanded.add(parentId); // Add the parent ID only if not already processed
|
|
108
|
-
processedParents.add(parentId);
|
|
109
|
-
}
|
|
110
|
-
currentId = parentId; // Move up to the next parent
|
|
111
|
-
} else {
|
|
112
|
-
break; // Break the loop if there's no further parent
|
|
113
|
-
}
|
|
75
|
+
const processedIds = new Set<string>();
|
|
76
|
+
|
|
77
|
+
ids.forEach((id) => {
|
|
78
|
+
let currentId: string | undefined = id;
|
|
79
|
+
while (currentId && !processedIds.has(currentId)) {
|
|
80
|
+
newExpanded.add(currentId);
|
|
81
|
+
processedIds.add(currentId);
|
|
82
|
+
currentId = childToParentMap.get(currentId);
|
|
114
83
|
}
|
|
115
84
|
});
|
|
116
85
|
|
|
@@ -119,55 +88,35 @@ export function expandNodes(ids: string[]) {
|
|
|
119
88
|
|
|
120
89
|
/**
|
|
121
90
|
* Collapse tree nodes of given ids. If the id is of a parent, it also collapses
|
|
122
|
-
*
|
|
123
|
-
* @param ids Ids of nodes to collapse.
|
|
91
|
+
* its descendants.
|
|
92
|
+
* @param ids - Ids of nodes to collapse.
|
|
124
93
|
*/
|
|
125
94
|
export function collapseNodes(ids: string[]) {
|
|
126
95
|
const { expanded, updateExpanded, nodeMap } = useTreeViewStore.getState();
|
|
127
96
|
const newExpanded = new Set(expanded);
|
|
128
97
|
|
|
129
|
-
//
|
|
130
|
-
const deleteChildrenFromExpanded = (nodeId: string
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
98
|
+
// Use an iterative approach to remove all descendants from the expanded set
|
|
99
|
+
const deleteChildrenFromExpanded = (nodeId: string) => {
|
|
100
|
+
const stack = [nodeId];
|
|
101
|
+
|
|
102
|
+
while (stack.length > 0) {
|
|
103
|
+
const currentId = stack.pop()!;
|
|
104
|
+
const node = nodeMap.get(currentId);
|
|
105
|
+
|
|
106
|
+
if (node && node.children) {
|
|
107
|
+
for (const child of node.children) {
|
|
108
|
+
newExpanded.delete(child.id);
|
|
109
|
+
stack.push(child.id);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
144
113
|
};
|
|
145
114
|
|
|
146
|
-
ids.forEach(id => {
|
|
147
|
-
// Remove the node ID from the set and all its
|
|
115
|
+
ids.forEach((id) => {
|
|
116
|
+
// Remove the node ID from the set and all its descendants
|
|
148
117
|
newExpanded.delete(id);
|
|
149
118
|
deleteChildrenFromExpanded(id);
|
|
150
119
|
});
|
|
151
120
|
|
|
152
121
|
updateExpanded(newExpanded);
|
|
153
122
|
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Finds a node in the tree by its ID.
|
|
157
|
-
*
|
|
158
|
-
* @param nodes - The array of tree nodes to search through.
|
|
159
|
-
* @returns The found tree node, or undefined if not found.
|
|
160
|
-
*/
|
|
161
|
-
function findNode(nodes: TreeNode[], parentId: string): TreeNode | undefined {
|
|
162
|
-
for (let node of nodes) {
|
|
163
|
-
if (node.id === parentId) {
|
|
164
|
-
return node;
|
|
165
|
-
} else if (node.children) {
|
|
166
|
-
const found = findNode(node.children, parentId);
|
|
167
|
-
if (found) {
|
|
168
|
-
return found;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return undefined;
|
|
173
|
-
}
|
|
@@ -4,7 +4,7 @@ import { useTreeViewStore } from "../store/treeView.store";
|
|
|
4
4
|
* Function to toggle checkbox state for a tree structure.
|
|
5
5
|
* It sets the checked and indeterminate state for all affected nodes in the tree after an action to check/uncheck is made.
|
|
6
6
|
* @param {string[]} ids - The ids of nodes that need to be checked or unchecked.
|
|
7
|
-
* @param {boolean} [forceCheck] - Optional. If provided, will force the check state of the nodes to be this value.
|
|
7
|
+
* @param {boolean} [forceCheck] - Optional. If provided, will force the check state of the nodes to be this value.
|
|
8
8
|
* If not provided, the check state will be toggled based on the current state.
|
|
9
9
|
*/
|
|
10
10
|
export function toggleCheckboxes(ids: string[], forceCheck?: boolean) {
|
|
@@ -26,145 +26,168 @@ export function toggleCheckboxes(ids: string[], forceCheck?: boolean) {
|
|
|
26
26
|
const tempChecked = new Set(checked);
|
|
27
27
|
const tempIndeterminate = new Set(indeterminate);
|
|
28
28
|
|
|
29
|
-
//
|
|
30
|
-
const
|
|
31
|
-
const memoAnyDescendantsChecked = new Map<string, boolean>();
|
|
29
|
+
// Keep track of nodes that have been toggled or affected.
|
|
30
|
+
const affectedNodes = new Set<string>();
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
* It uses memoization to avoid redundant calculations.
|
|
36
|
-
* @param {string} nodeId - The id of the node to be checked.
|
|
37
|
-
* @returns {boolean} - Whether all descendants of the node are checked.
|
|
38
|
-
*/
|
|
39
|
-
const areAllDescendantsChecked = (nodeId: string): boolean => {
|
|
40
|
-
// If the result for this node is already in the map, return it.
|
|
41
|
-
if (memoAllDescendantsChecked.has(nodeId)) {
|
|
42
|
-
return memoAllDescendantsChecked.get(nodeId)!;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const node = nodeMap.get(nodeId);
|
|
46
|
-
let allChecked = true;
|
|
47
|
-
if (node?.children) {
|
|
48
|
-
// If the node has children, recursively check all children.
|
|
49
|
-
for (const childNode of node.children) {
|
|
50
|
-
allChecked = allChecked && areAllDescendantsChecked(childNode.id);
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
// If the node has no children, its state is equal to whether it is in the checked set.
|
|
54
|
-
allChecked = tempChecked.has(nodeId);
|
|
55
|
-
}
|
|
32
|
+
// Memoization maps for node depths.
|
|
33
|
+
const nodeDepths = new Map<string, number>();
|
|
56
34
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
* Updated function to check if any descendants of a node are checked.
|
|
64
|
-
* It uses memoization to avoid redundant calculations and avoids unnecessarily deep recursion.
|
|
65
|
-
* @param {string} nodeId - The id of the node to be checked.
|
|
66
|
-
* @returns {boolean} - Whether any descendants of the node are checked.
|
|
67
|
-
*/
|
|
68
|
-
const areAnyDescendantsChecked = (nodeId: string): boolean => {
|
|
69
|
-
// If the result for this node is already in the map, return it.
|
|
70
|
-
if (memoAnyDescendantsChecked.has(nodeId)) {
|
|
71
|
-
return memoAnyDescendantsChecked.get(nodeId)!;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const node = nodeMap.get(nodeId);
|
|
75
|
-
let anyChecked = false;
|
|
76
|
-
if (node?.children) {
|
|
77
|
-
// Check if any direct child is checked, without requiring all descendants.
|
|
78
|
-
for (const childNode of node.children) {
|
|
79
|
-
if (tempChecked.has(childNode.id) || areAnyDescendantsChecked(childNode.id)) {
|
|
80
|
-
anyChecked = true;
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
} else {
|
|
85
|
-
// If the node has no children, its state is equal to whether it is in the checked set.
|
|
86
|
-
anyChecked = tempChecked.has(nodeId);
|
|
35
|
+
// Step 1: Toggle the clicked nodes and their children without updating parents yet.
|
|
36
|
+
ids.forEach((id) => {
|
|
37
|
+
const node = nodeMap.get(id);
|
|
38
|
+
if (!node) {
|
|
39
|
+
// Node does not exist; skip processing this ID
|
|
40
|
+
return;
|
|
87
41
|
}
|
|
88
42
|
|
|
89
|
-
// Store the result in the map and return it.
|
|
90
|
-
memoAnyDescendantsChecked.set(nodeId, anyChecked);
|
|
91
|
-
return anyChecked;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
// Toggle the clicked nodes and their children.
|
|
95
|
-
ids.forEach((id) => {
|
|
96
43
|
const isChecked = tempChecked.has(id);
|
|
97
44
|
const newCheckedState = forceCheck === undefined ? !isChecked : forceCheck;
|
|
98
45
|
|
|
99
46
|
if (newCheckedState) {
|
|
100
47
|
tempChecked.add(id);
|
|
101
48
|
tempIndeterminate.delete(id);
|
|
49
|
+
affectedNodes.add(id);
|
|
102
50
|
if (toChildren) {
|
|
103
|
-
|
|
51
|
+
updateChildrenIteratively(id, true);
|
|
104
52
|
}
|
|
105
53
|
} else {
|
|
106
54
|
tempChecked.delete(id);
|
|
107
55
|
tempIndeterminate.delete(id);
|
|
56
|
+
affectedNodes.add(id);
|
|
108
57
|
if (toChildren) {
|
|
109
|
-
|
|
58
|
+
updateChildrenIteratively(id, false);
|
|
110
59
|
}
|
|
111
60
|
}
|
|
112
|
-
|
|
113
|
-
// Skip updating parent nodes if toParents is false
|
|
114
|
-
if (toParents) {
|
|
115
|
-
updateParentNodes(id);
|
|
116
|
-
}
|
|
117
61
|
});
|
|
118
62
|
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
63
|
+
// Step 2: Collect all affected parent nodes.
|
|
64
|
+
const nodesToUpdate = new Set<string>();
|
|
65
|
+
|
|
66
|
+
if (toParents) {
|
|
67
|
+
affectedNodes.forEach((id) => {
|
|
68
|
+
let currentNodeId: string | undefined = id;
|
|
69
|
+
while (currentNodeId) {
|
|
70
|
+
const parentNodeId = childToParentMap.get(currentNodeId);
|
|
71
|
+
if (parentNodeId) {
|
|
72
|
+
nodesToUpdate.add(parentNodeId);
|
|
73
|
+
currentNodeId = parentNodeId;
|
|
127
74
|
} else {
|
|
128
|
-
|
|
129
|
-
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Step 3: Update parent nodes in bottom-up order.
|
|
82
|
+
if (toParents && nodesToUpdate.size > 0) {
|
|
83
|
+
// Convert the set to an array and sort nodes by depth (deepest first).
|
|
84
|
+
const sortedNodes = Array.from(nodesToUpdate).sort((a, b) => {
|
|
85
|
+
return getNodeDepth(b) - getNodeDepth(a);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
sortedNodes.forEach((nodeId) => {
|
|
89
|
+
updateNodeState(nodeId);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Function to iteratively update children nodes as per childrenChecked value.
|
|
95
|
+
* @param rootId - The ID of the root node to start updating from.
|
|
96
|
+
* @param childrenChecked - The desired checked state for children.
|
|
97
|
+
*/
|
|
98
|
+
function updateChildrenIteratively(rootId: string, childrenChecked: boolean) {
|
|
99
|
+
const stack = [rootId];
|
|
100
|
+
|
|
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
|
+
|
|
115
|
+
if (node.children && node.children.length > 0) {
|
|
116
|
+
for (const childNode of node.children) {
|
|
117
|
+
stack.push(childNode.id);
|
|
130
118
|
}
|
|
131
|
-
|
|
132
|
-
});
|
|
119
|
+
}
|
|
133
120
|
}
|
|
134
121
|
}
|
|
135
122
|
|
|
136
|
-
|
|
137
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Function to get the depth of a node for sorting purposes, with memoization.
|
|
125
|
+
* @param nodeId - The ID of the node to get the depth for.
|
|
126
|
+
* @returns The depth of the node.
|
|
127
|
+
*/
|
|
128
|
+
function getNodeDepth(nodeId: string): number {
|
|
129
|
+
if (nodeDepths.has(nodeId)) {
|
|
130
|
+
return nodeDepths.get(nodeId)!;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
let depth = 0;
|
|
138
134
|
let currentNodeId: string | undefined = nodeId;
|
|
139
135
|
while (currentNodeId) {
|
|
140
136
|
const parentNodeId = childToParentMap.get(currentNodeId);
|
|
141
137
|
if (parentNodeId) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
138
|
+
depth++;
|
|
139
|
+
currentNodeId = parentNodeId;
|
|
140
|
+
} else {
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
nodeDepths.set(nodeId, depth);
|
|
146
|
+
return depth;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Function to update the state of a node based on its children's states.
|
|
151
|
+
* @param nodeId - The ID of the node to update.
|
|
152
|
+
*/
|
|
153
|
+
function updateNodeState(nodeId: string) {
|
|
154
|
+
const node = nodeMap.get(nodeId);
|
|
155
|
+
if (!node || !node.children || node.children.length === 0) {
|
|
156
|
+
// Leaf nodes are already updated.
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let allChildrenChecked = true;
|
|
161
|
+
let anyChildCheckedOrIndeterminate = false;
|
|
162
|
+
|
|
163
|
+
for (const child of node.children) {
|
|
164
|
+
const isChecked = tempChecked.has(child.id);
|
|
165
|
+
const isIndeterminate = tempIndeterminate.has(child.id);
|
|
166
|
+
|
|
167
|
+
if (isChecked) {
|
|
168
|
+
anyChildCheckedOrIndeterminate = true;
|
|
169
|
+
} else if (isIndeterminate) {
|
|
170
|
+
anyChildCheckedOrIndeterminate = true;
|
|
171
|
+
allChildrenChecked = false;
|
|
172
|
+
} else {
|
|
173
|
+
allChildrenChecked = false;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// If both conditions are met, we can break early.
|
|
177
|
+
if (!allChildrenChecked && anyChildCheckedOrIndeterminate) {
|
|
178
|
+
break;
|
|
166
179
|
}
|
|
167
|
-
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (allChildrenChecked) {
|
|
183
|
+
tempChecked.add(nodeId);
|
|
184
|
+
tempIndeterminate.delete(nodeId);
|
|
185
|
+
} else if (anyChildCheckedOrIndeterminate) {
|
|
186
|
+
tempChecked.delete(nodeId);
|
|
187
|
+
tempIndeterminate.add(nodeId);
|
|
188
|
+
} else {
|
|
189
|
+
tempChecked.delete(nodeId);
|
|
190
|
+
tempIndeterminate.delete(nodeId);
|
|
168
191
|
}
|
|
169
192
|
}
|
|
170
193
|
|