react-native-tree-multi-select 1.2.1 → 1.2.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/.editorconfig +15 -0
- package/.gitattributes +3 -0
- package/.github/FUNDING.yml +13 -0
- package/.github/ISSUE_TEMPLATE/bug-report.md +42 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +30 -0
- package/.github/actions/setup/action.yml +28 -0
- package/.github/assets/Jairaj_Jangle_Google_Pay_UPI_QR_Code.jpg +0 -0
- package/.github/assets/paypal_donate.png +0 -0
- package/.github/assets/upi.png +0 -0
- package/.github/workflows/ci.yml +225 -0
- package/.gitignore +73 -0
- package/.nvmrc +1 -0
- package/.watchmanconfig +1 -0
- package/.yarnrc +3 -0
- package/CHANGELOG.md +145 -0
- package/CODE_OF_CONDUCT.md +133 -0
- package/CONTRIBUTING.md +114 -0
- package/babel.config.js +3 -0
- package/example/.bundle/config +2 -0
- package/example/.watchmanconfig +1 -0
- package/example/Gemfile +6 -0
- package/example/README.md +79 -0
- package/example/android/app/build.gradle +130 -0
- package/example/android/app/debug.keystore +0 -0
- package/example/android/app/proguard-rules.pro +10 -0
- package/example/android/app/src/debug/AndroidManifest.xml +13 -0
- package/example/android/app/src/debug/java/com/treemultiselectexample/ReactNativeFlipper.java +75 -0
- package/example/android/app/src/main/AndroidManifest.xml +25 -0
- package/example/android/app/src/main/java/com/treemultiselectexample/MainActivity.java +32 -0
- package/example/android/app/src/main/java/com/treemultiselectexample/MainApplication.java +62 -0
- package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +36 -0
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/values/strings.xml +3 -0
- package/example/android/app/src/main/res/values/styles.xml +9 -0
- package/example/android/app/src/release/java/com/treemultiselectexample/ReactNativeFlipper.java +20 -0
- package/example/android/build.gradle +23 -0
- package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/example/android/gradle/wrapper/gradle-wrapper.properties +6 -0
- package/example/android/gradle.properties +44 -0
- package/example/android/gradlew +244 -0
- package/example/android/gradlew.bat +92 -0
- package/example/android/settings.gradle +4 -0
- package/example/app.json +4 -0
- package/example/babel.config.js +17 -0
- package/example/index.js +5 -0
- package/example/ios/.xcode.env +11 -0
- package/example/ios/File.swift +6 -0
- package/example/ios/Podfile +62 -0
- package/example/ios/Podfile.lock +639 -0
- package/example/ios/TreeMultiSelectExample/AppDelegate.h +6 -0
- package/example/ios/TreeMultiSelectExample/AppDelegate.mm +26 -0
- package/example/ios/TreeMultiSelectExample/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
- package/example/ios/TreeMultiSelectExample/Images.xcassets/Contents.json +6 -0
- package/example/ios/TreeMultiSelectExample/Info.plist +74 -0
- package/example/ios/TreeMultiSelectExample/LaunchScreen.storyboard +47 -0
- package/example/ios/TreeMultiSelectExample/main.m +10 -0
- package/example/ios/TreeMultiSelectExample-Bridging-Header.h +3 -0
- package/example/ios/TreeMultiSelectExample.xcodeproj/project.pbxproj +706 -0
- package/example/ios/TreeMultiSelectExample.xcodeproj/xcshareddata/xcschemes/TreeMultiSelectExample.xcscheme +88 -0
- package/example/ios/TreeMultiSelectExample.xcworkspace/contents.xcworkspacedata +10 -0
- package/example/ios/TreeMultiSelectExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/example/ios/TreeMultiSelectExampleTests/Info.plist +24 -0
- package/example/ios/TreeMultiSelectExampleTests/TreeMultiSelectExampleTests.m +66 -0
- package/example/metro.config.js +45 -0
- package/example/package.json +41 -0
- package/example/react-native.config.js +10 -0
- package/example/src/App.tsx +70 -0
- package/example/src/components/CustomArrow.tsx +71 -0
- package/example/src/components/CustomCheckboxView.tsx +119 -0
- package/example/src/components/CustomNodeRowView.tsx +124 -0
- package/example/src/components/SearchInput.tsx +68 -0
- package/example/src/screens/CustomArrowScreen.tsx +99 -0
- package/example/src/screens/CustomCheckboxScreen.tsx +99 -0
- package/example/src/screens/CustomNodeRowViewScreen.tsx +99 -0
- package/example/src/screens/LargeDataScreen.tsx +95 -0
- package/example/src/screens/MediumDataScreen.tsx +96 -0
- package/example/src/screens/SmallDataScreen.tsx +96 -0
- package/example/src/screens/screens.styles.ts +25 -0
- package/example/src/utils/sampleDataGenerator.ts +32 -0
- package/example/yarn.lock +6368 -0
- package/lefthook.yml +17 -0
- package/lib/typescript/__mocks__/generateTree.mock.d.ts +17 -0
- package/lib/typescript/__mocks__/generateTree.mock.d.ts.map +1 -0
- package/lib/typescript/__mocks__/zustand.d.ts +3 -0
- package/lib/typescript/__mocks__/zustand.d.ts.map +1 -0
- package/lib/typescript/__tests__/expandCollapse.helper.test.d.ts +2 -0
- package/lib/typescript/__tests__/expandCollapse.helper.test.d.ts.map +1 -0
- package/lib/typescript/__tests__/flattenTree.helper.test.d.ts +2 -0
- package/lib/typescript/__tests__/flattenTree.helper.test.d.ts.map +1 -0
- package/lib/typescript/__tests__/initNodeMap.helper.test.d.ts +2 -0
- package/lib/typescript/__tests__/initNodeMap.helper.test.d.ts.map +1 -0
- package/lib/typescript/__tests__/search.helper.test.d.ts +2 -0
- package/lib/typescript/__tests__/search.helper.test.d.ts.map +1 -0
- package/lib/typescript/__tests__/selectAll.helper.test.d.ts +2 -0
- package/lib/typescript/__tests__/selectAll.helper.test.d.ts.map +1 -0
- package/lib/typescript/__tests__/store.test.d.ts +2 -0
- package/lib/typescript/__tests__/store.test.d.ts.map +1 -0
- package/lib/typescript/__tests__/toggleCheckbox.helper.test.d.ts +2 -0
- package/lib/typescript/__tests__/toggleCheckbox.helper.test.d.ts.map +1 -0
- package/package.json +4 -2
- package/scripts/bootstrap.js +29 -0
- package/src/__mocks__/generateTree.mock.ts +125 -0
- package/src/__mocks__/zustand.ts +24 -0
- package/src/__tests__/expandCollapse.helper.test.ts +189 -0
- package/src/__tests__/flattenTree.helper.test.ts +78 -0
- package/src/__tests__/initNodeMap.helper.test.ts +46 -0
- package/src/__tests__/search.helper.test.ts +47 -0
- package/src/__tests__/selectAll.helper.test.ts +233 -0
- package/src/__tests__/store.test.ts +208 -0
- package/src/__tests__/toggleCheckbox.helper.test.ts +124 -0
- package/tsconfig.build.json +5 -0
- package/tsconfig.json +31 -0
- package/turbo.json +34 -0
- package/yarn.lock +9953 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getFilteredTreeData } from "../helpers";
|
|
2
|
+
import { generateTree } from "../__mocks__/generateTree.mock";
|
|
3
|
+
import { TreeNode } from "../types/treeView.types";
|
|
4
|
+
|
|
5
|
+
describe('getFilteredTreeData', () => {
|
|
6
|
+
let nodes: TreeNode[];
|
|
7
|
+
let trimmedSearchTerm: string;
|
|
8
|
+
let searchKeys: string[];
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
nodes = generateTree(4, 10); // Create a tree with depth 3 and breadth 2
|
|
12
|
+
|
|
13
|
+
trimmedSearchTerm = '';
|
|
14
|
+
searchKeys = ['name'];
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('should return all nodes when search term is empty', () => {
|
|
18
|
+
const result = getFilteredTreeData(nodes, trimmedSearchTerm, searchKeys);
|
|
19
|
+
expect(result).toEqual(nodes);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('should return nodes that match the search term', () => {
|
|
23
|
+
trimmedSearchTerm = 'node1';
|
|
24
|
+
const result = getFilteredTreeData(nodes, trimmedSearchTerm, searchKeys);
|
|
25
|
+
expect(result.length).toBeGreaterThan(0);
|
|
26
|
+
result.forEach(node => {
|
|
27
|
+
expect(node.name).toContain(trimmedSearchTerm);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('should return parent nodes whose children match the search term', () => {
|
|
32
|
+
trimmedSearchTerm = 'node1.1';
|
|
33
|
+
const result = getFilteredTreeData(nodes, trimmedSearchTerm, searchKeys);
|
|
34
|
+
expect(result.length).toBeGreaterThan(0);
|
|
35
|
+
result.forEach(node => {
|
|
36
|
+
expect(node.children?.some(
|
|
37
|
+
child => child.name === trimmedSearchTerm
|
|
38
|
+
)).toBeTruthy();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('should return an empty array when no nodes match the search term', () => {
|
|
43
|
+
trimmedSearchTerm = 'nonexistent';
|
|
44
|
+
const result = getFilteredTreeData(nodes, trimmedSearchTerm, searchKeys);
|
|
45
|
+
expect(result).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { tree3d2b } from "../__mocks__/generateTree.mock";
|
|
2
|
+
import {
|
|
3
|
+
getFilteredTreeData,
|
|
4
|
+
getInnerMostChildrenIdsInTree,
|
|
5
|
+
initializeNodeMaps,
|
|
6
|
+
selectAll,
|
|
7
|
+
selectAllFiltered,
|
|
8
|
+
unselectAll,
|
|
9
|
+
unselectAllFiltered
|
|
10
|
+
} from "../helpers";
|
|
11
|
+
import { useTreeViewStore } from "../store/treeView.store";
|
|
12
|
+
import { act } from 'react-test-renderer';
|
|
13
|
+
|
|
14
|
+
jest.mock('zustand');
|
|
15
|
+
|
|
16
|
+
describe('selectAll helpers functions', () => {
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
useTreeViewStore.setState(useTreeViewStore.getState(), true);
|
|
19
|
+
|
|
20
|
+
// Setup mock tree
|
|
21
|
+
useTreeViewStore.getState().updateInitialTreeViewData(tree3d2b);
|
|
22
|
+
initializeNodeMaps(tree3d2b);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('selectAll works correctly', () => {
|
|
26
|
+
// Act
|
|
27
|
+
act(() => {
|
|
28
|
+
selectAll();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Assert
|
|
32
|
+
const { checked, indeterminate } = useTreeViewStore.getState();
|
|
33
|
+
expect(checked).toEqual(new Set([
|
|
34
|
+
'1',
|
|
35
|
+
'1.1',
|
|
36
|
+
'1.1.1',
|
|
37
|
+
"1.1.2",
|
|
38
|
+
'1.2',
|
|
39
|
+
"1.2.1",
|
|
40
|
+
"1.2.2",
|
|
41
|
+
'2',
|
|
42
|
+
'2.1',
|
|
43
|
+
"2.1.1",
|
|
44
|
+
"2.1.2",
|
|
45
|
+
"2.2",
|
|
46
|
+
"2.2.1",
|
|
47
|
+
"2.2.2",
|
|
48
|
+
]));
|
|
49
|
+
expect(indeterminate).toEqual(new Set([]));
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('unselectAll works correctly', () => {
|
|
53
|
+
// Arrange
|
|
54
|
+
act(() => {
|
|
55
|
+
selectAll();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Act
|
|
59
|
+
act(() => {
|
|
60
|
+
unselectAll();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Assert
|
|
64
|
+
const { checked, indeterminate } = useTreeViewStore.getState();
|
|
65
|
+
expect(checked).toEqual(new Set([]));
|
|
66
|
+
expect(indeterminate).toEqual(new Set([]));
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('getInnerMostChildrenIdsInTree works correctly', () => {
|
|
70
|
+
const initialData = useTreeViewStore.getState().initialTreeViewData;;
|
|
71
|
+
|
|
72
|
+
// Act
|
|
73
|
+
const innerMostChildrenIds = getInnerMostChildrenIdsInTree(initialData);
|
|
74
|
+
|
|
75
|
+
// Assert
|
|
76
|
+
expect(innerMostChildrenIds.sort()).toEqual([
|
|
77
|
+
'1.1.1',
|
|
78
|
+
"1.1.2",
|
|
79
|
+
"1.2.1",
|
|
80
|
+
"1.2.2",
|
|
81
|
+
"2.1.1",
|
|
82
|
+
"2.1.2",
|
|
83
|
+
"2.2.1",
|
|
84
|
+
"2.2.2",
|
|
85
|
+
].sort());
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
89
|
+
it('selectAllFiltered works correctly for empty search term', () => {
|
|
90
|
+
// Act
|
|
91
|
+
act(() => {
|
|
92
|
+
selectAllFiltered();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Assert
|
|
96
|
+
const { checked, indeterminate } = useTreeViewStore.getState();
|
|
97
|
+
expect(checked).toEqual(new Set([
|
|
98
|
+
'1',
|
|
99
|
+
'1.1',
|
|
100
|
+
'1.1.1',
|
|
101
|
+
"1.1.2",
|
|
102
|
+
'1.2',
|
|
103
|
+
"1.2.1",
|
|
104
|
+
"1.2.2",
|
|
105
|
+
'2',
|
|
106
|
+
'2.1',
|
|
107
|
+
"2.1.1",
|
|
108
|
+
"2.1.2",
|
|
109
|
+
"2.2",
|
|
110
|
+
"2.2.1",
|
|
111
|
+
"2.2.2",
|
|
112
|
+
]));
|
|
113
|
+
expect(Array.from(indeterminate)).toEqual([]);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('selectAllFiltered works correctly for non-empty search term with found nodes', () => {
|
|
117
|
+
const searchTerm = "1.1";
|
|
118
|
+
|
|
119
|
+
// Act
|
|
120
|
+
act(() => {
|
|
121
|
+
// Update search related states in the store
|
|
122
|
+
useTreeViewStore.getState().updateSearchText(searchTerm);
|
|
123
|
+
useTreeViewStore.getState().updateSearchKeys(["id"]);
|
|
124
|
+
|
|
125
|
+
const { searchText, searchKeys } = useTreeViewStore.getState();
|
|
126
|
+
|
|
127
|
+
// Get filtered tree data (getFilteredTreeData is already tested in `search.helper.test.ts`)
|
|
128
|
+
const filteredTreeData = getFilteredTreeData(
|
|
129
|
+
tree3d2b,
|
|
130
|
+
searchText,
|
|
131
|
+
searchKeys
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
// Get the ids of the inner most children in the filtered tree
|
|
135
|
+
const innerMostChildrenIds = getInnerMostChildrenIdsInTree(
|
|
136
|
+
filteredTreeData
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
// Update the state of innerMostChildrenIds in the store
|
|
140
|
+
useTreeViewStore.getState().updateInnerMostChildrenIds(
|
|
141
|
+
innerMostChildrenIds
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
// Call the select all filtered function
|
|
145
|
+
selectAllFiltered();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Assert
|
|
149
|
+
const { checked, indeterminate } = useTreeViewStore.getState();
|
|
150
|
+
expect(checked).toEqual(new Set([
|
|
151
|
+
'1.1', // As both of it's children are checked
|
|
152
|
+
'1.1.1',
|
|
153
|
+
'1.1.2',
|
|
154
|
+
'2.1.1'
|
|
155
|
+
]));
|
|
156
|
+
expect(indeterminate).toEqual(new Set([
|
|
157
|
+
'1', // As 1.2 is unchecked
|
|
158
|
+
'2', // only one if it's children is checked
|
|
159
|
+
'2.1'
|
|
160
|
+
]));
|
|
161
|
+
});
|
|
162
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
163
|
+
|
|
164
|
+
it('unselectAllFiltered works correctly for empty search term', () => {
|
|
165
|
+
// Arrange
|
|
166
|
+
act(() => {
|
|
167
|
+
selectAllFiltered();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Act
|
|
171
|
+
act(() => {
|
|
172
|
+
unselectAllFiltered();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Assert
|
|
176
|
+
const { checked, indeterminate } = useTreeViewStore.getState();
|
|
177
|
+
expect(checked).toEqual(new Set([]));
|
|
178
|
+
expect(indeterminate).toEqual(new Set([]));
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('unselectAllFiltered works correctly for non-empty search term with found nodes', () => {
|
|
182
|
+
const searchTerm = "1.1";
|
|
183
|
+
|
|
184
|
+
// Act
|
|
185
|
+
act(() => {
|
|
186
|
+
// First select all the nodes(unfiltered)
|
|
187
|
+
selectAll();
|
|
188
|
+
|
|
189
|
+
// Update search related states in the store
|
|
190
|
+
useTreeViewStore.getState().updateSearchText(searchTerm);
|
|
191
|
+
useTreeViewStore.getState().updateSearchKeys(["id"]);
|
|
192
|
+
|
|
193
|
+
const { searchText, searchKeys } = useTreeViewStore.getState();
|
|
194
|
+
|
|
195
|
+
// Get filtered tree data (getFilteredTreeData is already tested in `search.helper.test.ts`)
|
|
196
|
+
const filteredTreeData = getFilteredTreeData(
|
|
197
|
+
tree3d2b,
|
|
198
|
+
searchText,
|
|
199
|
+
searchKeys
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
// Get the ids of the inner most children in the filtered tree
|
|
203
|
+
const innerMostChildrenIds = getInnerMostChildrenIdsInTree(
|
|
204
|
+
filteredTreeData
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
// Update the state of innerMostChildrenIds in the store
|
|
208
|
+
useTreeViewStore.getState().updateInnerMostChildrenIds(
|
|
209
|
+
innerMostChildrenIds
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// Call the select all filtered function
|
|
213
|
+
unselectAllFiltered();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Assert
|
|
217
|
+
const { checked, indeterminate } = useTreeViewStore.getState();
|
|
218
|
+
expect(checked).toEqual(new Set([
|
|
219
|
+
'1.2',
|
|
220
|
+
'1.2.1',
|
|
221
|
+
'1.2.2',
|
|
222
|
+
'2.1.2',
|
|
223
|
+
'2.2',
|
|
224
|
+
'2.2.1',
|
|
225
|
+
'2.2.2',
|
|
226
|
+
]));
|
|
227
|
+
expect(indeterminate).toEqual(new Set([
|
|
228
|
+
'1',
|
|
229
|
+
'2',
|
|
230
|
+
'2.1'
|
|
231
|
+
]));
|
|
232
|
+
});
|
|
233
|
+
});
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
jest.mock('zustand');
|
|
2
|
+
|
|
3
|
+
import { act } from 'react-test-renderer';
|
|
4
|
+
import { useTreeViewStore } from '../store/treeView.store';
|
|
5
|
+
import { createRandomNumberSet, generateTree } from '../__mocks__/generateTree.mock';
|
|
6
|
+
import { TreeNode } from '../types/treeView.types';
|
|
7
|
+
|
|
8
|
+
describe('TreeViewStore', () => {
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
useTreeViewStore.setState(useTreeViewStore.getState(), true);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('updateChecked correctly updates the checked state', () => {
|
|
15
|
+
const val1 = new Set(['1', '2']);
|
|
16
|
+
act(() => {
|
|
17
|
+
useTreeViewStore.getState().updateChecked(val1);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
expect(useTreeViewStore.getState().checked).toEqual(val1);
|
|
21
|
+
|
|
22
|
+
const val2 = createRandomNumberSet();
|
|
23
|
+
act(() => {
|
|
24
|
+
useTreeViewStore.getState().updateChecked(val2);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
expect(useTreeViewStore.getState().checked).toEqual(val2);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('updateIndeterminate correctly updates the indeterminate state', () => {
|
|
31
|
+
const val1 = new Set(['1', '2']);
|
|
32
|
+
act(() => {
|
|
33
|
+
useTreeViewStore.getState().updateIndeterminate(val1);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(useTreeViewStore.getState().indeterminate).toEqual(val1);
|
|
37
|
+
|
|
38
|
+
const val2 = createRandomNumberSet();
|
|
39
|
+
act(() => {
|
|
40
|
+
useTreeViewStore.getState().updateIndeterminate(val2);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
expect(useTreeViewStore.getState().indeterminate).toEqual(val2);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('updateExpanded correctly updates the expanded state', () => {
|
|
47
|
+
const val1 = new Set(['1', '2']);
|
|
48
|
+
act(() => {
|
|
49
|
+
useTreeViewStore.getState().updateExpanded(val1);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
expect(useTreeViewStore.getState().expanded).toEqual(val1);
|
|
53
|
+
|
|
54
|
+
const val2 = createRandomNumberSet();
|
|
55
|
+
act(() => {
|
|
56
|
+
useTreeViewStore.getState().updateExpanded(val2);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(useTreeViewStore.getState().expanded).toEqual(val2);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('updateInitialTreeViewData correctly updates the initialTreeViewData state', () => {
|
|
63
|
+
const val1: TreeNode[] = [{
|
|
64
|
+
id: '1',
|
|
65
|
+
name: 'node1',
|
|
66
|
+
children: [
|
|
67
|
+
{
|
|
68
|
+
id: '1.1', name: 'node1.1', children: [
|
|
69
|
+
{ id: '1.1.1', name: 'node1.1.1' },
|
|
70
|
+
{ id: '1.1.2', name: 'node1.1.2' },
|
|
71
|
+
{ id: '1.1.3', name: 'node1.1.3' },
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: '1.2', name: 'node1.2', children: [
|
|
76
|
+
{ id: '1.2.1', name: 'node1.2.1' },
|
|
77
|
+
{ id: '1.2.2', name: 'node1.2.2' },
|
|
78
|
+
{ id: '1.2.3', name: 'node1.2.3' },
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: '1.3', name: 'node1.3', children: [
|
|
83
|
+
{ id: '1.3.1', name: 'node1.3.1' },
|
|
84
|
+
{ id: '1.3.2', name: 'node1.3.2' },
|
|
85
|
+
{ id: '1.3.3', name: 'node1.3.3' },
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
}];
|
|
90
|
+
act(() => {
|
|
91
|
+
useTreeViewStore.getState().updateInitialTreeViewData(val1);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
expect(useTreeViewStore.getState().initialTreeViewData).toEqual(val1);
|
|
95
|
+
|
|
96
|
+
const val2 = generateTree(3, 3);
|
|
97
|
+
act(() => {
|
|
98
|
+
useTreeViewStore.getState().updateInitialTreeViewData(val2);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(useTreeViewStore.getState().initialTreeViewData).toEqual(val2);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('updateNodeMap correctly updates the node map', () => {
|
|
105
|
+
const val1 = new Map<string, TreeNode>();
|
|
106
|
+
val1.set('1', generateTree(5, 10)[0] as TreeNode);
|
|
107
|
+
act(() => {
|
|
108
|
+
useTreeViewStore.getState().updateNodeMap(val1);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
expect(useTreeViewStore.getState().nodeMap).toEqual(val1);
|
|
112
|
+
|
|
113
|
+
const val2 = new Map<string, TreeNode>();
|
|
114
|
+
val2.set('2', {} as TreeNode);
|
|
115
|
+
act(() => {
|
|
116
|
+
useTreeViewStore.getState().updateNodeMap(val2);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
expect(useTreeViewStore.getState().nodeMap).toEqual(val2);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Testing updateChildToParentMap
|
|
123
|
+
test('updateChildToParentMap correctly updates the child to parent map', () => {
|
|
124
|
+
const val1 = new Map<string, string>();
|
|
125
|
+
val1.set('1', '2');
|
|
126
|
+
act(() => {
|
|
127
|
+
useTreeViewStore.getState().updateChildToParentMap(val1);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
expect(useTreeViewStore.getState().childToParentMap).toEqual(val1);
|
|
131
|
+
|
|
132
|
+
const val2 = new Map<string, string>();
|
|
133
|
+
val2.set('3', '4');
|
|
134
|
+
act(() => {
|
|
135
|
+
useTreeViewStore.getState().updateChildToParentMap(val2);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
expect(useTreeViewStore.getState().childToParentMap).toEqual(val2);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Testing updateSearchText
|
|
142
|
+
test('updateSearchText correctly updates the search text', () => {
|
|
143
|
+
const val1 = 'hello';
|
|
144
|
+
act(() => {
|
|
145
|
+
useTreeViewStore.getState().updateSearchText(val1);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
expect(useTreeViewStore.getState().searchText).toEqual(val1);
|
|
149
|
+
|
|
150
|
+
const val2 = 'world';
|
|
151
|
+
act(() => {
|
|
152
|
+
useTreeViewStore.getState().updateSearchText(val2);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(useTreeViewStore.getState().searchText).toEqual(val2);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Testing updateSearchKeys
|
|
159
|
+
test('updateSearchKeys correctly updates the search keys', () => {
|
|
160
|
+
const val1 = ['hello'];
|
|
161
|
+
act(() => {
|
|
162
|
+
useTreeViewStore.getState().updateSearchKeys(val1);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
expect(useTreeViewStore.getState().searchKeys).toEqual(val1);
|
|
166
|
+
|
|
167
|
+
const val2 = ['world'];
|
|
168
|
+
act(() => {
|
|
169
|
+
useTreeViewStore.getState().updateSearchKeys(val2);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
expect(useTreeViewStore.getState().searchKeys).toEqual(val2);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Testing updateInnerMostChildrenIds
|
|
176
|
+
test('updateInnerMostChildrenIds correctly updates the inner most children ids', () => {
|
|
177
|
+
const val1 = ['1', '2'];
|
|
178
|
+
act(() => {
|
|
179
|
+
useTreeViewStore.getState().updateInnerMostChildrenIds(val1);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
expect(useTreeViewStore.getState().innerMostChildrenIds).toEqual(val1);
|
|
183
|
+
|
|
184
|
+
const val2 = ['3', '4'];
|
|
185
|
+
act(() => {
|
|
186
|
+
useTreeViewStore.getState().updateInnerMostChildrenIds(val2);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
expect(useTreeViewStore.getState().innerMostChildrenIds).toEqual(val2);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Testing cleanUpTreeViewStore
|
|
193
|
+
test('cleanUpTreeViewStore correctly cleans up the store', () => {
|
|
194
|
+
act(() => {
|
|
195
|
+
useTreeViewStore.getState().cleanUpTreeViewStore();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
expect(useTreeViewStore.getState().checked).toEqual(new Set());
|
|
199
|
+
expect(useTreeViewStore.getState().indeterminate).toEqual(new Set());
|
|
200
|
+
expect(useTreeViewStore.getState().expanded).toEqual(new Set());
|
|
201
|
+
expect(useTreeViewStore.getState().initialTreeViewData).toEqual([]);
|
|
202
|
+
expect(useTreeViewStore.getState().nodeMap).toEqual(new Map());
|
|
203
|
+
expect(useTreeViewStore.getState().childToParentMap).toEqual(new Map());
|
|
204
|
+
expect(useTreeViewStore.getState().searchText).toEqual("");
|
|
205
|
+
expect(useTreeViewStore.getState().searchKeys).toEqual([""]);
|
|
206
|
+
expect(useTreeViewStore.getState().innerMostChildrenIds).toEqual([]);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
jest.mock('zustand');
|
|
2
|
+
|
|
3
|
+
import { useTreeViewStore } from '../store/treeView.store';
|
|
4
|
+
import {
|
|
5
|
+
initializeNodeMaps,
|
|
6
|
+
toggleCheckboxes
|
|
7
|
+
} from '../helpers';
|
|
8
|
+
import { act } from 'react-test-renderer';
|
|
9
|
+
import { tree3d2b } from '../__mocks__/generateTree.mock';
|
|
10
|
+
|
|
11
|
+
describe('toggleCheckboxes', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
useTreeViewStore.setState(useTreeViewStore.getState(), true);
|
|
14
|
+
|
|
15
|
+
// Setup mock tree
|
|
16
|
+
useTreeViewStore.getState().updateInitialTreeViewData(tree3d2b);
|
|
17
|
+
initializeNodeMaps(tree3d2b);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('correctly updates checkbox states', () => {
|
|
21
|
+
// Act
|
|
22
|
+
act(() => {
|
|
23
|
+
// Pre-selection also got covered in this test
|
|
24
|
+
toggleCheckboxes(['1', '2'], true);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Assert
|
|
28
|
+
const { checked, indeterminate } = useTreeViewStore.getState();
|
|
29
|
+
|
|
30
|
+
expect(checked).toEqual(new Set([
|
|
31
|
+
'1',
|
|
32
|
+
'1.1',
|
|
33
|
+
'1.1.1',
|
|
34
|
+
'1.1.2',
|
|
35
|
+
'1.2',
|
|
36
|
+
'1.2.1',
|
|
37
|
+
'1.2.2',
|
|
38
|
+
'2',
|
|
39
|
+
'2.1',
|
|
40
|
+
'2.1.1',
|
|
41
|
+
'2.1.2',
|
|
42
|
+
'2.2',
|
|
43
|
+
'2.2.1',
|
|
44
|
+
'2.2.2'
|
|
45
|
+
]));
|
|
46
|
+
|
|
47
|
+
expect(indeterminate).toEqual(new Set([]));
|
|
48
|
+
|
|
49
|
+
// Act
|
|
50
|
+
act(() => {
|
|
51
|
+
toggleCheckboxes(['1.2']); // Was checked, now should be unchecked
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Assert
|
|
55
|
+
const {
|
|
56
|
+
checked: checkedAfterUncheck,
|
|
57
|
+
indeterminate: indeterminateAfterUncheck
|
|
58
|
+
} = useTreeViewStore.getState();
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
expect(checkedAfterUncheck).toEqual(new Set([
|
|
62
|
+
'1.1',
|
|
63
|
+
'1.1.1',
|
|
64
|
+
'1.1.2',
|
|
65
|
+
'2',
|
|
66
|
+
'2.1',
|
|
67
|
+
'2.1.1',
|
|
68
|
+
'2.1.2',
|
|
69
|
+
'2.2',
|
|
70
|
+
'2.2.1',
|
|
71
|
+
'2.2.2'
|
|
72
|
+
]));
|
|
73
|
+
|
|
74
|
+
expect(indeterminateAfterUncheck).toEqual(new Set([
|
|
75
|
+
"1"
|
|
76
|
+
]));
|
|
77
|
+
|
|
78
|
+
// Act
|
|
79
|
+
act(() => {
|
|
80
|
+
toggleCheckboxes(['2']); // Was checked, now should be unchecked
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Assert
|
|
84
|
+
const {
|
|
85
|
+
checked: checkedAfterUncheck2,
|
|
86
|
+
indeterminate: indeterminateAfterUncheck2
|
|
87
|
+
} = useTreeViewStore.getState();
|
|
88
|
+
|
|
89
|
+
expect(checkedAfterUncheck2).toEqual(new Set([
|
|
90
|
+
'1.1',
|
|
91
|
+
'1.1.1',
|
|
92
|
+
'1.1.2'
|
|
93
|
+
]));
|
|
94
|
+
|
|
95
|
+
expect(indeterminateAfterUncheck2).toEqual(new Set([
|
|
96
|
+
"1"
|
|
97
|
+
]));
|
|
98
|
+
|
|
99
|
+
// Act
|
|
100
|
+
act(() => {
|
|
101
|
+
toggleCheckboxes(['1.2']); // Was unchecked, now should be checked
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Assert
|
|
105
|
+
const {
|
|
106
|
+
checked: checkedAfter1ChildrenCheck,
|
|
107
|
+
indeterminate: indeterminateAfter1ChildrenCheck
|
|
108
|
+
} = useTreeViewStore.getState();
|
|
109
|
+
|
|
110
|
+
// As all children of node 1 are checked, it should also be checked
|
|
111
|
+
expect(checkedAfter1ChildrenCheck).toEqual(new Set([
|
|
112
|
+
'1', // All children are checked again
|
|
113
|
+
'1.1',
|
|
114
|
+
'1.1.1',
|
|
115
|
+
'1.1.2',
|
|
116
|
+
'1.2',
|
|
117
|
+
'1.2.1',
|
|
118
|
+
'1.2.2'
|
|
119
|
+
]));
|
|
120
|
+
|
|
121
|
+
// 1 is all checked whereas all children of 2 are unchecked
|
|
122
|
+
expect(indeterminateAfter1ChildrenCheck).toEqual(new Set([]));
|
|
123
|
+
});
|
|
124
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"exclude": [
|
|
3
|
+
"node_modules"
|
|
4
|
+
],
|
|
5
|
+
"compilerOptions": {
|
|
6
|
+
"baseUrl": "./",
|
|
7
|
+
"paths": {
|
|
8
|
+
"react-native-tree-multi-select": ["./src/index"]
|
|
9
|
+
},
|
|
10
|
+
"allowUnreachableCode": false,
|
|
11
|
+
"allowUnusedLabels": false,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"jsx": "react",
|
|
15
|
+
"lib": ["esnext", "dom"],
|
|
16
|
+
"module": "esnext",
|
|
17
|
+
"moduleResolution": "node",
|
|
18
|
+
"noFallthroughCasesInSwitch": true,
|
|
19
|
+
"noImplicitReturns": true,
|
|
20
|
+
"noImplicitUseStrict": false,
|
|
21
|
+
"noStrictGenericChecks": false,
|
|
22
|
+
"noUncheckedIndexedAccess": true,
|
|
23
|
+
"noUnusedLocals": true,
|
|
24
|
+
"noUnusedParameters": true,
|
|
25
|
+
"resolveJsonModule": true,
|
|
26
|
+
"skipLibCheck": true,
|
|
27
|
+
"strict": true,
|
|
28
|
+
"target": "esnext",
|
|
29
|
+
"verbatimModuleSyntax": false
|
|
30
|
+
}
|
|
31
|
+
}
|
package/turbo.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://turbo.build/schema.json",
|
|
3
|
+
"pipeline": {
|
|
4
|
+
"build:android": {
|
|
5
|
+
"inputs": [
|
|
6
|
+
"package.json",
|
|
7
|
+
"android",
|
|
8
|
+
"!android/build",
|
|
9
|
+
"src/*.ts",
|
|
10
|
+
"src/*.tsx",
|
|
11
|
+
"example/package.json",
|
|
12
|
+
"example/android",
|
|
13
|
+
"!example/android/.gradle",
|
|
14
|
+
"!example/android/build",
|
|
15
|
+
"!example/android/app/build"
|
|
16
|
+
],
|
|
17
|
+
"outputs": []
|
|
18
|
+
},
|
|
19
|
+
"build:ios": {
|
|
20
|
+
"inputs": [
|
|
21
|
+
"package.json",
|
|
22
|
+
"*.podspec",
|
|
23
|
+
"ios",
|
|
24
|
+
"src/*.ts",
|
|
25
|
+
"src/*.tsx",
|
|
26
|
+
"example/package.json",
|
|
27
|
+
"example/ios",
|
|
28
|
+
"!example/ios/build",
|
|
29
|
+
"!example/ios/Pods"
|
|
30
|
+
],
|
|
31
|
+
"outputs": []
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|