react-native-tree-multi-select 3.0.0-beta.3 → 3.0.0-beta.5

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 (96) hide show
  1. package/README.md +100 -30
  2. package/lib/module/TreeView.js +36 -31
  3. package/lib/module/TreeView.js.map +1 -1
  4. package/lib/module/components/CheckboxView.js +8 -4
  5. package/lib/module/components/CheckboxView.js.map +1 -1
  6. package/lib/module/components/CustomExpandCollapseIcon.js +2 -2
  7. package/lib/module/components/CustomExpandCollapseIcon.js.map +1 -1
  8. package/lib/module/components/DragOverlay.js +17 -5
  9. package/lib/module/components/DragOverlay.js.map +1 -1
  10. package/lib/module/components/DropIndicator.js +2 -2
  11. package/lib/module/components/DropIndicator.js.map +1 -1
  12. package/lib/module/components/NodeList.js +78 -58
  13. package/lib/module/components/NodeList.js.map +1 -1
  14. package/lib/module/constants/treeView.constants.js +3 -0
  15. package/lib/module/constants/treeView.constants.js.map +1 -1
  16. package/lib/module/helpers/expandCollapse.helper.js.map +1 -1
  17. package/lib/module/helpers/moveTreeNode.helper.js +30 -0
  18. package/lib/module/helpers/moveTreeNode.helper.js.map +1 -1
  19. package/lib/module/helpers/selectAll.helper.js.map +1 -1
  20. package/lib/module/helpers/toggleCheckbox.helper.js +43 -60
  21. package/lib/module/helpers/toggleCheckbox.helper.js.map +1 -1
  22. package/lib/module/hooks/useDragDrop.js +146 -65
  23. package/lib/module/hooks/useDragDrop.js.map +1 -1
  24. package/lib/module/{handlers/ScrollToNodeHandler.js → hooks/useScrollToNode.js} +27 -26
  25. package/lib/module/hooks/useScrollToNode.js.map +1 -0
  26. package/lib/module/index.js +1 -0
  27. package/lib/module/index.js.map +1 -1
  28. package/lib/module/jest.setup.js +14 -1
  29. package/lib/module/jest.setup.js.map +1 -1
  30. package/lib/module/store/treeView.store.js +3 -0
  31. package/lib/module/store/treeView.store.js.map +1 -1
  32. package/lib/module/utils/typedMemo.js +3 -3
  33. package/lib/module/utils/typedMemo.js.map +1 -1
  34. package/lib/module/utils/useDeepCompareEffect.js +5 -5
  35. package/lib/module/utils/useDeepCompareEffect.js.map +1 -1
  36. package/lib/typescript/src/TreeView.d.ts +3 -3
  37. package/lib/typescript/src/TreeView.d.ts.map +1 -1
  38. package/lib/typescript/src/components/CheckboxView.d.ts +1 -2
  39. package/lib/typescript/src/components/CheckboxView.d.ts.map +1 -1
  40. package/lib/typescript/src/components/CustomExpandCollapseIcon.d.ts +1 -2
  41. package/lib/typescript/src/components/CustomExpandCollapseIcon.d.ts.map +1 -1
  42. package/lib/typescript/src/components/DragOverlay.d.ts +1 -0
  43. package/lib/typescript/src/components/DragOverlay.d.ts.map +1 -1
  44. package/lib/typescript/src/components/DropIndicator.d.ts +1 -2
  45. package/lib/typescript/src/components/DropIndicator.d.ts.map +1 -1
  46. package/lib/typescript/src/components/NodeList.d.ts.map +1 -1
  47. package/lib/typescript/src/constants/treeView.constants.d.ts +2 -0
  48. package/lib/typescript/src/constants/treeView.constants.d.ts.map +1 -1
  49. package/lib/typescript/src/helpers/expandCollapse.helper.d.ts +2 -2
  50. package/lib/typescript/src/helpers/expandCollapse.helper.d.ts.map +1 -1
  51. package/lib/typescript/src/helpers/moveTreeNode.helper.d.ts.map +1 -1
  52. package/lib/typescript/src/helpers/selectAll.helper.d.ts +4 -4
  53. package/lib/typescript/src/helpers/selectAll.helper.d.ts.map +1 -1
  54. package/lib/typescript/src/helpers/toggleCheckbox.helper.d.ts +3 -0
  55. package/lib/typescript/src/helpers/toggleCheckbox.helper.d.ts.map +1 -1
  56. package/lib/typescript/src/hooks/useDragDrop.d.ts +24 -8
  57. package/lib/typescript/src/hooks/useDragDrop.d.ts.map +1 -1
  58. package/lib/typescript/src/{handlers/ScrollToNodeHandler.d.ts → hooks/useScrollToNode.d.ts} +13 -15
  59. package/lib/typescript/src/hooks/useScrollToNode.d.ts.map +1 -0
  60. package/lib/typescript/src/index.d.ts +4 -3
  61. package/lib/typescript/src/index.d.ts.map +1 -1
  62. package/lib/typescript/src/jest.setup.d.ts +1 -1
  63. package/lib/typescript/src/jest.setup.d.ts.map +1 -1
  64. package/lib/typescript/src/store/treeView.store.d.ts +2 -1
  65. package/lib/typescript/src/store/treeView.store.d.ts.map +1 -1
  66. package/lib/typescript/src/types/dragDrop.types.d.ts +10 -0
  67. package/lib/typescript/src/types/dragDrop.types.d.ts.map +1 -1
  68. package/lib/typescript/src/types/treeView.types.d.ts +79 -41
  69. package/lib/typescript/src/types/treeView.types.d.ts.map +1 -1
  70. package/lib/typescript/src/utils/typedMemo.d.ts +1 -1
  71. package/lib/typescript/src/utils/typedMemo.d.ts.map +1 -1
  72. package/lib/typescript/src/utils/useDeepCompareEffect.d.ts +2 -2
  73. package/lib/typescript/src/utils/useDeepCompareEffect.d.ts.map +1 -1
  74. package/package.json +32 -15
  75. package/src/TreeView.tsx +57 -35
  76. package/src/components/CheckboxView.tsx +7 -4
  77. package/src/components/CustomExpandCollapseIcon.tsx +2 -2
  78. package/src/components/DragOverlay.tsx +19 -6
  79. package/src/components/DropIndicator.tsx +2 -2
  80. package/src/components/NodeList.tsx +87 -60
  81. package/src/constants/treeView.constants.ts +4 -1
  82. package/src/helpers/expandCollapse.helper.ts +5 -5
  83. package/src/helpers/moveTreeNode.helper.ts +33 -0
  84. package/src/helpers/selectAll.helper.ts +10 -10
  85. package/src/helpers/toggleCheckbox.helper.ts +56 -68
  86. package/src/hooks/useDragDrop.ts +190 -80
  87. package/src/{handlers/ScrollToNodeHandler.tsx → hooks/useScrollToNode.ts} +48 -45
  88. package/src/index.tsx +11 -0
  89. package/src/jest.setup.ts +14 -1
  90. package/src/store/treeView.store.ts +6 -1
  91. package/src/types/dragDrop.types.ts +12 -0
  92. package/src/types/treeView.types.ts +87 -43
  93. package/src/utils/typedMemo.ts +3 -3
  94. package/src/utils/useDeepCompareEffect.ts +13 -7
  95. package/lib/module/handlers/ScrollToNodeHandler.js.map +0 -1
  96. package/lib/typescript/src/handlers/ScrollToNodeHandler.d.ts.map +0 -1
@@ -1,7 +1,7 @@
1
1
  /**
2
- * ScrollToNodeHandler Component
2
+ * useScrollToNode Hook
3
3
  *
4
- * This component provides an imperative handle to scroll to a specified node within a tree view.
4
+ * Provides an imperative handle to scroll to a specified node within a tree view.
5
5
  * The scrolling action is orchestrated via a two-step "milestone" mechanism that ensures the target
6
6
  * node is both expanded in the tree and that the rendered list reflects this expansion before the scroll
7
7
  * is performed.
@@ -32,22 +32,23 @@
32
32
  * in the UI, thus preventing issues with attempting to scroll to an element that does not exist yet.
33
33
  */
34
34
 
35
- import React from "react";
35
+ import {
36
+ useEffect,
37
+ useImperativeHandle,
38
+ useLayoutEffect,
39
+ useRef,
40
+ useState,
41
+ type Dispatch,
42
+ type MutableRefObject,
43
+ type RefObject,
44
+ type SetStateAction,
45
+ } from "react";
36
46
  import { expandNodes } from "../helpers/expandCollapse.helper";
37
47
  import { useTreeViewStore } from "../store/treeView.store";
38
48
  import { useShallow } from "zustand/react/shallow";
39
49
  import { type __FlattenedTreeNode__ } from "../types/treeView.types";
40
- import { typedMemo } from "../utils/typedMemo";
41
50
  import { fastIsEqual } from "fast-is-equal";
42
51
 
43
- interface Props<ID> {
44
- storeId: string;
45
- flashListRef: React.MutableRefObject<any>;
46
- flattenedFilteredNodes: __FlattenedTreeNode__<ID>[];
47
- setInitialScrollIndex: React.Dispatch<React.SetStateAction<number>>;
48
- initialScrollNodeID: ID | undefined;
49
- }
50
-
51
52
  export interface ScrollToNodeParams<ID> {
52
53
  nodeId: ID;
53
54
  expandScrolledNode?: boolean;
@@ -57,27 +58,34 @@ export interface ScrollToNodeParams<ID> {
57
58
  viewPosition?: number;
58
59
  }
59
60
 
61
+ export interface ScrollToNodeHandlerRef<ID> {
62
+ scrollToNodeID: (params: ScrollToNodeParams<ID>) => void;
63
+ }
64
+
60
65
  // Enum representing the two milestones needed before scrolling
61
66
  enum ExpandQueueAction {
62
67
  EXPANDED,
63
68
  RENDERED,
64
69
  }
65
70
 
66
- export interface ScrollToNodeHandlerRef<ID> {
67
- scrollToNodeID: (params: ScrollToNodeParams<ID>) => void;
71
+ interface UseScrollToNodeParams<ID> {
72
+ storeId: string;
73
+ scrollToNodeHandlerRef: RefObject<ScrollToNodeHandlerRef<ID>>;
74
+ flashListRef: MutableRefObject<any>;
75
+ flattenedFilteredNodes: __FlattenedTreeNode__<ID>[];
76
+ setInitialScrollIndex: Dispatch<SetStateAction<number>>;
77
+ initialScrollNodeID: ID | undefined;
68
78
  }
69
79
 
70
- function _innerScrollToNodeHandler<ID>(
71
- props: Props<ID>,
72
- ref: React.ForwardedRef<ScrollToNodeHandlerRef<ID>>
73
- ) {
80
+ export function useScrollToNode<ID>(params: UseScrollToNodeParams<ID>) {
74
81
  const {
75
82
  storeId,
83
+ scrollToNodeHandlerRef,
76
84
  flashListRef,
77
85
  flattenedFilteredNodes,
78
86
  setInitialScrollIndex,
79
87
  initialScrollNodeID
80
- } = props;
88
+ } = params;
81
89
 
82
90
  const { expanded, childToParentMap } = useTreeViewStore<ID>(storeId)(useShallow(
83
91
  state => ({
@@ -86,9 +94,16 @@ function _innerScrollToNodeHandler<ID>(
86
94
  })
87
95
  ));
88
96
 
89
- React.useImperativeHandle(ref, () => ({
90
- scrollToNodeID: (params: ScrollToNodeParams<ID>) => {
91
- queuedScrollToNodeParams.current = params;
97
+ // Ref to store the scroll parameters for the queued action.
98
+ const queuedScrollToNodeParams = useRef<ScrollToNodeParams<ID> | null>(null);
99
+
100
+ // State to track progression: first the expansion is triggered, then the list is rendered.
101
+ const [expandAndScrollToNodeQueue, setExpandAndScrollToNodeQueue]
102
+ = useState<ExpandQueueAction[]>([]);
103
+
104
+ useImperativeHandle(scrollToNodeHandlerRef, () => ({
105
+ scrollToNodeID: (scrollParams: ScrollToNodeParams<ID>) => {
106
+ queuedScrollToNodeParams.current = scrollParams;
92
107
  // Mark that expansion is initiated.
93
108
  setExpandAndScrollToNodeQueue([ExpandQueueAction.EXPANDED]);
94
109
  // Trigger expansion logic (this may update the store and subsequently re-render the list).
@@ -100,18 +115,11 @@ function _innerScrollToNodeHandler<ID>(
100
115
  }
101
116
  }), [storeId]);
102
117
 
103
- // Ref to store the scroll parameters for the queued action.
104
- const queuedScrollToNodeParams = React.useRef<ScrollToNodeParams<ID> | null>(null);
105
-
106
- // State to track progression: first the expansion is triggered, then the list is rendered.
107
- const [expandAndScrollToNodeQueue, setExpandAndScrollToNodeQueue]
108
- = React.useState<ExpandQueueAction[]>([]);
109
-
110
- const latestFlattenedFilteredNodesRef = React.useRef(flattenedFilteredNodes);
118
+ const latestFlattenedFilteredNodesRef = useRef(flattenedFilteredNodes);
111
119
 
112
120
  /* When the rendered node list changes, update the ref.
113
121
  If an expansion was triggered, mark that the list is now rendered. */
114
- React.useEffect(() => {
122
+ useEffect(() => {
115
123
  setExpandAndScrollToNodeQueue(prevQueue => {
116
124
  if (prevQueue.includes(ExpandQueueAction.EXPANDED)) {
117
125
  latestFlattenedFilteredNodesRef.current = flattenedFilteredNodes;
@@ -127,7 +135,7 @@ function _innerScrollToNodeHandler<ID>(
127
135
 
128
136
  /* Once the target node is expanded and the list is updated (milestones reached),
129
137
  perform the scroll using the latest node list. */
130
- React.useLayoutEffect(() => {
138
+ useLayoutEffect(() => {
131
139
  if (queuedScrollToNodeParams.current === null)
132
140
  return;
133
141
 
@@ -146,12 +154,16 @@ function _innerScrollToNodeHandler<ID>(
146
154
  parentId = childToParentMap.get(queuedScrollToNodeParams.current.nodeId) as ID;
147
155
  }
148
156
 
149
- // Ensure if the parent is expanded before proceeding to scroll to the node
157
+ // Ensure if the parent is expanded before proceeding to scroll to the node.
158
+ // This fires transiently during the milestone system - the layout effect runs
159
+ // before the expansion has propagated to the store, then retries on next render.
160
+ /* istanbul ignore next -- async timing guard: expansion not yet propagated to store */
150
161
  if (parentId && !expanded.has(parentId))
151
162
  return;
152
163
  }
153
164
  // If node is set to expand
154
165
  else {
166
+ /* istanbul ignore next -- async timing guard: node expansion not yet propagated */
155
167
  if (!expanded.has(queuedScrollToNodeParams.current.nodeId))
156
168
  return;
157
169
  }
@@ -177,6 +189,7 @@ function _innerScrollToNodeHandler<ID>(
177
189
  viewPosition
178
190
  });
179
191
  } else {
192
+ /* istanbul ignore next -- __DEV__ is false in test/production */
180
193
  if (__DEV__) {
181
194
  console.info("Cannot find the item of the mentioned id to scroll in the rendered tree view list data!");
182
195
  }
@@ -193,8 +206,8 @@ function _innerScrollToNodeHandler<ID>(
193
206
  ////////////////////////////// Handle Initial Scroll /////////////////////////////
194
207
  /* On first render, if an initial scroll target is provided, determine its index.
195
208
  This is done only once. */
196
- const initialScrollDone = React.useRef(false);
197
- React.useLayoutEffect(() => {
209
+ const initialScrollDone = useRef(false);
210
+ useLayoutEffect(() => {
198
211
  if (initialScrollDone.current) return;
199
212
 
200
213
  const index = flattenedFilteredNodes.findIndex(
@@ -209,14 +222,4 @@ function _innerScrollToNodeHandler<ID>(
209
222
  // eslint-disable-next-line react-hooks/exhaustive-deps
210
223
  }, [flattenedFilteredNodes, initialScrollNodeID]);
211
224
  /////////////////////////////////////////////////////////////////////////////////
212
-
213
- return null;
214
225
  }
215
-
216
- const _ScrollToNodeHandler = React.forwardRef(_innerScrollToNodeHandler) as <ID>(
217
- props: Props<ID> & { ref?: React.ForwardedRef<ScrollToNodeHandlerRef<ID>>; }
218
- ) => ReturnType<typeof _innerScrollToNodeHandler>;
219
-
220
- export const ScrollToNodeHandler = typedMemo<
221
- typeof _ScrollToNodeHandler
222
- >(_ScrollToNodeHandler);
package/src/index.tsx CHANGED
@@ -9,20 +9,26 @@ import type {
9
9
  CheckboxValueType,
10
10
  BuiltInCheckBoxViewStyleProps,
11
11
  SelectionPropagation,
12
+ DragAndDropOptions,
13
+ DropAutoScrollOptions,
12
14
  DragDropCustomizations,
13
15
  DragOverlayStyleProps,
14
16
  DragOverlayComponentProps,
15
17
  DropIndicatorStyleProps,
16
18
  DropIndicatorComponentProps,
19
+ DragHandleProps,
17
20
  } from "./types/treeView.types";
18
21
  import type {
22
+ DragCancelEvent,
19
23
  DragEndEvent,
24
+ DragStartEvent,
20
25
  DropPosition
21
26
  } from "./types/dragDrop.types";
22
27
 
23
28
  export * from "./TreeView";
24
29
  export * from "./components/CheckboxView";
25
30
  export { moveTreeNode } from "./helpers/moveTreeNode.helper";
31
+ export { deleteTreeViewStore } from "./store/treeView.store";
26
32
 
27
33
  export type {
28
34
  TreeNode,
@@ -35,11 +41,16 @@ export type {
35
41
  CheckboxValueType,
36
42
  BuiltInCheckBoxViewStyleProps,
37
43
  SelectionPropagation,
44
+ DragAndDropOptions,
45
+ DropAutoScrollOptions,
46
+ DragCancelEvent,
38
47
  DragEndEvent,
48
+ DragStartEvent,
39
49
  DropPosition,
40
50
  DragDropCustomizations,
41
51
  DragOverlayStyleProps,
42
52
  DragOverlayComponentProps,
43
53
  DropIndicatorStyleProps,
44
54
  DropIndicatorComponentProps,
55
+ DragHandleProps,
45
56
  };
package/src/jest.setup.ts CHANGED
@@ -1 +1,14 @@
1
- import "@testing-library/jest-native/extend-expect";
1
+ import "@testing-library/react-native/extend-expect";
2
+ import { configure } from "@testing-library/react-native";
3
+
4
+ // Skip host component auto-detection which fails in RN 0.78+ jest environment.
5
+ // The type definition doesn't include hostComponentNames yet, but it works at runtime.
6
+ (configure as any)({
7
+ hostComponentNames: {
8
+ text: "Text",
9
+ textInput: "TextInput",
10
+ switch: "RCTSwitch",
11
+ scrollView: "RCTScrollView",
12
+ modal: "Modal",
13
+ },
14
+ });
@@ -1,6 +1,7 @@
1
+ import { create, type StoreApi, type UseBoundStore } from "zustand";
2
+
1
3
  import type { SelectionPropagation, TreeNode } from "../types/treeView.types";
2
4
  import type { DropPosition } from "../types/dragDrop.types";
3
- import { create, type StoreApi, type UseBoundStore } from "zustand";
4
5
 
5
6
  export type TreeViewState<ID> = {
6
7
  // Store ids of checked tree nodes
@@ -153,6 +154,10 @@ export function getTreeViewStore<ID>(id: string): UseBoundStore<StoreApi<TreeVie
153
154
  return typedStore<ID>().get(id)!;
154
155
  }
155
156
 
157
+ export function deleteTreeViewStore(id: string) {
158
+ treeViewStores.delete(id);
159
+ }
160
+
156
161
  export function useTreeViewStore<ID = string>(id: string) {
157
162
  return getTreeViewStore<ID>(id);
158
163
  }
@@ -3,6 +3,18 @@ import type { TreeNode } from "./treeView.types";
3
3
  /** Where a node is dropped relative to the target: as a sibling above/below, or as a child inside */
4
4
  export type DropPosition = "above" | "below" | "inside";
5
5
 
6
+ /** Event payload passed to the onDragStart callback when a drag begins */
7
+ export interface DragStartEvent<ID = string> {
8
+ /** The id of the node being dragged */
9
+ draggedNodeId: ID;
10
+ }
11
+
12
+ /** Event payload passed to the onDragCancel callback when a drag is cancelled without a drop */
13
+ export interface DragCancelEvent<ID = string> {
14
+ /** The id of the node that was being dragged */
15
+ draggedNodeId: ID;
16
+ }
17
+
6
18
  /** Event payload passed to the onDragEnd callback after a successful drop */
7
19
  export interface DragEndEvent<ID = string> {
8
20
  /** The id of the node that was dragged */
@@ -1,3 +1,4 @@
1
+ import { ComponentType, RefObject } from "react";
1
2
  import type {
2
3
  StyleProp,
3
4
  TextProps,
@@ -8,11 +9,11 @@ import type { FlashListProps } from "@shopify/flash-list";
8
9
  import type {
9
10
  ScrollToNodeHandlerRef,
10
11
  ScrollToNodeParams
11
- } from "../handlers/ScrollToNodeHandler";
12
+ } from "../hooks/useScrollToNode";
12
13
  import type {
13
14
  CheckboxProps as _CheckboxProps
14
15
  } from "@futurejj/react-native-checkbox";
15
- import type { DragEndEvent, DropPosition } from "./dragDrop.types";
16
+ import type { DragCancelEvent, DragEndEvent, DragStartEvent, DropPosition } from "./dragDrop.types";
16
17
 
17
18
  /** The tri-state value of a checkbox: checked, unchecked, or indeterminate */
18
19
  export type CheckboxValueType = boolean | "indeterminate";
@@ -66,11 +67,27 @@ export interface NodeRowProps<ID = string> {
66
67
  onExpand: () => void;
67
68
 
68
69
  /** Whether this node is an invalid drop target during a drag operation */
69
- isDragTarget?: boolean;
70
+ isInvalidDropTarget?: boolean;
71
+ /** Whether this node is the current valid drop target */
72
+ isDropTarget?: boolean;
73
+ /** The drop position if this node is the current drop target */
74
+ dropPosition?: DropPosition;
70
75
  /** Whether a drag operation is currently in progress */
71
76
  isDragging?: boolean;
72
77
  /** Whether this node is the one being dragged */
73
78
  isDraggedNode?: boolean;
79
+
80
+ /** Props to spread on a drag handle element. Attach to a specific View to
81
+ * make only that area initiate drag, or spread on the root for whole-row drag.
82
+ * Only present when drag-and-drop is enabled. */
83
+ dragHandleProps?: DragHandleProps;
84
+ }
85
+
86
+ /** Touch handlers to spread on a drag handle element within a custom node row */
87
+ export interface DragHandleProps {
88
+ onTouchStart: (e: any) => void;
89
+ onTouchEnd: () => void;
90
+ onTouchCancel: () => void;
74
91
  }
75
92
 
76
93
  /** Customization options for tree item appearance and behavior */
@@ -82,14 +99,14 @@ export interface TreeItemCustomizations<ID> {
82
99
  indentationMultiplier?: number;
83
100
 
84
101
  /** Custom checkbox component replacing the built-in checkbox */
85
- CheckboxComponent?: React.ComponentType<CheckBoxViewProps>;
102
+ CheckboxComponent?: ComponentType<CheckBoxViewProps>;
86
103
  /** Custom expand/collapse icon component */
87
- ExpandCollapseIconComponent?: React.ComponentType<ExpandIconProps>;
104
+ ExpandCollapseIconComponent?: ComponentType<ExpandIconProps>;
88
105
  /** Custom touchable component wrapping the expand/collapse icon */
89
- ExpandCollapseTouchableComponent?: React.ComponentType<TouchableOpacityProps>;
106
+ ExpandCollapseTouchableComponent?: ComponentType<TouchableOpacityProps>;
90
107
 
91
108
  /** Fully custom node row component replacing the entire built-in row */
92
- CustomNodeRowComponent?: React.ComponentType<NodeRowProps<ID>>;
109
+ CustomNodeRowComponent?: ComponentType<NodeRowProps<ID>>;
93
110
  }
94
111
 
95
112
  /** Internal props for a single node in the list (extends TreeItemCustomizations) */
@@ -116,43 +133,74 @@ export interface NodeProps<ID> extends TreeItemCustomizations<ID> {
116
133
  ) => void;
117
134
  /** Callback when a touch ends on this node */
118
135
  onNodeTouchEnd?: () => void;
119
- /** Long press duration in ms to start drag */
120
- longPressDuration?: number;
121
136
  /** Callback reporting this node's measured height */
122
137
  onItemLayout?: (height: number) => void;
123
138
  /** Customizations for drag-and-drop visuals */
124
139
  dragDropCustomizations?: DragDropCustomizations<ID>;
125
140
  }
126
141
 
127
- /** Props for the NodeList component that renders the flattened tree */
128
- export interface NodeListProps<ID> extends TreeItemCustomizations<ID> {
129
- /** Additional props passed to the underlying FlashList */
130
- treeFlashListProps?: TreeFlatListProps;
131
-
132
- /** Ref for programmatic scroll-to-node functionality */
133
- scrollToNodeHandlerRef: React.RefObject<ScrollToNodeHandlerRef<ID>>;
134
- /** Node ID to scroll to on initial render */
135
- initialScrollNodeID?: ID;
136
-
137
- /** Internal store identifier */
138
- storeId: string;
142
+ /** Options for auto-scrolling to the dropped node after a successful drop.
143
+ * Uses the same scroll parameters as `scrollToNodeID` (minus internally managed fields). */
144
+ export interface DropAutoScrollOptions extends Omit<ScrollToNodeParams<never>, "nodeId" | "expandScrolledNode"> {
145
+ /** Enable auto-scroll to the dropped node. Default: true */
146
+ enabled?: boolean;
147
+ }
139
148
 
140
- /** Enable drag-and-drop reordering */
141
- dragEnabled?: boolean;
142
- /** Callback fired after a node is dropped at a new position */
149
+ /** Configuration options for drag-and-drop reordering */
150
+ export interface DragAndDropOptions<ID = string> {
151
+ /** Enable drag-and-drop reordering. Default: true (when dragAndDrop is provided) */
152
+ enabled?: boolean;
153
+ /** Callback fired when a drag operation begins */
154
+ onDragStart?: (event: DragStartEvent<ID>) => void;
155
+ /** Callback fired after a node is successfully dropped at a new position */
143
156
  onDragEnd?: (event: DragEndEvent<ID>) => void;
157
+ /** Callback fired when a drag is cancelled without a successful drop */
158
+ onDragCancel?: (event: DragCancelEvent<ID>) => void;
144
159
  /** Long press duration in ms to start drag. Default: 400 */
145
160
  longPressDuration?: number;
146
161
  /** Distance from edge (px) to trigger auto-scroll during drag. Default: 60 */
147
162
  autoScrollThreshold?: number;
148
163
  /** Speed multiplier for auto-scroll during drag. Default: 1.0 */
149
164
  autoScrollSpeed?: number;
150
- /** Offset of the dragged overlay from the finger, in item-height units. Default: -1 (one item above finger) */
165
+ /** Offset of the dragged overlay from the finger, in item-height units. Default: -2 (two items above finger) */
151
166
  dragOverlayOffset?: number;
152
167
  /** Delay in ms before auto-expanding a collapsed node during drag hover. Default: 800 */
153
168
  autoExpandDelay?: number;
154
169
  /** Customizations for drag-and-drop visuals (overlay, indicator, opacity) */
155
- dragDropCustomizations?: DragDropCustomizations<ID>;
170
+ customizations?: DragDropCustomizations<ID>;
171
+
172
+ /** Callback to determine if a node can be dropped on a specific target.
173
+ * Return false to grey out the target and suppress the drop indicator. */
174
+ canDrop?: (draggedNode: TreeNode<ID>, targetNode: TreeNode<ID>, position: DropPosition) => boolean;
175
+ /** Maximum nesting depth allowed. Drops that would exceed this depth are suppressed. */
176
+ maxDepth?: number;
177
+ /** Callback to determine if a node can accept children.
178
+ * Return false to suppress the "inside" drop zone for that node. */
179
+ canNodeHaveChildren?: (node: TreeNode<ID>) => boolean;
180
+ /** Callback to determine if a node can be dragged.
181
+ * Return false to prevent dragging this node. Default: all nodes are draggable. */
182
+ canDrag?: (node: TreeNode<ID>) => boolean;
183
+ /** Auto-scroll to the dropped node after a successful drop.
184
+ * Pass `false` to disable, `true` for defaults, or an object to customize.
185
+ * Default: `{ enabled: true, animated: true, viewPosition: 0.5 }` */
186
+ autoScrollToDroppedNode?: boolean | DropAutoScrollOptions;
187
+ }
188
+
189
+ /** Props for the NodeList component that renders the flattened tree */
190
+ export interface NodeListProps<ID> extends TreeItemCustomizations<ID> {
191
+ /** Additional props passed to the underlying FlashList */
192
+ treeFlashListProps?: TreeFlatListProps;
193
+
194
+ /** Ref for programmatic scroll-to-node functionality */
195
+ scrollToNodeHandlerRef: RefObject<ScrollToNodeHandlerRef<ID>>;
196
+ /** Node ID to scroll to on initial render */
197
+ initialScrollNodeID?: ID;
198
+
199
+ /** Internal store identifier */
200
+ storeId: string;
201
+
202
+ /** Drag-and-drop configuration */
203
+ dragAndDrop?: DragAndDropOptions<ID>;
156
204
  }
157
205
 
158
206
  /** Props for the TreeView component */
@@ -176,20 +224,8 @@ export interface TreeViewProps<ID = string> extends Omit<
176
224
  /** Controls whether checking a node propagates to its children and/or parents */
177
225
  selectionPropagation?: SelectionPropagation;
178
226
 
179
- /** Enable drag-and-drop reordering */
180
- dragEnabled?: boolean;
181
- /** Callback fired after a node is dropped at a new position */
182
- onDragEnd?: (event: DragEndEvent<ID>) => void;
183
- /** Long press duration in ms to start drag. Default: 400 */
184
- longPressDuration?: number;
185
- /** Distance from edge (px) to trigger auto-scroll during drag. Default: 60 */
186
- autoScrollThreshold?: number;
187
- /** Speed multiplier for auto-scroll during drag. Default: 1.0 */
188
- autoScrollSpeed?: number;
189
- /** Offset of the dragged overlay from the finger, in item-height units. Default: -1 (one item above finger) */
190
- dragOverlayOffset?: number;
191
- /** Delay in ms before auto-expanding a collapsed node during drag hover. Default: 800 */
192
- autoExpandDelay?: number;
227
+ /** Drag-and-drop configuration */
228
+ dragAndDrop?: DragAndDropOptions<ID>;
193
229
  }
194
230
 
195
231
  type CheckboxProps = Omit<_CheckboxProps, "onPress" | "status">;
@@ -261,6 +297,10 @@ export interface TreeViewRef<ID = string> {
261
297
 
262
298
  /** Get a map of child node IDs to their parent node IDs */
263
299
  getChildToParentMap: () => Map<ID, ID>;
300
+
301
+ /** Programmatically move a node to a new position in the tree.
302
+ * Works like a drag-and-drop but without user interaction. */
303
+ moveNode: (nodeId: ID, targetNodeId: ID, position: DropPosition) => void;
264
304
  }
265
305
 
266
306
  /** Controls how checkbox selection propagates through the tree hierarchy */
@@ -315,16 +355,18 @@ export interface DragOverlayStyleProps {
315
355
 
316
356
  /** Combined drag-and-drop customization props */
317
357
  export interface DragDropCustomizations<ID = string> {
318
- /** Opacity applied to the dragged node and its invalid drop targets. Default: 0.3 */
358
+ /** Opacity applied to the node being dragged. Default: 0.3 */
319
359
  draggedNodeOpacity?: number;
360
+ /** Opacity applied to invalid drop targets during drag. Default: 0.3 */
361
+ invalidTargetOpacity?: number;
320
362
  /** Style props for the built-in drop indicator */
321
363
  dropIndicatorStyleProps?: DropIndicatorStyleProps;
322
364
  /** Style props for the drag overlay (lifted node ghost) */
323
365
  dragOverlayStyleProps?: DragOverlayStyleProps;
324
366
  /** Fully custom drop indicator component - replaces the built-in line/highlight */
325
- CustomDropIndicatorComponent?: React.ComponentType<DropIndicatorComponentProps>;
367
+ CustomDropIndicatorComponent?: ComponentType<DropIndicatorComponentProps>;
326
368
  /** Fully custom drag overlay component - replaces the built-in ghost node */
327
- CustomDragOverlayComponent?: React.ComponentType<DragOverlayComponentProps<ID>>;
369
+ CustomDragOverlayComponent?: ComponentType<DragOverlayComponentProps<ID>>;
328
370
  }
329
371
 
330
372
  /** Props passed to a custom drag overlay component */
@@ -333,4 +375,6 @@ export interface DragOverlayComponentProps<ID = string> {
333
375
  node: __FlattenedTreeNode__<ID>;
334
376
  /** The nesting level of the dragged node */
335
377
  level: number;
378
+ /** The current checkbox value of the dragged node */
379
+ checkedValue: CheckboxValueType;
336
380
  }
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import { memo } from "react";
2
2
 
3
- /** wrapper for React.memo that works with generic components. */
4
- export const typedMemo: <T>(c: T) => T = React.memo;
3
+ /** wrapper for memo that works with generic components. */
4
+ export const typedMemo: <T>(c: T) => T = memo;
@@ -1,4 +1,10 @@
1
- import React from "react";
1
+ import {
2
+ useEffect,
3
+ useMemo,
4
+ useRef,
5
+ type DependencyList,
6
+ type EffectCallback,
7
+ } from "react";
2
8
  import { fastIsEqual } from "fast-is-equal";
3
9
 
4
10
  /**
@@ -9,17 +15,17 @@ import { fastIsEqual } from "fast-is-equal";
9
15
  * @param deps The dependencies array to compare deeply.
10
16
  */
11
17
  export default function useDeepCompareEffect(
12
- effect: React.EffectCallback,
13
- deps: React.DependencyList
18
+ effect: EffectCallback,
19
+ deps: DependencyList
14
20
  ) {
15
21
  // Ref to track if it's the first render
16
- const firstRenderRef = React.useRef<boolean>(true);
22
+ const firstRenderRef = useRef<boolean>(true);
17
23
 
18
24
  // Memoized dependencies to avoid redundant `isEqual` checks
19
- const memoizedDependencies = React.useMemo(() => deps, [deps]);
25
+ const memoizedDependencies = useMemo(() => deps, [deps]);
20
26
 
21
27
  // Ref to store the previous dependencies
22
- const dependenciesRef = React.useRef<React.DependencyList>(memoizedDependencies);
28
+ const dependenciesRef = useRef<DependencyList>(memoizedDependencies);
23
29
 
24
30
  // Check for dependency changes
25
31
  const dependenciesChanged = !fastIsEqual(
@@ -30,7 +36,7 @@ export default function useDeepCompareEffect(
30
36
  dependenciesRef.current = memoizedDependencies;
31
37
  }
32
38
 
33
- React.useEffect(() => {
39
+ useEffect(() => {
34
40
  if (firstRenderRef.current) {
35
41
  firstRenderRef.current = false;
36
42
  }
@@ -1 +0,0 @@
1
- {"version":3,"names":["React","expandNodes","useTreeViewStore","useShallow","typedMemo","fastIsEqual","ExpandQueueAction","_innerScrollToNodeHandler","props","ref","storeId","flashListRef","flattenedFilteredNodes","setInitialScrollIndex","initialScrollNodeID","expanded","childToParentMap","state","useImperativeHandle","scrollToNodeID","params","queuedScrollToNodeParams","current","setExpandAndScrollToNodeQueue","EXPANDED","nodeId","expandScrolledNode","useRef","expandAndScrollToNodeQueue","useState","latestFlattenedFilteredNodesRef","useEffect","prevQueue","includes","RENDERED","useLayoutEffect","parentId","has","get","animated","viewOffset","viewPosition","scrollToItem","index","findIndex","item","id","scrollToIndex","__DEV__","console","info","initialScrollDone","_ScrollToNodeHandler","forwardRef","ScrollToNodeHandler"],"sourceRoot":"../../../src","sources":["handlers/ScrollToNodeHandler.tsx"],"mappings":"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","ignoreList":[]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ScrollToNodeHandler.d.ts","sourceRoot":"","sources":["../../../../src/handlers/ScrollToNodeHandler.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAIrE,UAAU,KAAK,CAAC,EAAE;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAC1C,sBAAsB,EAAE,qBAAqB,CAAC,EAAE,CAAC,EAAE,CAAC;IACpD,qBAAqB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IACpE,mBAAmB,EAAE,EAAE,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,kBAAkB,CAAC,EAAE;IACpC,MAAM,EAAE,EAAE,CAAC;IACX,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAQD,MAAM,WAAW,sBAAsB,CAAC,EAAE;IACxC,cAAc,EAAE,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;CAC1D;AAED,iBAAS,yBAAyB,CAAC,EAAE,EACnC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,EAChB,GAAG,EAAE,KAAK,CAAC,YAAY,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC,QA8IpD;AAMD,eAAO,MAAM,mBAAmB,GAJ6C,EAAE,SACtE,KAAK,CAAC,EAAE,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC,CAAC;CAAE,KACzE,UAAU,CAAC,OAAO,yBAAyB,CAIzB,CAAC"}