react-native-tree-multi-select 1.7.0 → 1.8.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 (71) hide show
  1. package/README.md +6 -6
  2. package/lib/commonjs/TreeView.js +6 -4
  3. package/lib/commonjs/TreeView.js.map +1 -1
  4. package/lib/commonjs/components/NodeList.js +3 -2
  5. package/lib/commonjs/components/NodeList.js.map +1 -1
  6. package/lib/commonjs/helpers/expandCollapse.helper.js.map +1 -1
  7. package/lib/commonjs/helpers/flattenTree.helper.js +1 -1
  8. package/lib/commonjs/helpers/flattenTree.helper.js.map +1 -1
  9. package/lib/commonjs/helpers/search.helper.js +5 -5
  10. package/lib/commonjs/helpers/search.helper.js.map +1 -1
  11. package/lib/commonjs/helpers/selectAll.helper.js +5 -5
  12. package/lib/commonjs/helpers/selectAll.helper.js.map +1 -1
  13. package/lib/commonjs/helpers/toggleCheckbox.helper.js.map +1 -1
  14. package/lib/commonjs/helpers/treeNode.helper.js +1 -1
  15. package/lib/commonjs/helpers/treeNode.helper.js.map +1 -1
  16. package/lib/commonjs/store/treeView.store.js +5 -3
  17. package/lib/commonjs/store/treeView.store.js.map +1 -1
  18. package/lib/commonjs/utils/typedMemo.js +11 -0
  19. package/lib/commonjs/utils/typedMemo.js.map +1 -0
  20. package/lib/module/TreeView.js +6 -4
  21. package/lib/module/TreeView.js.map +1 -1
  22. package/lib/module/components/NodeList.js +3 -2
  23. package/lib/module/components/NodeList.js.map +1 -1
  24. package/lib/module/helpers/expandCollapse.helper.js.map +1 -1
  25. package/lib/module/helpers/flattenTree.helper.js +1 -1
  26. package/lib/module/helpers/flattenTree.helper.js.map +1 -1
  27. package/lib/module/helpers/search.helper.js +5 -5
  28. package/lib/module/helpers/search.helper.js.map +1 -1
  29. package/lib/module/helpers/selectAll.helper.js +5 -5
  30. package/lib/module/helpers/selectAll.helper.js.map +1 -1
  31. package/lib/module/helpers/toggleCheckbox.helper.js.map +1 -1
  32. package/lib/module/helpers/treeNode.helper.js +1 -1
  33. package/lib/module/helpers/treeNode.helper.js.map +1 -1
  34. package/lib/module/store/treeView.store.js +5 -3
  35. package/lib/module/store/treeView.store.js.map +1 -1
  36. package/lib/module/utils/typedMemo.js +7 -0
  37. package/lib/module/utils/typedMemo.js.map +1 -0
  38. package/lib/typescript/TreeView.d.ts +5 -1
  39. package/lib/typescript/TreeView.d.ts.map +1 -1
  40. package/lib/typescript/components/NodeList.d.ts +2 -2
  41. package/lib/typescript/components/NodeList.d.ts.map +1 -1
  42. package/lib/typescript/helpers/expandCollapse.helper.d.ts +3 -3
  43. package/lib/typescript/helpers/expandCollapse.helper.d.ts.map +1 -1
  44. package/lib/typescript/helpers/flattenTree.helper.d.ts +1 -1
  45. package/lib/typescript/helpers/flattenTree.helper.d.ts.map +1 -1
  46. package/lib/typescript/helpers/search.helper.d.ts +1 -1
  47. package/lib/typescript/helpers/search.helper.d.ts.map +1 -1
  48. package/lib/typescript/helpers/selectAll.helper.d.ts +1 -1
  49. package/lib/typescript/helpers/selectAll.helper.d.ts.map +1 -1
  50. package/lib/typescript/helpers/toggleCheckbox.helper.d.ts +1 -1
  51. package/lib/typescript/helpers/toggleCheckbox.helper.d.ts.map +1 -1
  52. package/lib/typescript/helpers/treeNode.helper.d.ts +1 -1
  53. package/lib/typescript/helpers/treeNode.helper.d.ts.map +1 -1
  54. package/lib/typescript/store/treeView.store.d.ts +17 -17
  55. package/lib/typescript/store/treeView.store.d.ts.map +1 -1
  56. package/lib/typescript/types/treeView.types.d.ts +22 -22
  57. package/lib/typescript/types/treeView.types.d.ts.map +1 -1
  58. package/lib/typescript/utils/typedMemo.d.ts +3 -0
  59. package/lib/typescript/utils/typedMemo.d.ts.map +1 -0
  60. package/package.json +1 -1
  61. package/src/TreeView.tsx +16 -14
  62. package/src/components/NodeList.tsx +12 -11
  63. package/src/helpers/expandCollapse.helper.ts +9 -9
  64. package/src/helpers/flattenTree.helper.ts +7 -7
  65. package/src/helpers/search.helper.ts +12 -12
  66. package/src/helpers/selectAll.helper.ts +11 -11
  67. package/src/helpers/toggleCheckbox.helper.ts +11 -11
  68. package/src/helpers/treeNode.helper.ts +8 -8
  69. package/src/store/treeView.store.ts +39 -37
  70. package/src/types/treeView.types.ts +23 -23
  71. package/src/utils/typedMemo.ts +4 -0
@@ -26,11 +26,12 @@ import { CheckboxView } from "./CheckboxView";
26
26
  import { CustomExpandCollapseIcon } from "./CustomExpandCollapseIcon";
27
27
  import { defaultIndentationMultiplier } from "../constants/treeView.constants";
28
28
  import { useShallow } from 'zustand/react/shallow';
29
+ import { typedMemo } from "../utils/typedMemo";
29
30
 
30
- const NodeList = React.memo(_NodeList);
31
+ const NodeList = typedMemo(_NodeList);
31
32
  export default NodeList;
32
33
 
33
- function _NodeList(props: NodeListProps) {
34
+ function _NodeList<ID>(props: NodeListProps<ID>) {
34
35
  const {
35
36
  storeId,
36
37
 
@@ -50,7 +51,7 @@ function _NodeList(props: NodeListProps) {
50
51
  updateInnerMostChildrenIds,
51
52
  searchKeys,
52
53
  searchText
53
- } = useTreeViewStore(storeId)(useShallow(
54
+ } = useTreeViewStore<ID>(storeId)(useShallow(
54
55
  state => ({
55
56
  expanded: state.expanded,
56
57
  initialTreeViewData: state.initialTreeViewData,
@@ -61,31 +62,31 @@ function _NodeList(props: NodeListProps) {
61
62
  ));
62
63
 
63
64
  // First we filter the tree as per the search term and keys
64
- const filteredTree = React.useMemo(() => getFilteredTreeData(
65
+ const filteredTree = React.useMemo(() => getFilteredTreeData<ID>(
65
66
  initialTreeViewData,
66
67
  searchText.trim().toLowerCase(),
67
68
  searchKeys
68
69
  ), [initialTreeViewData, searchText, searchKeys]);
69
70
 
70
71
  // Then we flatten the tree to make it "render-compatible" in a "flat" list
71
- const flattenedFilteredNodes = React.useMemo(() => getFlattenedTreeData(
72
+ const flattenedFilteredNodes = React.useMemo(() => getFlattenedTreeData<ID>(
72
73
  filteredTree,
73
74
  expanded,
74
75
  ), [filteredTree, expanded]);
75
76
 
76
77
  // And update the innermost children id -> required to un/select filtered tree
77
78
  React.useEffect(() => {
78
- const updatedInnerMostChildrenIds = getInnerMostChildrenIdsInTree(
79
+ const updatedInnerMostChildrenIds = getInnerMostChildrenIdsInTree<ID>(
79
80
  filteredTree
80
81
  );
81
82
  updateInnerMostChildrenIds(updatedInnerMostChildrenIds);
82
83
  }, [filteredTree, updateInnerMostChildrenIds]);
83
84
 
84
85
  const nodeRenderer = React.useCallback((
85
- { item }: { item: __FlattenedTreeNode__; }
86
+ { item }: { item: __FlattenedTreeNode__<ID>; }
86
87
  ) => {
87
88
  return (
88
- <Node
89
+ <Node<ID>
89
90
  storeId={storeId}
90
91
 
91
92
  node={item}
@@ -144,8 +145,8 @@ function getValue(
144
145
  }
145
146
  }
146
147
 
147
- const Node = React.memo(_Node);
148
- function _Node(props: NodeProps) {
148
+ const Node = typedMemo(_Node);
149
+ function _Node<ID>(props: NodeProps<ID>) {
149
150
  const {
150
151
  storeId,
151
152
 
@@ -164,7 +165,7 @@ function _Node(props: NodeProps) {
164
165
  const {
165
166
  isExpanded,
166
167
  value,
167
- } = useTreeViewStore(storeId)(useShallow(
168
+ } = useTreeViewStore<ID>(storeId)(useShallow(
168
169
  state => ({
169
170
  isExpanded: state.expanded.has(node.id),
170
171
  value: getValue(
@@ -8,8 +8,8 @@ import { getTreeViewStore } from "../store/treeView.store";
8
8
  *
9
9
  * @param id - The ID of the tree node to toggle.
10
10
  */
11
- export function handleToggleExpand(storeId: string, id: string) {
12
- const treeViewStore = getTreeViewStore(storeId);
11
+ export function handleToggleExpand<ID>(storeId: string, id: ID) {
12
+ const treeViewStore = getTreeViewStore<ID>(storeId);
13
13
  const {
14
14
  expanded,
15
15
  updateExpanded,
@@ -72,14 +72,14 @@ export function collapseAll(storeId: string) {
72
72
  * its ancestors up to the root.
73
73
  * @param ids - Ids of nodes to expand.
74
74
  */
75
- export function expandNodes(storeId: string, ids: string[]) {
76
- const treeViewStore = getTreeViewStore(storeId);
75
+ export function expandNodes<ID>(storeId: string, ids: ID[]) {
76
+ const treeViewStore = getTreeViewStore<ID>(storeId);
77
77
  const { expanded, updateExpanded, childToParentMap } = treeViewStore.getState();
78
78
  const newExpanded = new Set(expanded);
79
- const processedIds = new Set<string>();
79
+ const processedIds = new Set<ID>();
80
80
 
81
81
  ids.forEach((id) => {
82
- let currentId: string | undefined = id;
82
+ let currentId: ID | undefined = id;
83
83
  while (currentId && !processedIds.has(currentId)) {
84
84
  newExpanded.add(currentId);
85
85
  processedIds.add(currentId);
@@ -95,13 +95,13 @@ export function expandNodes(storeId: string, ids: string[]) {
95
95
  * its descendants.
96
96
  * @param ids - Ids of nodes to collapse.
97
97
  */
98
- export function collapseNodes(storeId: string, ids: string[]) {
99
- const treeViewStore = getTreeViewStore(storeId);
98
+ export function collapseNodes<ID>(storeId: string, ids: ID[]) {
99
+ const treeViewStore = getTreeViewStore<ID>(storeId);
100
100
  const { expanded, updateExpanded, nodeMap } = treeViewStore.getState();
101
101
  const newExpanded = new Set(expanded);
102
102
 
103
103
  // Use an iterative approach to remove all descendants from the expanded set
104
- const deleteChildrenFromExpanded = (nodeId: string) => {
104
+ const deleteChildrenFromExpanded = (nodeId: ID) => {
105
105
  const stack = [nodeId];
106
106
 
107
107
  while (stack.length > 0) {
@@ -1,7 +1,7 @@
1
1
  import { TreeNode, __FlattenedTreeNode__ } from "../types/treeView.types";
2
2
 
3
3
  /**
4
- * Flatten the tree and attach a "level" key to object to indicate it's depth. This
4
+ * Flatten the tree and attach a "level" key to object to indicate it's depth. This
5
5
  * returns the flattened tree data of expanded ids only. We do not prune the tree off the
6
6
  * children after the flattening as it would be unnecessary computation.
7
7
  *
@@ -10,12 +10,12 @@ import { TreeNode, __FlattenedTreeNode__ } from "../types/treeView.types";
10
10
  * @param __level__ - (optional) for internal recursive use only
11
11
  * @returns Flattened tree data with expanded ids only
12
12
  */
13
- export function getFlattenedTreeData(
14
- nodes: TreeNode[],
15
- expandedIds: Set<string>,
16
- ): __FlattenedTreeNode__[] {
17
- const flattened: __FlattenedTreeNode__[] = [];
18
- const stack: { node: TreeNode; level: number; }[] = [];
13
+ export function getFlattenedTreeData<ID>(
14
+ nodes: TreeNode<ID>[],
15
+ expandedIds: Set<ID>,
16
+ ): __FlattenedTreeNode__<ID>[] {
17
+ const flattened: __FlattenedTreeNode__<ID>[] = [];
18
+ const stack: { node: TreeNode<ID>; level: number; }[] = [];
19
19
 
20
20
  // Initialize stack with the root nodes and level 0
21
21
  for (let i = nodes.length - 1; i >= 0; i--) {
@@ -3,22 +3,22 @@ import { TreeNode } from "../types/treeView.types";
3
3
  /**
4
4
  * Get filtered tree data based on the search term and the search keys
5
5
  * If any of the parent contains the search term, the tree will also contain
6
- * it's children.
7
- *
6
+ * it's children.
7
+ *
8
8
  * If only one of the innermost children contains the search term then it's siblings
9
9
  * won't be included in the search. But all it's ancestor nodes will be included
10
- *
10
+ *
11
11
  * @param nodes Input tree data
12
12
  * @param trimmedSearchTerm search term
13
13
  * @param searchKeys search key
14
14
  * @returns filtered tree data
15
15
  */
16
- export function getFilteredTreeData(
17
- nodes: TreeNode[],
16
+ export function getFilteredTreeData<ID>(
17
+ nodes: TreeNode<ID>[],
18
18
  trimmedSearchTerm: string,
19
19
  searchKeys: string[]
20
- ): TreeNode[] {
21
- let filtered: TreeNode[] = [];
20
+ ): TreeNode<ID>[] {
21
+ let filtered: TreeNode<ID>[] = [];
22
22
 
23
23
  for (let node of nodes) {
24
24
  const isSearchTermInNode = doesNodeContainSearchTerm(
@@ -32,7 +32,7 @@ export function getFilteredTreeData(
32
32
  filtered.push(node);
33
33
  } else if (node.children) {
34
34
  // If node does not match, check its children and include them if they match
35
- const childMatches = getFilteredTreeData(
35
+ const childMatches = getFilteredTreeData<ID>(
36
36
  node.children,
37
37
  trimmedSearchTerm,
38
38
  searchKeys
@@ -51,7 +51,7 @@ export function getFilteredTreeData(
51
51
  /**
52
52
  * Checks if a given tree node contains a specific search term in any of its specified keys.
53
53
  *
54
- * This function will check each of the specified keys in the tree node, convert the key's value to a string,
54
+ * This function will check each of the specified keys in the tree node, convert the key's value to a string,
55
55
  * and check if it includes the search term.
56
56
  *
57
57
  * @param node - The tree node to search through.
@@ -59,8 +59,8 @@ export function getFilteredTreeData(
59
59
  * @param searchKeys - The keys in the tree node to search in.
60
60
  * @returns True if the search term is found in any of the specified keys, false otherwise.
61
61
  */
62
- function doesNodeContainSearchTerm(
63
- node: TreeNode,
62
+ function doesNodeContainSearchTerm<ID>(
63
+ node: TreeNode<ID>,
64
64
  searchTerm: string,
65
65
  searchKeys: string[]
66
66
  ): boolean {
@@ -69,7 +69,7 @@ function doesNodeContainSearchTerm(
69
69
  // Get the value of the key in the tree node
70
70
  const nodeValue = node[key];
71
71
  // Check if the string representation of the key's value includes the search term
72
- // If the value is undefined or null, `nodeValue?.toString()` will return undefined,
72
+ // If the value is undefined or null, `nodeValue?.toString()` will return undefined,
73
73
  // and the call to `toLowerCase().includes(searchTerm)` will return false.
74
74
  return (nodeValue?.toString().toLowerCase().includes(searchTerm));
75
75
  });
@@ -4,7 +4,7 @@ import { toggleCheckboxes } from "./toggleCheckbox.helper";
4
4
 
5
5
  /**
6
6
  * Selects all nodes that are currently visible due to the applied filter.
7
- *
7
+ *
8
8
  * If there is no search text, then it selects all nodes; otherwise, it selects all visible nodes.
9
9
  */
10
10
  export function selectAllFiltered(storeId: string) {
@@ -22,7 +22,7 @@ export function selectAllFiltered(storeId: string) {
22
22
 
23
23
  /**
24
24
  * Unselects all nodes that are currently visible due to the applied filter.
25
- *
25
+ *
26
26
  * If there is no search text, then it unselects all nodes; otherwise, it unselects all visible nodes.
27
27
  */
28
28
  export function unselectAllFiltered(storeId: string) {
@@ -40,7 +40,7 @@ export function unselectAllFiltered(storeId: string) {
40
40
 
41
41
  /**
42
42
  * Selects all nodes in the tree.
43
- *
43
+ *
44
44
  * This function selects all nodes by adding all node ids to the checked set and clearing the indeterminate set.
45
45
  */
46
46
  export function selectAll(storeId: string) {
@@ -61,7 +61,7 @@ export function selectAll(storeId: string) {
61
61
 
62
62
  /**
63
63
  * Unselects all nodes in the tree.
64
- *
64
+ *
65
65
  * This function unselects all nodes by clearing both the checked and indeterminate sets.
66
66
  */
67
67
  export function unselectAll(storeId: string) {
@@ -75,16 +75,16 @@ export function unselectAll(storeId: string) {
75
75
 
76
76
  /**
77
77
  * Get the ids of the innermost children in the tree
78
- *
78
+ *
79
79
  * @param filteredTreeNodes - The filtered tree data
80
80
  * @returns - array of ids of the inner most children only
81
81
  */
82
- export function getInnerMostChildrenIdsInTree(
83
- filteredTreeNodes: TreeNode[]
84
- ): string[] {
85
- const allLeafIds: string[] = [];
82
+ export function getInnerMostChildrenIdsInTree<ID>(
83
+ filteredTreeNodes: TreeNode<ID>[]
84
+ ): ID[] {
85
+ const allLeafIds: ID[] = [];
86
86
 
87
- const getLeafNodes = (_nodes: TreeNode[]) => {
87
+ const getLeafNodes = (_nodes: TreeNode<ID>[]) => {
88
88
  for (let node of _nodes) {
89
89
  if (node.children) {
90
90
  getLeafNodes(node.children);
@@ -97,4 +97,4 @@ export function getInnerMostChildrenIdsInTree(
97
97
  getLeafNodes(filteredTreeNodes);
98
98
 
99
99
  return allLeafIds;
100
- }
100
+ }
@@ -7,12 +7,12 @@ import { getTreeViewStore } from "../store/treeView.store";
7
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
- export function toggleCheckboxes(
10
+ export function toggleCheckboxes<ID>(
11
11
  storeId: string,
12
- ids: string[],
12
+ ids: ID[],
13
13
  forceCheck?: boolean
14
14
  ) {
15
- const treeViewStore = getTreeViewStore(storeId);
15
+ const treeViewStore = getTreeViewStore<ID>(storeId);
16
16
  const {
17
17
  checked,
18
18
  updateChecked,
@@ -32,10 +32,10 @@ export function toggleCheckboxes(
32
32
  const tempIndeterminate = new Set(indeterminate);
33
33
 
34
34
  // Keep track of nodes that have been toggled or affected.
35
- const affectedNodes = new Set<string>();
35
+ const affectedNodes = new Set<ID>();
36
36
 
37
37
  // Memoization maps for node depths.
38
- const nodeDepths = new Map<string, number>();
38
+ const nodeDepths = new Map<ID, number>();
39
39
 
40
40
  // Step 1: Toggle the clicked nodes and their children without updating parents yet.
41
41
  ids.forEach((id) => {
@@ -66,11 +66,11 @@ export function toggleCheckboxes(
66
66
  });
67
67
 
68
68
  // Step 2: Collect all affected parent nodes.
69
- const nodesToUpdate = new Set<string>();
69
+ const nodesToUpdate = new Set<ID>();
70
70
 
71
71
  if (toParents) {
72
72
  affectedNodes.forEach((id) => {
73
- let currentNodeId: string | undefined = id;
73
+ let currentNodeId: ID | undefined = id;
74
74
  while (currentNodeId) {
75
75
  const parentNodeId = childToParentMap.get(currentNodeId);
76
76
  if (parentNodeId) {
@@ -100,7 +100,7 @@ export function toggleCheckboxes(
100
100
  * @param rootId - The ID of the root node to start updating from.
101
101
  * @param childrenChecked - The desired checked state for children.
102
102
  */
103
- function updateChildrenIteratively(rootId: string, childrenChecked: boolean) {
103
+ function updateChildrenIteratively(rootId: ID, childrenChecked: boolean) {
104
104
  const stack = [rootId];
105
105
 
106
106
  while (stack.length > 0) {
@@ -130,13 +130,13 @@ export function toggleCheckboxes(
130
130
  * @param nodeId - The ID of the node to get the depth for.
131
131
  * @returns The depth of the node.
132
132
  */
133
- function getNodeDepth(nodeId: string): number {
133
+ function getNodeDepth(nodeId: ID): number {
134
134
  if (nodeDepths.has(nodeId)) {
135
135
  return nodeDepths.get(nodeId)!;
136
136
  }
137
137
 
138
138
  let depth = 0;
139
- let currentNodeId: string | undefined = nodeId;
139
+ let currentNodeId: ID | undefined = nodeId;
140
140
  while (currentNodeId) {
141
141
  const parentNodeId = childToParentMap.get(currentNodeId);
142
142
  if (parentNodeId) {
@@ -155,7 +155,7 @@ export function toggleCheckboxes(
155
155
  * Function to update the state of a node based on its children's states.
156
156
  * @param nodeId - The ID of the node to update.
157
157
  */
158
- function updateNodeState(nodeId: string) {
158
+ function updateNodeState(nodeId: ID) {
159
159
  const node = nodeMap.get(nodeId);
160
160
  if (!node || !node.children || node.children.length === 0) {
161
161
  // Leaf nodes are already updated.
@@ -6,21 +6,21 @@ import {
6
6
  /**
7
7
  * Initialize the maps for tracking tree nodes and their parent-child relationships.
8
8
  *
9
- * This function is intended to be called once, during component initialization,
9
+ * This function is intended to be called once, during component initialization,
10
10
  * with the initial tree data and any preselected node IDs.
11
11
  *
12
12
  * @param initialData - An array of TreeNode objects that represent the initial tree structure.
13
13
  * @param preselectedIds - An optional array of TreeNode IDs that should be preselected.
14
14
  */
15
- export function initializeNodeMaps(storeId: string, initialData: TreeNode[]) {
16
- const treeViewStore = getTreeViewStore(storeId);
15
+ export function initializeNodeMaps<ID>(storeId: string, initialData: TreeNode<ID>[]) {
16
+ const treeViewStore = getTreeViewStore<ID>(storeId);
17
17
  const {
18
18
  updateNodeMap,
19
19
  updateChildToParentMap
20
20
  } = treeViewStore.getState();
21
21
 
22
- const tempNodeMap: Map<string, TreeNode> = new Map();
23
- const tempChildToParentMap: Map<string, string> = new Map();
22
+ const tempNodeMap: Map<ID, TreeNode<ID>> = new Map();
23
+ const tempChildToParentMap: Map<ID, ID> = new Map();
24
24
 
25
25
  /**
26
26
  * Recursively processes nodes, adding them to the nodeMap and childToParentMap.
@@ -29,8 +29,8 @@ export function initializeNodeMaps(storeId: string, initialData: TreeNode[]) {
29
29
  * @param parentId - The ID of the parent node, if applicable.
30
30
  */
31
31
  const processNodes = (
32
- nodes: TreeNode[],
33
- parentId: string | null = null
32
+ nodes: TreeNode<ID>[],
33
+ parentId: ID | null = null
34
34
  ) => {
35
35
  nodes.forEach((node) => {
36
36
  // Each node is added to the nodeMap with its ID as the key
@@ -47,4 +47,4 @@ export function initializeNodeMaps(storeId: string, initialData: TreeNode[]) {
47
47
 
48
48
  updateNodeMap(tempNodeMap);
49
49
  updateChildToParentMap(tempChildToParentMap);
50
- }
50
+ }
@@ -1,30 +1,30 @@
1
1
  import type { SelectionPropagation, TreeNode } from "src/types/treeView.types";
2
2
  import { create, StoreApi, UseBoundStore } from 'zustand';
3
3
 
4
- export type TreeViewState = {
4
+ export type TreeViewState<ID> = {
5
5
  // Store ids of checked tree nodes
6
- checked: Set<string>;
7
- updateChecked: (checked: Set<string>) => void;
6
+ checked: Set<ID>;
7
+ updateChecked: (checked: Set<ID>) => void;
8
8
 
9
9
  // Store ids of indeterminate state nodes
10
- indeterminate: Set<string>;
11
- updateIndeterminate: (indeterminate: Set<string>) => void;
10
+ indeterminate: Set<ID>;
11
+ updateIndeterminate: (indeterminate: Set<ID>) => void;
12
12
 
13
13
  // Store ids of expanded parent nodes
14
- expanded: Set<string>;
15
- updateExpanded: (expanded: Set<string>) => void;
14
+ expanded: Set<ID>;
15
+ updateExpanded: (expanded: Set<ID>) => void;
16
16
 
17
17
  // Store initial tree view data exactly as passed by the consumer
18
- initialTreeViewData: TreeNode[];
19
- updateInitialTreeViewData: (initialTreeViewData: TreeNode[]) => void;
18
+ initialTreeViewData: TreeNode<ID>[];
19
+ updateInitialTreeViewData: (initialTreeViewData: TreeNode<ID>[]) => void;
20
20
 
21
21
  // Map to store the id to the tree node map
22
- nodeMap: Map<string, TreeNode>;
23
- updateNodeMap: (nodeMap: Map<string, TreeNode>) => void;
22
+ nodeMap: Map<ID, TreeNode<ID>>;
23
+ updateNodeMap: (nodeMap: Map<ID, TreeNode<ID>>) => void;
24
24
 
25
25
  // Map to store child id to parent id map
26
- childToParentMap: Map<string, string>;
27
- updateChildToParentMap: (childToParentMap: Map<string, string>) => void;
26
+ childToParentMap: Map<ID, ID>;
27
+ updateChildToParentMap: (childToParentMap: Map<ID, ID>) => void;
28
28
 
29
29
  // Search text state
30
30
  searchText: string;
@@ -35,8 +35,8 @@ export type TreeViewState = {
35
35
  updateSearchKeys: (searchKeys: string[]) => void;
36
36
 
37
37
  // To store inner most children ids - required to un/select all filtered-only nodes
38
- innerMostChildrenIds: string[];
39
- updateInnerMostChildrenIds: (innerMostChildrenIds: string[]) => void;
38
+ innerMostChildrenIds: ID[];
39
+ updateInnerMostChildrenIds: (innerMostChildrenIds: ID[]) => void;
40
40
 
41
41
  selectionPropagation: SelectionPropagation;
42
42
  setSelectionPropagation: (
@@ -48,30 +48,32 @@ export type TreeViewState = {
48
48
  };
49
49
 
50
50
  // Map to store individual tree view stores by id
51
- const treeViewStores = new Map<string, UseBoundStore<StoreApi<TreeViewState>>>();
51
+ const treeViewStores = new Map<string, UseBoundStore<StoreApi<TreeViewState<unknown>>>>();
52
+ // a function that returns a strongly typed version of `treeViewStores`
53
+ const typedStore: <ID>() => Map<string, UseBoundStore<StoreApi<TreeViewState<ID>>>> = <ID>() => treeViewStores as Map<string, UseBoundStore<StoreApi<TreeViewState<ID>>>>;
52
54
 
53
- export function getTreeViewStore(id: string): UseBoundStore<StoreApi<TreeViewState>> {
54
- if (!treeViewStores.has(id)) {
55
- const store = create<TreeViewState>((set) => ({
55
+ export function getTreeViewStore<ID>(id: string): UseBoundStore<StoreApi<TreeViewState<ID>>> {
56
+ if (!typedStore<ID>().has(id)) {
57
+ const store = create<TreeViewState<ID>>((set) => ({
56
58
  checked: new Set(),
57
- updateChecked: (checked: Set<string>) => set({ checked }),
59
+ updateChecked: (checked: Set<ID>) => set({ checked }),
58
60
 
59
61
  indeterminate: new Set(),
60
- updateIndeterminate: (indeterminate: Set<string>) => set({ indeterminate }),
62
+ updateIndeterminate: (indeterminate: Set<ID>) => set({ indeterminate }),
61
63
 
62
- expanded: new Set<string>(),
63
- updateExpanded: (expanded: Set<string>) => set({ expanded }),
64
+ expanded: new Set<ID>(),
65
+ updateExpanded: (expanded: Set<ID>) => set({ expanded }),
64
66
 
65
67
  initialTreeViewData: [],
66
- updateInitialTreeViewData: (initialTreeViewData: TreeNode[]) => set({
68
+ updateInitialTreeViewData: (initialTreeViewData: TreeNode<ID>[]) => set({
67
69
  initialTreeViewData
68
70
  }),
69
71
 
70
- nodeMap: new Map<string, TreeNode>(),
71
- updateNodeMap: (nodeMap: Map<string, TreeNode>) => set({ nodeMap }),
72
+ nodeMap: new Map<ID, TreeNode<ID>>(),
73
+ updateNodeMap: (nodeMap: Map<ID, TreeNode<ID>>) => set({ nodeMap }),
72
74
 
73
- childToParentMap: new Map<string, string>(),
74
- updateChildToParentMap: (childToParentMap: Map<string, string>) => set({
75
+ childToParentMap: new Map<ID, ID>(),
76
+ updateChildToParentMap: (childToParentMap: Map<ID, ID>) => set({
75
77
  childToParentMap
76
78
  }),
77
79
 
@@ -82,7 +84,7 @@ export function getTreeViewStore(id: string): UseBoundStore<StoreApi<TreeViewSta
82
84
  updateSearchKeys: (searchKeys: string[]) => set({ searchKeys }),
83
85
 
84
86
  innerMostChildrenIds: [],
85
- updateInnerMostChildrenIds: (innerMostChildrenIds: string[]) => set({
87
+ updateInnerMostChildrenIds: (innerMostChildrenIds: ID[]) => set({
86
88
  innerMostChildrenIds
87
89
  }),
88
90
 
@@ -99,10 +101,10 @@ export function getTreeViewStore(id: string): UseBoundStore<StoreApi<TreeViewSta
99
101
  set({
100
102
  checked: new Set(),
101
103
  indeterminate: new Set(),
102
- expanded: new Set<string>(),
104
+ expanded: new Set<ID>(),
103
105
  initialTreeViewData: [],
104
- nodeMap: new Map<string, TreeNode>(),
105
- childToParentMap: new Map<string, string>(),
106
+ nodeMap: new Map<ID, TreeNode<ID>>(),
107
+ childToParentMap: new Map<ID, ID>(),
106
108
  searchText: "",
107
109
  searchKeys: [""],
108
110
  innerMostChildrenIds: [],
@@ -110,11 +112,11 @@ export function getTreeViewStore(id: string): UseBoundStore<StoreApi<TreeViewSta
110
112
  }),
111
113
  }));
112
114
 
113
- treeViewStores.set(id, store);
115
+ typedStore<ID>().set(id, store);
114
116
  }
115
- return treeViewStores.get(id)!;
117
+ return typedStore<ID>().get(id)!;
116
118
  }
117
119
 
118
- export function useTreeViewStore(id: string) {
119
- return getTreeViewStore(id);
120
- }
120
+ export function useTreeViewStore<ID = string>(id: string) {
121
+ return getTreeViewStore<ID>(id);
122
+ }
@@ -15,14 +15,14 @@ export interface ExpandIconProps {
15
15
  isExpanded: boolean;
16
16
  }
17
17
 
18
- export interface TreeNode {
19
- id: string;
18
+ export interface TreeNode<ID = string> {
19
+ id: ID;
20
20
  name: string;
21
- children?: TreeNode[];
21
+ children?: TreeNode<ID>[];
22
22
  [key: string]: any;
23
23
  }
24
24
 
25
- export interface __FlattenedTreeNode__ extends TreeNode {
25
+ export interface __FlattenedTreeNode__<ID = string> extends TreeNode<ID> {
26
26
  level?: number;
27
27
  }
28
28
 
@@ -33,8 +33,8 @@ export type TreeFlatListProps<ItemT = any> = Omit<
33
33
  | "renderItem"
34
34
  >;
35
35
 
36
- export interface NodeRowProps {
37
- node: TreeNode;
36
+ export interface NodeRowProps<ID = string> {
37
+ node: TreeNode<ID>;
38
38
  level: number;
39
39
 
40
40
  checkedValue: CheckboxValueType;
@@ -44,7 +44,7 @@ export interface NodeRowProps {
44
44
  onExpand: () => void;
45
45
  }
46
46
 
47
- export interface TreeItemCustomizations {
47
+ export interface TreeItemCustomizations<ID> {
48
48
  checkBoxViewStyleProps?: BuiltInCheckBoxViewStyleProps;
49
49
 
50
50
  indentationMultiplier?: number;
@@ -53,29 +53,29 @@ export interface TreeItemCustomizations {
53
53
  ExpandCollapseIconComponent?: React.ComponentType<ExpandIconProps>;
54
54
  ExpandCollapseTouchableComponent?: React.ComponentType<TouchableOpacityProps>;
55
55
 
56
- CustomNodeRowComponent?: React.ComponentType<NodeRowProps>;
56
+ CustomNodeRowComponent?: React.ComponentType<NodeRowProps<ID>>;
57
57
  }
58
58
 
59
- export interface NodeProps extends TreeItemCustomizations {
60
- node: __FlattenedTreeNode__;
59
+ export interface NodeProps<ID> extends TreeItemCustomizations<ID> {
60
+ node: __FlattenedTreeNode__<ID>;
61
61
  level: number;
62
62
  storeId: string;
63
63
  }
64
64
 
65
- export interface NodeListProps extends TreeItemCustomizations {
65
+ export interface NodeListProps<ID> extends TreeItemCustomizations<ID> {
66
66
  treeFlashListProps?: TreeFlatListProps;
67
67
  storeId: string;
68
68
  }
69
69
 
70
- export interface TreeViewProps extends Omit<NodeListProps, "storeId"> {
71
- data: TreeNode[];
70
+ export interface TreeViewProps<ID = string> extends Omit<NodeListProps<ID>, "storeId"> {
71
+ data: TreeNode<ID>[];
72
72
 
73
- onCheck?: (checkedIds: string[], indeterminateIds: string[]) => void;
74
- onExpand?: (expandedIds: string[]) => void;
73
+ onCheck?: (checkedIds: ID[], indeterminateIds: ID[]) => void;
74
+ onExpand?: (expandedIds: ID[]) => void;
75
75
 
76
- preselectedIds?: string[];
76
+ preselectedIds?: ID[];
77
77
 
78
- preExpandedIds?: string[];
78
+ preExpandedIds?: ID[];
79
79
 
80
80
  selectionPropagation?: SelectionPropagation;
81
81
  }
@@ -103,7 +103,7 @@ export type BuiltInCheckBoxViewProps =
103
103
  CheckBoxViewProps
104
104
  & BuiltInCheckBoxViewStyleProps;
105
105
 
106
- export interface TreeViewRef {
106
+ export interface TreeViewRef<ID = string> {
107
107
  selectAll: () => void;
108
108
  unselectAll: () => void;
109
109
 
@@ -113,11 +113,11 @@ export interface TreeViewRef {
113
113
  expandAll: () => void;
114
114
  collapseAll: () => void;
115
115
 
116
- expandNodes: (ids: string[]) => void;
117
- collapseNodes: (ids: string[]) => void;
116
+ expandNodes: (ids: ID[]) => void;
117
+ collapseNodes: (ids: ID[]) => void;
118
118
 
119
- selectNodes: (ids: string[]) => void;
120
- unselectNodes: (ids: string[]) => void;
119
+ selectNodes: (ids: ID[]) => void;
120
+ unselectNodes: (ids: ID[]) => void;
121
121
 
122
122
  setSearchText: (searchText: string, searchKeys?: string[]) => void;
123
123
  }
@@ -125,4 +125,4 @@ export interface TreeViewRef {
125
125
  export interface SelectionPropagation {
126
126
  toChildren?: boolean;
127
127
  toParents?: boolean;
128
- }
128
+ }
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+
3
+ /** wrapper for React.memo that works with generic components. */
4
+ export const typedMemo: <T>(c: T) => T = React.memo;