react-native-tree-multi-select 0.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.
Files changed (108) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +124 -0
  3. package/android/build.gradle +94 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +4 -0
  6. package/android/src/main/java/com/treemultiselect/TreeMultiSelectModule.kt +25 -0
  7. package/android/src/main/java/com/treemultiselect/TreeMultiSelectPackage.kt +17 -0
  8. package/ios/TreeMultiSelect-Bridging-Header.h +2 -0
  9. package/ios/TreeMultiSelect.mm +14 -0
  10. package/ios/TreeMultiSelect.swift +8 -0
  11. package/ios/TreeMultiSelect.xcodeproj/project.pbxproj +283 -0
  12. package/ios/TreeMultiSelect.xcodeproj/project.xcworkspace/contents.xcworkspacedata +4 -0
  13. package/ios/TreeMultiSelect.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  14. package/ios/TreeMultiSelect.xcodeproj/project.xcworkspace/xcuserdata/guest_jj.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  15. package/ios/TreeMultiSelect.xcodeproj/xcuserdata/guest_jj.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  16. package/lib/commonjs/TreeView.js +99 -0
  17. package/lib/commonjs/TreeView.js.map +1 -0
  18. package/lib/commonjs/components/CheckboxView.js +77 -0
  19. package/lib/commonjs/components/CheckboxView.js.map +1 -0
  20. package/lib/commonjs/components/CustomExpandCollapseIcon.js +20 -0
  21. package/lib/commonjs/components/CustomExpandCollapseIcon.js.map +1 -0
  22. package/lib/commonjs/components/NodeList.js +193 -0
  23. package/lib/commonjs/components/NodeList.js.map +1 -0
  24. package/lib/commonjs/helpers/expandCollapse.helper.js +93 -0
  25. package/lib/commonjs/helpers/expandCollapse.helper.js.map +1 -0
  26. package/lib/commonjs/helpers/index.js +61 -0
  27. package/lib/commonjs/helpers/index.js.map +1 -0
  28. package/lib/commonjs/helpers/initNodeMap.helper.js +44 -0
  29. package/lib/commonjs/helpers/initNodeMap.helper.js.map +1 -0
  30. package/lib/commonjs/helpers/search.helper.js +29 -0
  31. package/lib/commonjs/helpers/search.helper.js.map +1 -0
  32. package/lib/commonjs/helpers/selectAll.helper.js +73 -0
  33. package/lib/commonjs/helpers/selectAll.helper.js.map +1 -0
  34. package/lib/commonjs/helpers/toggleCheckbox.helper.js +153 -0
  35. package/lib/commonjs/helpers/toggleCheckbox.helper.js.map +1 -0
  36. package/lib/commonjs/index.js +28 -0
  37. package/lib/commonjs/index.js.map +1 -0
  38. package/lib/commonjs/signals/global.signals.js +42 -0
  39. package/lib/commonjs/signals/global.signals.js.map +1 -0
  40. package/lib/commonjs/types/treeView.types.js +6 -0
  41. package/lib/commonjs/types/treeView.types.js.map +1 -0
  42. package/lib/module/TreeView.js +89 -0
  43. package/lib/module/TreeView.js.map +1 -0
  44. package/lib/module/components/CheckboxView.js +68 -0
  45. package/lib/module/components/CheckboxView.js.map +1 -0
  46. package/lib/module/components/CustomExpandCollapseIcon.js +13 -0
  47. package/lib/module/components/CustomExpandCollapseIcon.js.map +1 -0
  48. package/lib/module/components/NodeList.js +185 -0
  49. package/lib/module/components/NodeList.js.map +1 -0
  50. package/lib/module/helpers/expandCollapse.helper.js +86 -0
  51. package/lib/module/helpers/expandCollapse.helper.js.map +1 -0
  52. package/lib/module/helpers/index.js +6 -0
  53. package/lib/module/helpers/index.js.map +1 -0
  54. package/lib/module/helpers/initNodeMap.helper.js +39 -0
  55. package/lib/module/helpers/initNodeMap.helper.js.map +1 -0
  56. package/lib/module/helpers/search.helper.js +23 -0
  57. package/lib/module/helpers/search.helper.js.map +1 -0
  58. package/lib/module/helpers/selectAll.helper.js +65 -0
  59. package/lib/module/helpers/selectAll.helper.js.map +1 -0
  60. package/lib/module/helpers/toggleCheckbox.helper.js +148 -0
  61. package/lib/module/helpers/toggleCheckbox.helper.js.map +1 -0
  62. package/lib/module/index.js +4 -0
  63. package/lib/module/index.js.map +1 -0
  64. package/lib/module/signals/global.signals.js +26 -0
  65. package/lib/module/signals/global.signals.js.map +1 -0
  66. package/lib/module/types/treeView.types.js +2 -0
  67. package/lib/module/types/treeView.types.js.map +1 -0
  68. package/lib/typescript/TreeView.d.ts +4 -0
  69. package/lib/typescript/TreeView.d.ts.map +1 -0
  70. package/lib/typescript/components/CheckboxView.d.ts +24 -0
  71. package/lib/typescript/components/CheckboxView.d.ts.map +1 -0
  72. package/lib/typescript/components/CustomExpandCollapseIcon.d.ts +4 -0
  73. package/lib/typescript/components/CustomExpandCollapseIcon.d.ts.map +1 -0
  74. package/lib/typescript/components/NodeList.d.ts +14 -0
  75. package/lib/typescript/components/NodeList.d.ts.map +1 -0
  76. package/lib/typescript/helpers/expandCollapse.helper.d.ts +18 -0
  77. package/lib/typescript/helpers/expandCollapse.helper.d.ts.map +1 -0
  78. package/lib/typescript/helpers/index.d.ts +6 -0
  79. package/lib/typescript/helpers/index.d.ts.map +1 -0
  80. package/lib/typescript/helpers/initNodeMap.helper.d.ts +12 -0
  81. package/lib/typescript/helpers/initNodeMap.helper.d.ts.map +1 -0
  82. package/lib/typescript/helpers/search.helper.d.ts +14 -0
  83. package/lib/typescript/helpers/search.helper.d.ts.map +1 -0
  84. package/lib/typescript/helpers/selectAll.helper.d.ts +25 -0
  85. package/lib/typescript/helpers/selectAll.helper.d.ts.map +1 -0
  86. package/lib/typescript/helpers/toggleCheckbox.helper.d.ts +9 -0
  87. package/lib/typescript/helpers/toggleCheckbox.helper.d.ts.map +1 -0
  88. package/lib/typescript/index.d.ts +5 -0
  89. package/lib/typescript/index.d.ts.map +1 -0
  90. package/lib/typescript/signals/global.signals.d.ts +11 -0
  91. package/lib/typescript/signals/global.signals.d.ts.map +1 -0
  92. package/lib/typescript/types/treeView.types.d.ts +61 -0
  93. package/lib/typescript/types/treeView.types.d.ts.map +1 -0
  94. package/package.json +165 -0
  95. package/react-native-tree-multi-select.podspec +41 -0
  96. package/src/TreeView.tsx +139 -0
  97. package/src/components/CheckboxView.tsx +109 -0
  98. package/src/components/CustomExpandCollapseIcon.tsx +20 -0
  99. package/src/components/NodeList.tsx +278 -0
  100. package/src/helpers/expandCollapse.helper.ts +88 -0
  101. package/src/helpers/index.ts +5 -0
  102. package/src/helpers/initNodeMap.helper.ts +46 -0
  103. package/src/helpers/search.helper.ts +28 -0
  104. package/src/helpers/selectAll.helper.ts +59 -0
  105. package/src/helpers/toggleCheckbox.helper.ts +144 -0
  106. package/src/index.tsx +22 -0
  107. package/src/signals/global.signals.ts +36 -0
  108. package/src/types/treeView.types.ts +86 -0
@@ -0,0 +1,144 @@
1
+ import { childToParentMap, nodeMap, state } from "../signals/global.signals";
2
+
3
+ /**
4
+ * Function to toggle checkbox state for a tree structure.
5
+ * It sets the checked and indeterminate state for all affected nodes in the tree after an action to check/uncheck is made.
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.
8
+ * If not provided, the check state will be toggled based on the current state.
9
+ */
10
+ export function toggleCheckboxes(ids: string[], forceCheck?: boolean) {
11
+ // Create new sets for checked and indeterminate state so as not to mutate the original state.
12
+ const checked = new Set(state.value.checked);
13
+ const indeterminate = new Set(state.value.indeterminate);
14
+
15
+ // Maps for memoization of the recursive functions areAllDescendantsChecked and areAnyDescendantsChecked.
16
+ const memoAllDescendantsChecked = new Map();
17
+ const memoAnyDescendantsChecked = new Map();
18
+
19
+ /**
20
+ * Recursive function to check/uncheck a node and all its children.
21
+ * @param {string} nodeId - The id of the node to be checked or unchecked.
22
+ * @param {boolean} isChecked - Whether the node should be checked or unchecked.
23
+ */
24
+ const toggleNodeAndChildren = (nodeId: string, isChecked: boolean) => {
25
+ // Set or unset this node in the checked set, and remove it from the indeterminate set.
26
+ if (isChecked) {
27
+ checked.add(nodeId);
28
+ indeterminate.delete(nodeId);
29
+ } else {
30
+ checked.delete(nodeId);
31
+ }
32
+
33
+ // Get the node from the node map and recursively apply the same state to all its children.
34
+ const node = nodeMap.value.get(nodeId);
35
+ node?.children?.forEach((childNode) => {
36
+ if (isChecked) indeterminate.delete(childNode.id);
37
+ toggleNodeAndChildren(childNode.id, isChecked);
38
+ });
39
+ };
40
+
41
+ /**
42
+ * Recursive function to check if all descendants of a node are checked.
43
+ * It uses memoization to avoid redundant calculations.
44
+ * @param {string} nodeId - The id of the node to be checked.
45
+ * @returns {boolean} - Whether all descendants of the node are checked.
46
+ */
47
+ const areAllDescendantsChecked = (nodeId: string): boolean => {
48
+ // If the result for this node is already in the map, return it.
49
+ if (memoAllDescendantsChecked.has(nodeId)) {
50
+ return memoAllDescendantsChecked.get(nodeId);
51
+ }
52
+
53
+ const node = nodeMap.value.get(nodeId);
54
+ let allChecked = true;
55
+ if (node?.children) {
56
+ // If the node has children, recursively check all children.
57
+ for (const childNode of node.children) {
58
+ allChecked = allChecked && areAllDescendantsChecked(childNode.id);
59
+ }
60
+ } else {
61
+ // If the node has no children, its state is equal to whether it is in the checked set.
62
+ allChecked = checked.has(nodeId);
63
+ }
64
+
65
+ // Store the result in the map and return it.
66
+ memoAllDescendantsChecked.set(nodeId, allChecked);
67
+ return allChecked;
68
+ };
69
+
70
+ /**
71
+ * Recursive function to check if any descendants of a node are checked.
72
+ * It uses memoization to avoid redundant calculations.
73
+ * @param {string} nodeId - The id of the node to be checked.
74
+ * @returns {boolean} - Whether any descendants of the node are checked.
75
+ */
76
+ const areAnyDescendantsChecked = (nodeId: string): boolean => {
77
+ // If the result for this node is already in the map, return it.
78
+ if (memoAnyDescendantsChecked.has(nodeId)) {
79
+ return memoAnyDescendantsChecked.get(nodeId);
80
+ }
81
+
82
+ const node = nodeMap.value.get(nodeId);
83
+ let anyChecked = false;
84
+ if (node?.children) {
85
+ // If the node has children, recursively check all children.
86
+ for (const childNode of node.children) {
87
+ anyChecked = anyChecked || areAnyDescendantsChecked(childNode.id);
88
+ }
89
+ } else {
90
+ // If the node has no children, its state is equal to whether it is in the checked set.
91
+ anyChecked = checked.has(nodeId);
92
+ }
93
+
94
+ // Store the result in the map and return it.
95
+ memoAnyDescendantsChecked.set(nodeId, anyChecked);
96
+ return anyChecked;
97
+ };
98
+
99
+ /**
100
+ * Function to update the indeterminate and checked state of a node and its ancestors.
101
+ * @param {string} nodeId - The id of the node to be updated.
102
+ */
103
+ const updateNodeAndAncestorsState = (nodeId: string) => {
104
+ const node = nodeMap.value.get(nodeId);
105
+ const hasOnlyOneChild = node?.children && node.children.length === 1;
106
+
107
+ // Update the node's state based on the state of its descendants.
108
+ if (areAllDescendantsChecked(nodeId)) {
109
+ checked.add(nodeId);
110
+ indeterminate.delete(nodeId);
111
+ } else if (areAnyDescendantsChecked(nodeId)) {
112
+ if (hasOnlyOneChild) {
113
+ // If a node has only one child and it's not checked,
114
+ // remove this node from both checked and indeterminate sets.
115
+ checked.delete(nodeId);
116
+ indeterminate.delete(nodeId);
117
+ } else {
118
+ checked.delete(nodeId);
119
+ indeterminate.add(nodeId);
120
+ }
121
+ } else {
122
+ checked.delete(nodeId);
123
+ indeterminate.delete(nodeId);
124
+ }
125
+ };
126
+
127
+ // Toggle the clicked nodes and their children.
128
+ ids.forEach((id) => {
129
+ const isChecked = checked.has(id);
130
+ toggleNodeAndChildren(id, forceCheck === undefined ? !isChecked : forceCheck);
131
+ });
132
+
133
+ // Update the state of all affected nodes.
134
+ ids.forEach((id) => {
135
+ let currentNodeId: string | undefined = id;
136
+ while (currentNodeId) {
137
+ updateNodeAndAncestorsState(currentNodeId);
138
+ currentNodeId = childToParentMap.value.get(currentNodeId);
139
+ }
140
+ });
141
+
142
+ // Update the state object with the new checked and indeterminate sets.
143
+ state.value = ({ checked, indeterminate });
144
+ };
package/src/index.tsx ADDED
@@ -0,0 +1,22 @@
1
+ import type {
2
+ TreeNode,
3
+ TreeViewProps,
4
+ TreeViewRef,
5
+ TreeFlatListProps,
6
+ ExpandIconProps,
7
+ CheckBoxViewProps,
8
+ CheckBoxViewStyleProps
9
+ } from "./types/treeView.types";
10
+
11
+ export * from "./TreeView";
12
+ export * from "./components/CheckboxView";
13
+
14
+ export type {
15
+ TreeNode,
16
+ TreeViewProps,
17
+ TreeViewRef,
18
+ TreeFlatListProps,
19
+ ExpandIconProps,
20
+ CheckBoxViewProps,
21
+ CheckBoxViewStyleProps
22
+ };
@@ -0,0 +1,36 @@
1
+ import { signal } from "@preact/signals-react";
2
+ import type { TreeNode, __CheckBoxState__ } from "src/types/treeView.types";
3
+
4
+ export const state = signal<__CheckBoxState__>({
5
+ checked: new Set(),
6
+ indeterminate: new Set(),
7
+ });
8
+ export const expanded = signal(new Set<string>());
9
+
10
+ export const globalData = signal<TreeNode[]>([]);
11
+
12
+ export const nodeMap = signal(new Map<string, TreeNode>());
13
+ export const childToParentMap = signal(new Map<string, string>());
14
+
15
+ export const searchText = signal("");
16
+ export const searchKeys = signal<string[]>([""]);
17
+
18
+ export const innerMostChildrenIds = signal<string[]>([]);
19
+
20
+ export function cleanUpGlobalSignals() {
21
+ state.value = ({
22
+ checked: new Set(),
23
+ indeterminate: new Set(),
24
+ });
25
+ expanded.value = new Set<string>();
26
+
27
+ globalData.value = [];
28
+
29
+ nodeMap.value = new Map<string, TreeNode>();
30
+ childToParentMap.value = new Map<string, string>();
31
+
32
+ searchText.value = "";
33
+ searchKeys.value = [];
34
+
35
+ innerMostChildrenIds.value = [];
36
+ }
@@ -0,0 +1,86 @@
1
+ import type { StyleProp, TextProps, TouchableOpacityProps, ViewStyle } from "react-native";
2
+ import type { FlashListProps } from "@shopify/flash-list";
3
+ import {
4
+ type Props as RNPaperCheckboxAndroidProps
5
+ } from 'react-native-paper/src/components/Checkbox/CheckboxAndroid';
6
+
7
+ export type CheckboxValueType = boolean | 'indeterminate';
8
+
9
+ export interface ExpandIconProps {
10
+ isExpanded: boolean;
11
+ }
12
+
13
+ export type __CheckBoxState__ = {
14
+ checked: Set<string>;
15
+ indeterminate: Set<string>;
16
+ };
17
+
18
+ export interface TreeNode {
19
+ id: string;
20
+ name: string;
21
+ children?: TreeNode[];
22
+ [key: string]: any;
23
+ }
24
+
25
+ export interface __FlattenedTreeNode__ {
26
+ id: string;
27
+ name: string;
28
+ children?: TreeNode[];
29
+ level?: number;
30
+ [key: string]: any;
31
+ }
32
+
33
+ export type TreeFlatListProps<ItemT = any> = Omit<
34
+ FlashListProps<ItemT>,
35
+ "data"
36
+ | "renderItem"
37
+ | "keyExtractor"
38
+ >;
39
+
40
+ export interface TreeViewProps {
41
+ data: TreeNode[];
42
+
43
+ onCheck?: (checkedIds: string[]) => void;
44
+ onExpand?: (expandedIds: string[]) => void;
45
+
46
+ preselectedIds?: string[],
47
+
48
+ treeFlashListProps?: TreeFlatListProps;
49
+ checkBoxViewStyleProps?: CheckBoxViewStyleProps;
50
+
51
+ CheckboxComponent?: React.ComponentType<CheckBoxViewProps>;
52
+ ExpandCollapseIconComponent?: React.ComponentType<ExpandIconProps>;
53
+ ExpandCollapseTouchableComponent?: React.ComponentType<TouchableOpacityProps>;
54
+ }
55
+
56
+ type CheckboxProps = Omit<RNPaperCheckboxAndroidProps, "onPress" | "status">;
57
+
58
+ export interface CheckBoxViewProps extends CheckBoxViewStyleProps {
59
+ value: CheckboxValueType;
60
+ onValueChange: (value: boolean) => void;
61
+ text: string;
62
+ }
63
+
64
+ export interface CheckBoxViewStyleProps {
65
+ // Optional style modifiers
66
+ outermostParentViewStyle?: StyleProp<ViewStyle> | {};
67
+ checkboxParentViewStyle?: StyleProp<ViewStyle> | {};
68
+ textTouchableStyle?: StyleProp<ViewStyle> | {};
69
+
70
+ // Optional checkbox and text component props
71
+ checkboxProps?: CheckboxProps;
72
+ textProps?: TextProps;
73
+ }
74
+
75
+ export interface TreeViewRef {
76
+ selectAll: () => void;
77
+ unselectAll: () => void;
78
+
79
+ selectAllFiltered: () => void;
80
+ unselectAllFiltered: () => void;
81
+
82
+ expandAll: () => void;
83
+ collapseAll: () => void;
84
+
85
+ setSearchText: (searchText: string, searchKeys?: string[]) => void;
86
+ }