react-arborist 3.2.0 → 3.3.1-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 (213) hide show
  1. package/dist/main/components/cursor.d.ts +1 -0
  2. package/dist/main/components/cursor.js +20 -0
  3. package/dist/{components → main/components}/default-container.d.ts +1 -2
  4. package/dist/main/components/default-container.js +238 -0
  5. package/dist/main/components/default-cursor.js +35 -0
  6. package/dist/{components → main/components}/default-drag-preview.d.ts +1 -2
  7. package/dist/main/components/default-drag-preview.js +57 -0
  8. package/dist/{components → main/components}/default-node.d.ts +1 -2
  9. package/dist/main/components/default-node.js +32 -0
  10. package/dist/{components → main/components}/default-row.d.ts +1 -2
  11. package/dist/main/components/default-row.js +8 -0
  12. package/dist/main/components/drag-preview-container.d.ts +1 -0
  13. package/dist/main/components/drag-preview-container.js +21 -0
  14. package/dist/{components → main/components}/list-inner-element.d.ts +1 -1
  15. package/dist/main/components/list-inner-element.js +25 -0
  16. package/dist/main/components/list-outer-element.d.ts +2 -0
  17. package/dist/main/components/list-outer-element.js +38 -0
  18. package/dist/main/components/outer-drop.js +9 -0
  19. package/dist/{components → main/components}/provider.d.ts +2 -2
  20. package/dist/main/components/provider.js +52 -0
  21. package/dist/{components → main/components}/row-container.d.ts +2 -2
  22. package/dist/main/components/row-container.js +84 -0
  23. package/dist/main/components/tree-container.d.ts +1 -0
  24. package/dist/main/components/tree-container.js +12 -0
  25. package/dist/{components → main/components}/tree.d.ts +1 -1
  26. package/dist/main/components/tree.js +15 -0
  27. package/dist/{context.d.ts → main/context.d.ts} +4 -4
  28. package/dist/main/context.js +33 -0
  29. package/dist/main/data/create-index.js +10 -0
  30. package/dist/main/data/create-list.js +62 -0
  31. package/dist/main/data/create-root.js +43 -0
  32. package/dist/main/data/make-tree.d.ts +5 -0
  33. package/dist/main/data/make-tree.js +40 -0
  34. package/dist/{data → main/data}/simple-tree.d.ts +1 -1
  35. package/dist/main/data/simple-tree.js +100 -0
  36. package/dist/{dnd → main/dnd}/compute-drop.d.ts +6 -6
  37. package/dist/main/dnd/compute-drop.js +129 -0
  38. package/dist/main/dnd/drag-hook.js +46 -0
  39. package/dist/{dnd → main/dnd}/drop-hook.d.ts +2 -2
  40. package/dist/main/dnd/drop-hook.js +42 -0
  41. package/dist/main/dnd/measure-hover.d.ts +8 -0
  42. package/dist/main/dnd/measure-hover.js +21 -0
  43. package/dist/main/dnd/outer-drop-hook.js +45 -0
  44. package/dist/main/hooks/use-fresh-node.js +18 -0
  45. package/dist/{hooks → main/hooks}/use-simple-tree.d.ts +1 -1
  46. package/dist/main/hooks/use-simple-tree.js +35 -0
  47. package/dist/main/hooks/use-validated-props.js +29 -0
  48. package/dist/main/index.js +27 -0
  49. package/dist/{interfaces → main/interfaces}/node-api.d.ts +2 -1
  50. package/dist/main/interfaces/node-api.js +164 -0
  51. package/dist/{interfaces → main/interfaces}/tree-api.d.ts +90 -7
  52. package/dist/main/interfaces/tree-api.js +649 -0
  53. package/dist/main/interfaces/tree-api.test.d.ts +1 -0
  54. package/dist/main/interfaces/tree-api.test.js +14 -0
  55. package/dist/{state → main/state}/dnd-slice.d.ts +4 -4
  56. package/dist/main/state/dnd-slice.js +35 -0
  57. package/dist/{state → main/state}/drag-slice.d.ts +4 -2
  58. package/dist/main/state/drag-slice.js +24 -0
  59. package/dist/{state → main/state}/edit-slice.d.ts +1 -1
  60. package/dist/main/state/edit-slice.js +18 -0
  61. package/dist/{state → main/state}/focus-slice.d.ts +1 -1
  62. package/dist/main/state/focus-slice.js +26 -0
  63. package/dist/main/state/initial.js +29 -0
  64. package/dist/{state → main/state}/open-slice.d.ts +2 -2
  65. package/dist/main/state/open-slice.js +48 -0
  66. package/dist/main/state/root-reducer.d.ts +96 -0
  67. package/dist/main/state/root-reducer.js +20 -0
  68. package/dist/{state → main/state}/selection-slice.d.ts +1 -1
  69. package/dist/main/state/selection-slice.js +59 -0
  70. package/dist/{types → main/types}/dnd.d.ts +2 -2
  71. package/dist/main/types/dnd.js +2 -0
  72. package/dist/{types → main/types}/handlers.d.ts +5 -5
  73. package/dist/main/types/handlers.js +2 -0
  74. package/dist/{types → main/types}/renderers.d.ts +4 -4
  75. package/dist/main/types/renderers.js +2 -0
  76. package/dist/main/types/state.d.ts +2 -0
  77. package/dist/main/types/state.js +2 -0
  78. package/dist/main/types/tree-props.js +2 -0
  79. package/dist/{types → main/types}/utils.d.ts +5 -5
  80. package/dist/main/types/utils.js +2 -0
  81. package/dist/{utils.d.ts → main/utils.d.ts} +2 -2
  82. package/dist/main/utils.js +183 -0
  83. package/dist/module/components/cursor.d.ts +1 -0
  84. package/dist/module/components/cursor.js +16 -0
  85. package/dist/module/components/default-container.d.ts +6 -0
  86. package/dist/module/components/default-container.js +234 -0
  87. package/dist/module/components/default-cursor.d.ts +3 -0
  88. package/dist/module/components/default-cursor.js +29 -0
  89. package/dist/module/components/default-drag-preview.d.ts +2 -0
  90. package/dist/module/components/default-drag-preview.js +53 -0
  91. package/dist/module/components/default-node.d.ts +2 -0
  92. package/dist/module/components/default-node.js +28 -0
  93. package/dist/module/components/default-row.d.ts +2 -0
  94. package/dist/module/components/default-row.js +4 -0
  95. package/dist/module/components/drag-preview-container.d.ts +1 -0
  96. package/dist/module/components/drag-preview-container.js +17 -0
  97. package/dist/module/components/list-inner-element.d.ts +2 -0
  98. package/dist/module/components/list-inner-element.js +22 -0
  99. package/dist/module/components/list-outer-element.d.ts +2 -0
  100. package/dist/module/components/list-outer-element.js +35 -0
  101. package/dist/module/components/outer-drop.d.ts +4 -0
  102. package/dist/module/components/outer-drop.js +5 -0
  103. package/dist/module/components/provider.d.ts +10 -0
  104. package/dist/module/components/provider.js +48 -0
  105. package/dist/module/components/row-container.d.ts +7 -0
  106. package/dist/module/components/row-container.js +58 -0
  107. package/dist/module/components/tree-container.d.ts +1 -0
  108. package/dist/module/components/tree-container.js +8 -0
  109. package/dist/module/components/tree.d.ts +8 -0
  110. package/dist/module/components/tree.js +12 -0
  111. package/dist/module/context.d.ts +22 -0
  112. package/dist/module/context.js +26 -0
  113. package/dist/module/data/create-index.d.ts +4 -0
  114. package/dist/module/data/create-index.js +6 -0
  115. package/dist/module/data/create-list.d.ts +3 -0
  116. package/dist/module/data/create-list.js +58 -0
  117. package/dist/module/data/create-root.d.ts +4 -0
  118. package/dist/module/data/create-root.js +39 -0
  119. package/dist/module/data/make-tree.d.ts +5 -0
  120. package/dist/module/data/make-tree.js +36 -0
  121. package/dist/module/data/simple-tree.d.ts +44 -0
  122. package/dist/module/data/simple-tree.js +96 -0
  123. package/dist/module/dnd/compute-drop.d.ts +37 -0
  124. package/dist/module/dnd/compute-drop.js +125 -0
  125. package/dist/module/dnd/drag-hook.d.ts +3 -0
  126. package/dist/module/dnd/drag-hook.js +42 -0
  127. package/dist/module/dnd/drop-hook.d.ts +8 -0
  128. package/dist/module/dnd/drop-hook.js +38 -0
  129. package/dist/module/dnd/measure-hover.d.ts +8 -0
  130. package/dist/module/dnd/measure-hover.js +17 -0
  131. package/dist/module/dnd/outer-drop-hook.d.ts +1 -0
  132. package/dist/module/dnd/outer-drop-hook.js +41 -0
  133. package/dist/module/hooks/use-fresh-node.d.ts +1 -0
  134. package/dist/module/hooks/use-fresh-node.js +14 -0
  135. package/dist/module/hooks/use-simple-tree.d.ts +12 -0
  136. package/dist/module/hooks/use-simple-tree.js +31 -0
  137. package/dist/module/hooks/use-validated-props.d.ts +2 -0
  138. package/dist/module/hooks/use-validated-props.js +25 -0
  139. package/dist/module/index.d.ts +8 -0
  140. package/dist/module/index.js +9 -0
  141. package/dist/module/interfaces/node-api.d.ts +71 -0
  142. package/dist/module/interfaces/node-api.js +160 -0
  143. package/dist/module/interfaces/tree-api.d.ts +214 -0
  144. package/dist/module/interfaces/tree-api.js +622 -0
  145. package/dist/module/interfaces/tree-api.test.d.ts +1 -0
  146. package/dist/module/interfaces/tree-api.test.js +12 -0
  147. package/dist/module/state/dnd-slice.d.ts +29 -0
  148. package/dist/module/state/dnd-slice.js +31 -0
  149. package/dist/module/state/drag-slice.d.ts +9 -0
  150. package/dist/module/state/drag-slice.js +20 -0
  151. package/dist/module/state/edit-slice.d.ts +8 -0
  152. package/dist/module/state/edit-slice.js +13 -0
  153. package/dist/module/state/focus-slice.d.ts +12 -0
  154. package/dist/module/state/focus-slice.js +20 -0
  155. package/dist/module/state/initial.d.ts +3 -0
  156. package/dist/module/state/initial.js +25 -0
  157. package/dist/module/state/open-slice.d.ts +30 -0
  158. package/dist/module/state/open-slice.js +44 -0
  159. package/dist/module/state/root-reducer.d.ts +96 -0
  160. package/dist/module/state/root-reducer.js +17 -0
  161. package/dist/module/state/selection-slice.d.ts +42 -0
  162. package/dist/module/state/selection-slice.js +55 -0
  163. package/dist/module/types/dnd.d.ts +8 -0
  164. package/dist/module/types/dnd.js +1 -0
  165. package/dist/module/types/handlers.d.ts +30 -0
  166. package/dist/module/types/handlers.js +1 -0
  167. package/dist/module/types/renderers.d.ts +29 -0
  168. package/dist/module/types/renderers.js +1 -0
  169. package/dist/module/types/state.d.ts +2 -0
  170. package/dist/module/types/state.js +1 -0
  171. package/dist/module/types/tree-props.d.ts +56 -0
  172. package/dist/module/types/tree-props.js +1 -0
  173. package/dist/module/types/utils.d.ts +17 -0
  174. package/dist/module/types/utils.js +1 -0
  175. package/dist/module/utils.d.ts +24 -0
  176. package/dist/module/utils.js +162 -0
  177. package/package.json +26 -25
  178. package/src/components/default-container.tsx +2 -0
  179. package/src/components/provider.tsx +3 -2
  180. package/src/components/row-container.tsx +1 -1
  181. package/src/dnd/compute-drop.ts +6 -3
  182. package/src/dnd/drag-hook.ts +1 -1
  183. package/src/dnd/drop-hook.ts +1 -1
  184. package/src/interfaces/node-api.ts +10 -0
  185. package/src/interfaces/tree-api.ts +16 -3
  186. package/src/state/dnd-slice.ts +2 -2
  187. package/src/state/drag-slice.ts +27 -11
  188. package/src/state/initial.ts +6 -1
  189. package/src/utils.ts +2 -2
  190. package/dist/components/cursor.d.ts +0 -2
  191. package/dist/components/drag-preview-container.d.ts +0 -2
  192. package/dist/components/list-outer-element.d.ts +0 -2
  193. package/dist/components/tree-container.d.ts +0 -2
  194. package/dist/index.js +0 -2414
  195. package/dist/index.js.map +0 -1
  196. package/dist/module.js +0 -2387
  197. package/dist/module.js.map +0 -1
  198. package/dist/state/root-reducer.d.ts +0 -13
  199. package/dist/types/state.d.ts +0 -2
  200. package/jest.config.js +0 -5
  201. package/tsconfig.json +0 -4
  202. /package/dist/{components → main/components}/default-cursor.d.ts +0 -0
  203. /package/dist/{components → main/components}/outer-drop.d.ts +0 -0
  204. /package/dist/{data → main/data}/create-index.d.ts +0 -0
  205. /package/dist/{data → main/data}/create-list.d.ts +0 -0
  206. /package/dist/{data → main/data}/create-root.d.ts +0 -0
  207. /package/dist/{dnd → main/dnd}/drag-hook.d.ts +0 -0
  208. /package/dist/{dnd → main/dnd}/outer-drop-hook.d.ts +0 -0
  209. /package/dist/{hooks → main/hooks}/use-fresh-node.d.ts +0 -0
  210. /package/dist/{hooks → main/hooks}/use-validated-props.d.ts +0 -0
  211. /package/dist/{index.d.ts → main/index.d.ts} +0 -0
  212. /package/dist/{state → main/state}/initial.d.ts +0 -0
  213. /package/dist/{types → main/types}/tree-props.d.ts +0 -0
@@ -0,0 +1,162 @@
1
+ export function bound(n, min, max) {
2
+ return Math.max(Math.min(n, max), min);
3
+ }
4
+ export function isItem(node) {
5
+ return node && node.isLeaf;
6
+ }
7
+ export function isClosed(node) {
8
+ return node && node.isInternal && !node.isOpen;
9
+ }
10
+ /**
11
+ * Is first param a descendant of the second param
12
+ */
13
+ export const isDescendant = (a, b) => {
14
+ let n = a;
15
+ while (n) {
16
+ if (n.id === b.id)
17
+ return true;
18
+ n = n.parent;
19
+ }
20
+ return false;
21
+ };
22
+ export const indexOf = (node) => {
23
+ if (!node.parent)
24
+ throw Error("Node does not have a parent");
25
+ return node.parent.children.findIndex((c) => c.id === node.id);
26
+ };
27
+ export function noop() { }
28
+ export function dfs(node, id) {
29
+ if (!node)
30
+ return null;
31
+ if (node.id === id)
32
+ return node;
33
+ if (node.children) {
34
+ for (let child of node.children) {
35
+ const result = dfs(child, id);
36
+ if (result)
37
+ return result;
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+ export function walk(node, fn) {
43
+ fn(node);
44
+ if (node.children) {
45
+ for (let child of node.children) {
46
+ walk(child, fn);
47
+ }
48
+ }
49
+ }
50
+ export function focusNextElement(target) {
51
+ const elements = getFocusable(target);
52
+ let next;
53
+ for (let i = 0; i < elements.length; ++i) {
54
+ const item = elements[i];
55
+ if (item === target) {
56
+ next = nextItem(elements, i);
57
+ break;
58
+ }
59
+ }
60
+ // @ts-ignore ??
61
+ next === null || next === void 0 ? void 0 : next.focus();
62
+ }
63
+ export function focusPrevElement(target) {
64
+ const elements = getFocusable(target);
65
+ let next;
66
+ for (let i = 0; i < elements.length; ++i) {
67
+ const item = elements[i];
68
+ if (item === target) {
69
+ next = prevItem(elements, i);
70
+ break;
71
+ }
72
+ }
73
+ // @ts-ignore
74
+ next === null || next === void 0 ? void 0 : next.focus();
75
+ }
76
+ function nextItem(list, index) {
77
+ if (index + 1 < list.length) {
78
+ return list[index + 1];
79
+ }
80
+ else {
81
+ return list[0];
82
+ }
83
+ }
84
+ function prevItem(list, index) {
85
+ if (index - 1 >= 0) {
86
+ return list[index - 1];
87
+ }
88
+ else {
89
+ return list[list.length - 1];
90
+ }
91
+ }
92
+ function getFocusable(target) {
93
+ return Array.from(document.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled]), details:not([disabled]), summary:not(:disabled)')).filter((e) => e === target || !target.contains(e));
94
+ }
95
+ export function access(obj, accessor) {
96
+ if (typeof accessor === "boolean")
97
+ return accessor;
98
+ if (typeof accessor === "string")
99
+ return obj[accessor];
100
+ return accessor(obj);
101
+ }
102
+ export function identifyNull(obj) {
103
+ if (obj === null)
104
+ return null;
105
+ else
106
+ return identify(obj);
107
+ }
108
+ export function identify(obj) {
109
+ return typeof obj === "string" ? obj : obj.id;
110
+ }
111
+ export function mergeRefs(...refs) {
112
+ return (instance) => {
113
+ refs.forEach((ref) => {
114
+ if (typeof ref === "function") {
115
+ ref(instance);
116
+ }
117
+ else if (ref != null) {
118
+ ref.current = instance;
119
+ }
120
+ });
121
+ };
122
+ }
123
+ export function safeRun(fn, ...args) {
124
+ if (fn)
125
+ return fn(...args);
126
+ }
127
+ export function waitFor(fn) {
128
+ return new Promise((resolve, reject) => {
129
+ let tries = 0;
130
+ function check() {
131
+ tries += 1;
132
+ if (tries === 100)
133
+ reject();
134
+ if (fn())
135
+ resolve();
136
+ else
137
+ setTimeout(check, 10);
138
+ }
139
+ check();
140
+ });
141
+ }
142
+ export function getInsertIndex(tree) {
143
+ var _a, _b;
144
+ const focus = tree.focusedNode;
145
+ if (!focus)
146
+ return (_b = (_a = tree.root.children) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
147
+ if (focus.isOpen)
148
+ return 0;
149
+ if (focus.parent)
150
+ return focus.childIndex + 1;
151
+ return 0;
152
+ }
153
+ export function getInsertParentId(tree) {
154
+ const focus = tree.focusedNode;
155
+ if (!focus)
156
+ return null;
157
+ if (focus.isOpen)
158
+ return focus.id;
159
+ if (focus.parent && !focus.parent.isRoot)
160
+ return focus.parent.id;
161
+ return null;
162
+ }
package/package.json CHANGED
@@ -1,23 +1,25 @@
1
1
  {
2
2
  "name": "react-arborist",
3
- "version": "3.2.0",
3
+ "version": "3.3.1-0",
4
4
  "license": "MIT",
5
5
  "source": "src/index.ts",
6
- "main": "dist/index.js",
7
- "module": "dist/module.js",
8
- "types": "dist/index.d.ts",
6
+ "main": "dist/main/index.js",
7
+ "module": "dist/module/index.js",
8
+ "types": "dist/module/index.d.ts",
9
9
  "sideEffects": false,
10
10
  "scripts": {
11
- "start": "run-p 'start:**'",
11
+ "build:cjs": "tsc --outDir dist/main",
12
+ "build:es": "tsc --outDir dist/module --module es2022 --moduleResolution node",
12
13
  "build": "npm-run-all clean -p 'build:**'",
13
- "test": "jest",
14
- "build:js": "parcel build --target main --target module",
15
- "build:types": "tsc --outDir dist",
16
14
  "clean": "rimraf dist",
17
- "start:js": "parcel watch --target main --target module --no-hmr --no-cache",
18
- "start:types": "tsc --outDir dist --watch",
19
- "prepack": "yarn build"
15
+ "prepack": "yarn build",
16
+ "test": "jest",
17
+ "watch": "yarn build:es --watch"
20
18
  },
19
+ "files": [
20
+ "src",
21
+ "dist"
22
+ ],
21
23
  "repository": {
22
24
  "type": "git",
23
25
  "url": "https://github.com/brimdata/react-arborist.git"
@@ -37,9 +39,9 @@
37
39
  ],
38
40
  "dependencies": {
39
41
  "react-dnd": "^14.0.3",
40
- "react-dnd-html5-backend": "^14.0.1",
41
- "react-window": "^1.8.6",
42
- "redux": "^4.1.1",
42
+ "react-dnd-html5-backend": "^14.0.3",
43
+ "react-window": "^1.8.10",
44
+ "redux": "^5.0.0",
43
45
  "use-sync-external-store": "^1.2.0"
44
46
  },
45
47
  "peerDependencies": {
@@ -47,16 +49,15 @@
47
49
  "react-dom": ">= 16.14"
48
50
  },
49
51
  "devDependencies": {
50
- "@parcel/core": "^2.3.2",
51
- "@types/jest": "^27.4.1",
52
- "@types/react": "^18.0.0",
53
- "@types/react-window": "^1.8.5",
54
- "@types/use-sync-external-store": "^0.0.3",
55
- "jest": "^29.4.1",
52
+ "@types/jest": "^29.5.11",
53
+ "@types/react": "^18.2.43",
54
+ "@types/react-window": "^1.8.8",
55
+ "@types/use-sync-external-store": "^0.0.6",
56
+ "jest": "^29.7.0",
56
57
  "npm-run-all": "^4.1.5",
57
- "parcel": "^2.3.2",
58
- "rimraf": "^4.1.2",
59
- "ts-jest": "^29.0.5",
60
- "typescript": "^4.6.2"
61
- }
58
+ "rimraf": "^5.0.5",
59
+ "ts-jest": "^29.1.1",
60
+ "typescript": "^5.3.3"
61
+ },
62
+ "stableVersion": "3.3.0"
62
63
  }
@@ -18,6 +18,7 @@ export function DefaultContainer() {
18
18
  const tree = useTreeApi();
19
19
  return (
20
20
  <div
21
+ role="tree"
21
22
  style={{
22
23
  height: tree.height,
23
24
  width: tree.width,
@@ -215,6 +216,7 @@ export function DefaultContainer() {
215
216
  if (node) tree.focus(node.id);
216
217
  }}
217
218
  >
219
+ {/* @ts-ignore */}
218
220
  <FixedSizeList
219
221
  className={tree.props.className}
220
222
  outerRef={tree.listEl}
@@ -15,7 +15,7 @@ import {
15
15
  } from "../context";
16
16
  import { TreeApi } from "../interfaces/tree-api";
17
17
  import { initialState } from "../state/initial";
18
- import { rootReducer, RootState } from "../state/root-reducer";
18
+ import { Actions, rootReducer, RootState } from "../state/root-reducer";
19
19
  import { HTML5Backend } from "react-dnd-html5-backend";
20
20
  import { DndProvider } from "react-dnd";
21
21
  import { TreeProps } from "../types/tree-props";
@@ -37,7 +37,8 @@ export function TreeProvider<T>({
37
37
  }: Props<T>) {
38
38
  const list = useRef<FixedSizeList | null>(null);
39
39
  const listEl = useRef<HTMLDivElement | null>(null);
40
- const store = useRef<Store>(
40
+ const store = useRef<Store<RootState, Actions>>(
41
+ // @ts-ignore
41
42
  createStore(rootReducer, initialState(treeProps))
42
43
  );
43
44
  const state = useSyncExternalStore<RootState>(
@@ -58,7 +58,7 @@ export const RowContainer = React.memo(function RowContainer<T>({
58
58
  );
59
59
  const rowAttrs: React.HTMLAttributes<any> = {
60
60
  role: "treeitem",
61
- "aria-level": node.level,
61
+ "aria-level": node.level + 1,
62
62
  "aria-selected": node.isSelected,
63
63
  style: rowStyle,
64
64
  tabIndex: -1,
@@ -26,7 +26,7 @@ function getNodesAroundCursor(
26
26
  hover: HoverData
27
27
  ): [NodeApi | null, NodeApi | null] {
28
28
  if (!node) {
29
- // We're hoving over the empty part of the list, not over an item,
29
+ // We're hovering over the empty part of the list, not over an item,
30
30
  // Put the cursor below the last item which is "prev"
31
31
  return [prev, null];
32
32
  }
@@ -83,7 +83,10 @@ export type ComputedDrop = {
83
83
  cursor: Cursor | null;
84
84
  };
85
85
 
86
- function dropAt(parentId: string | undefined, index: number): DropResult {
86
+ function dropAt(
87
+ parentId: string | undefined,
88
+ index: number | null
89
+ ): DropResult {
87
90
  return { parentId: parentId || null, index };
88
91
  }
89
92
 
@@ -135,7 +138,7 @@ export function computeDrop(args: Args): ComputedDrop {
135
138
  /* Hovering over the middle of a folder */
136
139
  if (node && node.isInternal && hover.inMiddle) {
137
140
  return {
138
- drop: dropAt(node.id, 0),
141
+ drop: dropAt(node.id, null),
139
142
  cursor: highlightCursor(node.id),
140
143
  };
141
144
  }
@@ -31,7 +31,7 @@ export function useDragHook<T>(node: NodeApi<T>): ConnectDragSource {
31
31
  safeRun(tree.props.onMove, {
32
32
  dragIds,
33
33
  parentId: parentId === ROOT_ID ? null : parentId,
34
- index,
34
+ index: index === null ? 0 : index, // When it's null it was dropped over a folder
35
35
  dragNodes: tree.dragNodes,
36
36
  parentNode: tree.get(parentId),
37
37
  });
@@ -8,7 +8,7 @@ import { actions as dnd } from "../state/dnd-slice";
8
8
 
9
9
  export type DropResult = {
10
10
  parentId: string | null;
11
- index: number;
11
+ index: number | null;
12
12
  };
13
13
 
14
14
  export function useDropHook(
@@ -130,6 +130,16 @@ export class NodeApi<T = any> {
130
130
  return this.parent?.children![i + 1] ?? null;
131
131
  }
132
132
 
133
+ isAncestorOf(node: NodeApi<T> | null) {
134
+ if (!node) return false;
135
+ let ancestor: NodeApi<T> | null = node;
136
+ while (ancestor) {
137
+ if (ancestor.id === this.id) return true;
138
+ ancestor = ancestor.parent;
139
+ }
140
+ return false;
141
+ }
142
+
133
143
  select() {
134
144
  this.tree.select(this);
135
145
  }
@@ -419,6 +419,18 @@ export class TreeApi<T> {
419
419
  .filter((n) => !!n) as NodeApi<T>[];
420
420
  }
421
421
 
422
+ get dragNode() {
423
+ return this.get(this.state.nodes.drag.id);
424
+ }
425
+
426
+ get dragDestinationParent() {
427
+ return this.get(this.state.nodes.drag.destinationParentId);
428
+ }
429
+
430
+ get dragDestinationIndex() {
431
+ return this.state.nodes.drag.destinationIndex;
432
+ }
433
+
422
434
  canDrop() {
423
435
  if (this.isFiltered) return false;
424
436
  const parentNode = this.get(this.state.dnd.parentId) ?? this.root;
@@ -428,7 +440,7 @@ export class TreeApi<T> {
428
440
  for (const drag of dragNodes) {
429
441
  if (!drag) return false;
430
442
  if (!parentNode) return false;
431
- if (drag.isInternal && utils.isDecendent(parentNode, drag)) return false;
443
+ if (drag.isInternal && utils.isDescendant(parentNode, drag)) return false;
432
444
  }
433
445
 
434
446
  // Allow the user to insert their own logic
@@ -436,7 +448,7 @@ export class TreeApi<T> {
436
448
  return !isDisabled({
437
449
  parentNode,
438
450
  dragNodes: this.dragNodes,
439
- index: this.state.dnd.index,
451
+ index: this.state.dnd.index || 0,
440
452
  });
441
453
  } else if (typeof isDisabled == "string") {
442
454
  // @ts-ignore
@@ -606,7 +618,8 @@ export class TreeApi<T> {
606
618
  willReceiveDrop(node: string | IdObj | null) {
607
619
  const id = identifyNull(node);
608
620
  if (!id) return false;
609
- return id === this.state.nodes.drag.idWillReceiveDrop;
621
+ const { destinationParentId, destinationIndex } = this.state.nodes.drag;
622
+ return id === destinationParentId && destinationIndex === null;
610
623
  }
611
624
 
612
625
  /* Tree Event Handlers */
@@ -8,7 +8,7 @@ export type DndState = {
8
8
  cursor: Cursor;
9
9
  dragIds: string[];
10
10
  parentId: null | string;
11
- index: number;
11
+ index: number | null;
12
12
  };
13
13
 
14
14
  /* Actions */
@@ -22,7 +22,7 @@ export const actions = {
22
22
  dragEnd() {
23
23
  return { type: "DND_DRAG_END" as const };
24
24
  },
25
- hovering(parentId: string | null, index: number) {
25
+ hovering(parentId: string | null, index: number | null) {
26
26
  return { type: "DND_HOVERING" as const, parentId, index };
27
27
  },
28
28
  };
@@ -1,27 +1,43 @@
1
1
  import { ActionTypes } from "../types/utils";
2
2
  import { actions as dnd } from "./dnd-slice";
3
+ import { initialState } from "./initial";
3
4
 
4
5
  /* Types */
5
6
 
6
- export type DragSlice = { id: string | null; idWillReceiveDrop: string | null };
7
+ export type DragSlice = {
8
+ id: string | null;
9
+ selectedIds: string[];
10
+ destinationParentId: string | null;
11
+ destinationIndex: number | null;
12
+ };
7
13
 
8
14
  /* Reducer */
9
15
 
10
16
  export function reducer(
11
- state: DragSlice = { id: null, idWillReceiveDrop: null },
17
+ state: DragSlice = initialState().nodes.drag,
12
18
  action: ActionTypes<typeof dnd>
13
- ) {
19
+ ): DragSlice {
14
20
  switch (action.type) {
15
21
  case "DND_DRAG_START":
16
- return { ...state, id: action.id };
22
+ return { ...state, id: action.id, selectedIds: action.dragIds };
17
23
  case "DND_DRAG_END":
18
- return { ...state, id: null };
19
- case "DND_CURSOR":
20
- const c = action.cursor;
21
- if (c.type === "highlight" && c.id !== state.idWillReceiveDrop) {
22
- return { ...state, idWillReceiveDrop: c.id };
23
- } else if (c.type !== "highlight" && state.idWillReceiveDrop !== null) {
24
- return { ...state, idWillReceiveDrop: null };
24
+ return {
25
+ ...state,
26
+ id: null,
27
+ destinationParentId: null,
28
+ destinationIndex: null,
29
+ selectedIds: [],
30
+ };
31
+ case "DND_HOVERING":
32
+ if (
33
+ action.parentId !== state.destinationParentId ||
34
+ action.index != state.destinationIndex
35
+ ) {
36
+ return {
37
+ ...state,
38
+ destinationParentId: action.parentId,
39
+ destinationIndex: action.index,
40
+ };
25
41
  } else {
26
42
  return state;
27
43
  }
@@ -7,7 +7,12 @@ export const initialState = (props?: TreeProps<any>): RootState => ({
7
7
  open: { filtered: {}, unfiltered: props?.initialOpenState ?? {} },
8
8
  focus: { id: null, treeFocused: false },
9
9
  edit: { id: null },
10
- drag: { id: null, idWillReceiveDrop: null },
10
+ drag: {
11
+ id: null,
12
+ selectedIds: [],
13
+ destinationParentId: null,
14
+ destinationIndex: null,
15
+ },
11
16
  selection: { ids: new Set(), anchor: null, mostRecent: null },
12
17
  },
13
18
  dnd: {
package/src/utils.ts CHANGED
@@ -15,9 +15,9 @@ export function isClosed(node: NodeApi<any> | null) {
15
15
  }
16
16
 
17
17
  /**
18
- * Is first param a decendent of the second param
18
+ * Is first param a descendant of the second param
19
19
  */
20
- export const isDecendent = (a: NodeApi<any>, b: NodeApi<any>) => {
20
+ export const isDescendant = (a: NodeApi<any>, b: NodeApi<any>) => {
21
21
  let n: NodeApi<any> | null = a;
22
22
  while (n) {
23
23
  if (n.id === b.id) return true;
@@ -1,2 +0,0 @@
1
- /// <reference types="react" />
2
- export declare function Cursor(): JSX.Element | null;
@@ -1,2 +0,0 @@
1
- /// <reference types="react" />
2
- export declare function DragPreviewContainer(): JSX.Element;
@@ -1,2 +0,0 @@
1
- /// <reference types="react" />
2
- export declare const ListOuterElement: import("react").ForwardRefExoticComponent<Pick<import("react").HTMLProps<HTMLDivElement>, "id" | "children" | "data" | "open" | "cite" | "form" | "label" | "slot" | "span" | "style" | "summary" | "title" | "pattern" | "start" | "hidden" | "color" | "content" | "size" | "default" | "wrap" | "multiple" | "disabled" | "onFocus" | "onClick" | "list" | "name" | "defaultValue" | "onBlur" | "onKeyDown" | "accessKey" | "dir" | "draggable" | "lang" | "translate" | "className" | "classID" | "value" | "defaultChecked" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "download" | "alt" | "coords" | "autoPlay" | "controls" | "autoFocus" | "formAction" | "formEncType" | "formMethod" | "formNoValidate" | "formTarget" | "dateTime" | "acceptCharset" | "action" | "autoComplete" | "encType" | "manifest" | "allowFullScreen" | "allowTransparency" | "frameBorder" | "accept" | "capture" | "checked" | "challenge" | "keyType" | "keyParams" | "htmlFor" | "as" | "charSet" | "httpEquiv" | "high" | "low" | "reversed" | "selected" | "async" | "cellPadding" | "cellSpacing" | "colSpan" | "headers" | "rowSpan" | "scope" | "cols" | "maxLength" | "minLength" | "kind" | "src" | "srcLang" | "preload" | "crossOrigin" | "defer" | "height" | "href" | "hrefLang" | "integrity" | "loop" | "marginHeight" | "marginWidth" | "max" | "media" | "mediaGroup" | "method" | "min" | "muted" | "nonce" | "noValidate" | "optimum" | "placeholder" | "playsInline" | "poster" | "readOnly" | "rel" | "required" | "rows" | "sandbox" | "scoped" | "scrolling" | "seamless" | "shape" | "sizes" | "srcDoc" | "srcSet" | "step" | "target" | "type" | "useMap" | "width" | "wmode" | "contentEditable" | "contextMenu" | "spellCheck" | "tabIndex" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocusCapture" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "key"> & import("react").RefAttributes<unknown>>;
@@ -1,2 +0,0 @@
1
- /// <reference types="react" />
2
- export declare function TreeContainer(): JSX.Element;