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,125 @@
1
+ import { bound, indexOf, isClosed, isItem } from "../utils";
2
+ function measureHover(el, offset) {
3
+ const rect = el.getBoundingClientRect();
4
+ const x = offset.x - Math.round(rect.x);
5
+ const y = offset.y - Math.round(rect.y);
6
+ const height = rect.height;
7
+ const inTopHalf = y < height / 2;
8
+ const inBottomHalf = !inTopHalf;
9
+ const pad = height / 4;
10
+ const inMiddle = y > pad && y < height - pad;
11
+ const atTop = !inMiddle && inTopHalf;
12
+ const atBottom = !inMiddle && inBottomHalf;
13
+ return { x, inTopHalf, inBottomHalf, inMiddle, atTop, atBottom };
14
+ }
15
+ function getNodesAroundCursor(node, prev, next, hover) {
16
+ if (!node) {
17
+ // We're hovering over the empty part of the list, not over an item,
18
+ // Put the cursor below the last item which is "prev"
19
+ return [prev, null];
20
+ }
21
+ if (node.isInternal) {
22
+ if (hover.atTop) {
23
+ return [prev, node];
24
+ }
25
+ else if (hover.inMiddle) {
26
+ return [node, node];
27
+ }
28
+ else {
29
+ return [node, next];
30
+ }
31
+ }
32
+ else {
33
+ if (hover.inTopHalf) {
34
+ return [prev, node];
35
+ }
36
+ else {
37
+ return [node, next];
38
+ }
39
+ }
40
+ }
41
+ function getDropLevel(hovering, aboveCursor, belowCursor, indent) {
42
+ const hoverLevel = Math.round(Math.max(0, hovering.x - indent) / indent);
43
+ let min, max;
44
+ if (!aboveCursor) {
45
+ max = 0;
46
+ min = 0;
47
+ }
48
+ else if (!belowCursor) {
49
+ max = aboveCursor.level;
50
+ min = 0;
51
+ }
52
+ else {
53
+ max = aboveCursor.level;
54
+ min = belowCursor.level;
55
+ }
56
+ return bound(hoverLevel, min, max);
57
+ }
58
+ function dropAt(parentId, index) {
59
+ return { parentId: parentId || null, index };
60
+ }
61
+ function lineCursor(index, level) {
62
+ return {
63
+ type: "line",
64
+ index,
65
+ level,
66
+ };
67
+ }
68
+ function noCursor() {
69
+ return {
70
+ type: "none",
71
+ };
72
+ }
73
+ function highlightCursor(id) {
74
+ return {
75
+ type: "highlight",
76
+ id,
77
+ };
78
+ }
79
+ function walkUpFrom(node, level) {
80
+ var _a;
81
+ let drop = node;
82
+ while (drop.parent && drop.level > level) {
83
+ drop = drop.parent;
84
+ }
85
+ const parentId = ((_a = drop.parent) === null || _a === void 0 ? void 0 : _a.id) || null;
86
+ const index = indexOf(drop) + 1;
87
+ return { parentId, index };
88
+ }
89
+ /**
90
+ * This is the most complex, tricky function in the whole repo.
91
+ * It could be simplified and made more understandable.
92
+ */
93
+ export function computeDrop(args) {
94
+ var _a;
95
+ const hover = measureHover(args.element, args.offset);
96
+ const { node, nextNode, prevNode } = args;
97
+ const [above, below] = getNodesAroundCursor(node, prevNode, nextNode, hover);
98
+ /* Hovering over the middle of a folder */
99
+ if (node && node.isInternal && hover.inMiddle) {
100
+ return {
101
+ drop: dropAt(node.id, null),
102
+ cursor: highlightCursor(node.id),
103
+ };
104
+ }
105
+ /* At the top of the list */
106
+ if (!above) {
107
+ return {
108
+ drop: dropAt((_a = below === null || below === void 0 ? void 0 : below.parent) === null || _a === void 0 ? void 0 : _a.id, 0),
109
+ cursor: lineCursor(0, 0),
110
+ };
111
+ }
112
+ /* The above node is an item or a closed folder */
113
+ if (isItem(above) || isClosed(above)) {
114
+ const level = getDropLevel(hover, above, below, args.indent);
115
+ return {
116
+ drop: walkUpFrom(above, level),
117
+ cursor: lineCursor(above.rowIndex + 1, level),
118
+ };
119
+ }
120
+ /* The above node is an open folder */
121
+ return {
122
+ drop: dropAt(above === null || above === void 0 ? void 0 : above.id, 0),
123
+ cursor: lineCursor(above.rowIndex + 1, above.level + 1),
124
+ };
125
+ }
@@ -0,0 +1,3 @@
1
+ import { ConnectDragSource } from "react-dnd";
2
+ import { NodeApi } from "../interfaces/node-api";
3
+ export declare function useDragHook<T>(node: NodeApi<T>): ConnectDragSource;
@@ -0,0 +1,42 @@
1
+ import { useEffect } from "react";
2
+ import { useDrag } from "react-dnd";
3
+ import { getEmptyImage } from "react-dnd-html5-backend";
4
+ import { useTreeApi } from "../context";
5
+ import { actions as dnd } from "../state/dnd-slice";
6
+ import { safeRun } from "../utils";
7
+ import { ROOT_ID } from "../data/create-root";
8
+ export function useDragHook(node) {
9
+ const tree = useTreeApi();
10
+ const ids = tree.selectedIds;
11
+ const [_, ref, preview] = useDrag(() => ({
12
+ canDrag: () => node.isDraggable,
13
+ type: "NODE",
14
+ item: () => {
15
+ // This is fired once at the begging of a drag operation
16
+ const dragIds = tree.isSelected(node.id) ? Array.from(ids) : [node.id];
17
+ tree.dispatch(dnd.dragStart(node.id, dragIds));
18
+ return { id: node.id };
19
+ },
20
+ end: () => {
21
+ tree.hideCursor();
22
+ let { parentId, index, dragIds } = tree.state.dnd;
23
+ // If they held down meta, we need to create a copy
24
+ // if (drop.dropEffect === "copy")
25
+ if (tree.canDrop()) {
26
+ safeRun(tree.props.onMove, {
27
+ dragIds,
28
+ parentId: parentId === ROOT_ID ? null : parentId,
29
+ index: index === null ? 0 : index, // When it's null it was dropped over a folder
30
+ dragNodes: tree.dragNodes,
31
+ parentNode: tree.get(parentId),
32
+ });
33
+ tree.open(parentId);
34
+ }
35
+ tree.dispatch(dnd.dragEnd());
36
+ },
37
+ }), [ids, node]);
38
+ useEffect(() => {
39
+ preview(getEmptyImage());
40
+ }, [preview]);
41
+ return ref;
42
+ }
@@ -0,0 +1,8 @@
1
+ import { RefObject } from "react";
2
+ import { ConnectDropTarget } from "react-dnd";
3
+ import { NodeApi } from "../interfaces/node-api";
4
+ export type DropResult = {
5
+ parentId: string | null;
6
+ index: number | null;
7
+ };
8
+ export declare function useDropHook(el: RefObject<HTMLElement | null>, node: NodeApi<any>): ConnectDropTarget;
@@ -0,0 +1,38 @@
1
+ import { useDrop } from "react-dnd";
2
+ import { useTreeApi } from "../context";
3
+ import { computeDrop } from "./compute-drop";
4
+ import { actions as dnd } from "../state/dnd-slice";
5
+ export function useDropHook(el, node) {
6
+ const tree = useTreeApi();
7
+ const [_, dropRef] = useDrop(() => ({
8
+ accept: "NODE",
9
+ canDrop: () => tree.canDrop(),
10
+ hover: (_item, m) => {
11
+ const offset = m.getClientOffset();
12
+ if (!el.current || !offset)
13
+ return;
14
+ const { cursor, drop } = computeDrop({
15
+ element: el.current,
16
+ offset: offset,
17
+ indent: tree.indent,
18
+ node: node,
19
+ prevNode: node.prev,
20
+ nextNode: node.next,
21
+ });
22
+ if (drop)
23
+ tree.dispatch(dnd.hovering(drop.parentId, drop.index));
24
+ if (m.canDrop()) {
25
+ if (cursor)
26
+ tree.showCursor(cursor);
27
+ }
28
+ else {
29
+ tree.hideCursor();
30
+ }
31
+ },
32
+ drop: (_, m) => {
33
+ if (!m.canDrop())
34
+ return null;
35
+ },
36
+ }), [node, el.current, tree.props]);
37
+ return dropRef;
38
+ }
@@ -0,0 +1,8 @@
1
+ import { XYCoord } from "react-dnd";
2
+ export declare function measureHover(el: HTMLElement, offset: XYCoord, indent: number): {
3
+ level: number;
4
+ inTopHalf: boolean;
5
+ inBottomHalf: boolean;
6
+ inMiddle: boolean;
7
+ };
8
+ export type HoverData = ReturnType<typeof measureHover>;
@@ -0,0 +1,17 @@
1
+ import { bound } from "../utils";
2
+ export function measureHover(el, offset, indent) {
3
+ const nextEl = el.nextElementSibling;
4
+ const prevEl = el.previousElementSibling;
5
+ const rect = el.getBoundingClientRect();
6
+ const x = offset.x - Math.round(rect.x);
7
+ const y = offset.y - Math.round(rect.y);
8
+ const height = rect.height;
9
+ const inTopHalf = y < height / 2;
10
+ const inBottomHalf = !inTopHalf;
11
+ const pad = height / 4;
12
+ const inMiddle = y > pad && y < height - pad;
13
+ const maxLevel = Number(inBottomHalf ? el.dataset.level : prevEl ? prevEl.dataset.level : 0);
14
+ const minLevel = Number(inTopHalf ? el.dataset.level : nextEl ? nextEl.dataset.level : 0);
15
+ const level = bound(Math.floor(x / indent), minLevel, maxLevel);
16
+ return { level, inTopHalf, inBottomHalf, inMiddle };
17
+ }
@@ -0,0 +1 @@
1
+ export declare function useOuterDrop(): void;
@@ -0,0 +1,41 @@
1
+ import { useDrop } from "react-dnd";
2
+ import { useTreeApi } from "../context";
3
+ import { computeDrop } from "./compute-drop";
4
+ import { actions as dnd } from "../state/dnd-slice";
5
+ export function useOuterDrop() {
6
+ const tree = useTreeApi();
7
+ // In case we drop an item at the bottom of the list
8
+ const [, drop] = useDrop(() => ({
9
+ accept: "NODE",
10
+ canDrop: (_item, m) => {
11
+ if (!m.isOver({ shallow: true }))
12
+ return false;
13
+ return tree.canDrop();
14
+ },
15
+ hover: (_item, m) => {
16
+ if (!m.isOver({ shallow: true }))
17
+ return;
18
+ const offset = m.getClientOffset();
19
+ if (!tree.listEl.current || !offset)
20
+ return;
21
+ const { cursor, drop } = computeDrop({
22
+ element: tree.listEl.current,
23
+ offset: offset,
24
+ indent: tree.indent,
25
+ node: null,
26
+ prevNode: tree.visibleNodes[tree.visibleNodes.length - 1],
27
+ nextNode: null,
28
+ });
29
+ if (drop)
30
+ tree.dispatch(dnd.hovering(drop.parentId, drop.index));
31
+ if (m.canDrop()) {
32
+ if (cursor)
33
+ tree.showCursor(cursor);
34
+ }
35
+ else {
36
+ tree.hideCursor();
37
+ }
38
+ },
39
+ }), [tree]);
40
+ drop(tree.listEl);
41
+ }
@@ -0,0 +1 @@
1
+ export declare function useFreshNode<T>(index: number): import("..").NodeApi<T>;
@@ -0,0 +1,14 @@
1
+ import { useMemo } from "react";
2
+ import { useTreeApi } from "../context";
3
+ export function useFreshNode(index) {
4
+ const tree = useTreeApi();
5
+ const original = tree.at(index);
6
+ if (!original)
7
+ throw new Error(`Could not find node for index: ${index}`);
8
+ return useMemo(() => {
9
+ const fresh = original.clone();
10
+ tree.visibleNodes[index] = fresh; // sneaky
11
+ return fresh;
12
+ // Return a fresh instance if the state values change
13
+ }, [...Object.values(original.state), original]);
14
+ }
@@ -0,0 +1,12 @@
1
+ import { CreateHandler, DeleteHandler, MoveHandler, RenameHandler } from "../types/handlers";
2
+ export type SimpleTreeData = {
3
+ id: string;
4
+ name: string;
5
+ children?: SimpleTreeData[];
6
+ };
7
+ export declare function useSimpleTree<T>(initialData: readonly T[]): readonly [readonly T[], {
8
+ onMove: MoveHandler<T>;
9
+ onRename: RenameHandler<T>;
10
+ onCreate: CreateHandler<T>;
11
+ onDelete: DeleteHandler<T>;
12
+ }];
@@ -0,0 +1,31 @@
1
+ import { useMemo, useState } from "react";
2
+ import { SimpleTree } from "../data/simple-tree";
3
+ let nextId = 0;
4
+ export function useSimpleTree(initialData) {
5
+ const [data, setData] = useState(initialData);
6
+ const tree = useMemo(() => new SimpleTree(data), [data]);
7
+ const onMove = (args) => {
8
+ for (const id of args.dragIds) {
9
+ tree.move({ id, parentId: args.parentId, index: args.index });
10
+ }
11
+ setData(tree.data);
12
+ };
13
+ const onRename = ({ name, id }) => {
14
+ tree.update({ id, changes: { name } });
15
+ setData(tree.data);
16
+ };
17
+ const onCreate = ({ parentId, index, type }) => {
18
+ const data = { id: `simple-tree-id-${nextId++}`, name: "" };
19
+ if (type === "internal")
20
+ data.children = [];
21
+ tree.create({ parentId, index, data });
22
+ setData(tree.data);
23
+ return data;
24
+ };
25
+ const onDelete = (args) => {
26
+ args.ids.forEach((id) => tree.drop({ id }));
27
+ setData(tree.data);
28
+ };
29
+ const controller = { onMove, onRename, onCreate, onDelete };
30
+ return [data, controller];
31
+ }
@@ -0,0 +1,2 @@
1
+ import { TreeProps } from "../types/tree-props";
2
+ export declare function useValidatedProps<T>(props: TreeProps<T>): TreeProps<T>;
@@ -0,0 +1,25 @@
1
+ import { useSimpleTree } from "./use-simple-tree";
2
+ export function useValidatedProps(props) {
3
+ if (props.initialData && props.data) {
4
+ throw new Error(`React Arborist Tree => Provide either a data or initialData prop, but not both.`);
5
+ }
6
+ if (props.initialData &&
7
+ (props.onCreate || props.onDelete || props.onMove || props.onRename)) {
8
+ throw new Error(`React Arborist Tree => You passed the initialData prop along with a data handler.
9
+ Use the data prop if you want to provide your own handlers.`);
10
+ }
11
+ if (props.initialData) {
12
+ /**
13
+ * Let's break the rules of hooks here. If the initialData prop
14
+ * is provided, we will assume it will not change for the life of
15
+ * the component.
16
+ *
17
+ * We will provide the real data and the handlers to update it.
18
+ * */
19
+ const [data, controller] = useSimpleTree(props.initialData);
20
+ return Object.assign(Object.assign(Object.assign({}, props), controller), { data });
21
+ }
22
+ else {
23
+ return props;
24
+ }
25
+ }
@@ -0,0 +1,8 @@
1
+ export { Tree } from "./components/tree";
2
+ export * from "./types/handlers";
3
+ export * from "./types/renderers";
4
+ export * from "./types/state";
5
+ export * from "./interfaces/node-api";
6
+ export * from "./interfaces/tree-api";
7
+ export * from "./data/simple-tree";
8
+ export * from "./hooks/use-simple-tree";
@@ -0,0 +1,9 @@
1
+ /* The Public Api */
2
+ export { Tree } from "./components/tree";
3
+ export * from "./types/handlers";
4
+ export * from "./types/renderers";
5
+ export * from "./types/state";
6
+ export * from "./interfaces/node-api";
7
+ export * from "./interfaces/tree-api";
8
+ export * from "./data/simple-tree";
9
+ export * from "./hooks/use-simple-tree";
@@ -0,0 +1,71 @@
1
+ import React from "react";
2
+ import { TreeApi } from "./tree-api";
3
+ type Params<T> = {
4
+ id: string;
5
+ data: T;
6
+ level: number;
7
+ children: NodeApi<T>[] | null;
8
+ parent: NodeApi<T> | null;
9
+ isDraggable: boolean;
10
+ rowIndex: number | null;
11
+ tree: TreeApi<T>;
12
+ };
13
+ export declare class NodeApi<T = any> {
14
+ tree: TreeApi<T>;
15
+ id: string;
16
+ data: T;
17
+ level: number;
18
+ children: NodeApi<T>[] | null;
19
+ parent: NodeApi<T> | null;
20
+ isDraggable: boolean;
21
+ rowIndex: number | null;
22
+ constructor(params: Params<T>);
23
+ get isRoot(): boolean;
24
+ get isLeaf(): boolean;
25
+ get isInternal(): boolean;
26
+ get isOpen(): boolean;
27
+ get isClosed(): boolean;
28
+ get isEditable(): boolean;
29
+ get isEditing(): boolean;
30
+ get isSelected(): boolean;
31
+ get isOnlySelection(): boolean;
32
+ get isSelectedStart(): boolean;
33
+ get isSelectedEnd(): boolean;
34
+ get isFocused(): boolean;
35
+ get isDragging(): boolean;
36
+ get willReceiveDrop(): boolean;
37
+ get state(): {
38
+ isClosed: boolean;
39
+ isDragging: boolean;
40
+ isEditing: boolean;
41
+ isFocused: boolean;
42
+ isInternal: boolean;
43
+ isLeaf: boolean;
44
+ isOpen: boolean;
45
+ isSelected: boolean;
46
+ isSelectedEnd: boolean;
47
+ isSelectedStart: boolean;
48
+ willReceiveDrop: boolean;
49
+ };
50
+ get childIndex(): number;
51
+ get next(): NodeApi<T> | null;
52
+ get prev(): NodeApi<T> | null;
53
+ get nextSibling(): NodeApi<T> | null;
54
+ isAncestorOf(node: NodeApi<T> | null): boolean;
55
+ select(): void;
56
+ deselect(): void;
57
+ selectMulti(): void;
58
+ selectContiguous(): void;
59
+ activate(): void;
60
+ focus(): void;
61
+ toggle(): void;
62
+ open(): void;
63
+ openParents(): void;
64
+ close(): void;
65
+ submit(value: string): void;
66
+ reset(): void;
67
+ clone(): NodeApi<T>;
68
+ edit(): Promise<import("..").EditResult>;
69
+ handleClick: (e: React.MouseEvent) => void;
70
+ }
71
+ export {};
@@ -0,0 +1,160 @@
1
+ import { ROOT_ID } from "../data/create-root";
2
+ export class NodeApi {
3
+ constructor(params) {
4
+ this.handleClick = (e) => {
5
+ if (e.metaKey && !this.tree.props.disableMultiSelection) {
6
+ this.isSelected ? this.deselect() : this.selectMulti();
7
+ }
8
+ else if (e.shiftKey && !this.tree.props.disableMultiSelection) {
9
+ this.selectContiguous();
10
+ }
11
+ else {
12
+ this.select();
13
+ this.activate();
14
+ }
15
+ };
16
+ this.tree = params.tree;
17
+ this.id = params.id;
18
+ this.data = params.data;
19
+ this.level = params.level;
20
+ this.children = params.children;
21
+ this.parent = params.parent;
22
+ this.isDraggable = params.isDraggable;
23
+ this.rowIndex = params.rowIndex;
24
+ }
25
+ get isRoot() {
26
+ return this.id === ROOT_ID;
27
+ }
28
+ get isLeaf() {
29
+ return !Array.isArray(this.children);
30
+ }
31
+ get isInternal() {
32
+ return !this.isLeaf;
33
+ }
34
+ get isOpen() {
35
+ return this.isLeaf ? false : this.tree.isOpen(this.id);
36
+ }
37
+ get isClosed() {
38
+ return this.isLeaf ? false : !this.tree.isOpen(this.id);
39
+ }
40
+ get isEditable() {
41
+ return this.tree.isEditable(this.data);
42
+ }
43
+ get isEditing() {
44
+ return this.tree.editingId === this.id;
45
+ }
46
+ get isSelected() {
47
+ return this.tree.isSelected(this.id);
48
+ }
49
+ get isOnlySelection() {
50
+ return this.isSelected && this.tree.hasOneSelection;
51
+ }
52
+ get isSelectedStart() {
53
+ var _a;
54
+ return this.isSelected && !((_a = this.prev) === null || _a === void 0 ? void 0 : _a.isSelected);
55
+ }
56
+ get isSelectedEnd() {
57
+ var _a;
58
+ return this.isSelected && !((_a = this.next) === null || _a === void 0 ? void 0 : _a.isSelected);
59
+ }
60
+ get isFocused() {
61
+ return this.tree.isFocused(this.id);
62
+ }
63
+ get isDragging() {
64
+ return this.tree.isDragging(this.id);
65
+ }
66
+ get willReceiveDrop() {
67
+ return this.tree.willReceiveDrop(this.id);
68
+ }
69
+ get state() {
70
+ return {
71
+ isClosed: this.isClosed,
72
+ isDragging: this.isDragging,
73
+ isEditing: this.isEditing,
74
+ isFocused: this.isFocused,
75
+ isInternal: this.isInternal,
76
+ isLeaf: this.isLeaf,
77
+ isOpen: this.isOpen,
78
+ isSelected: this.isSelected,
79
+ isSelectedEnd: this.isSelectedEnd,
80
+ isSelectedStart: this.isSelectedStart,
81
+ willReceiveDrop: this.willReceiveDrop,
82
+ };
83
+ }
84
+ get childIndex() {
85
+ if (this.parent && this.parent.children) {
86
+ return this.parent.children.findIndex((child) => child.id === this.id);
87
+ }
88
+ else {
89
+ return -1;
90
+ }
91
+ }
92
+ get next() {
93
+ if (this.rowIndex === null)
94
+ return null;
95
+ return this.tree.at(this.rowIndex + 1);
96
+ }
97
+ get prev() {
98
+ if (this.rowIndex === null)
99
+ return null;
100
+ return this.tree.at(this.rowIndex - 1);
101
+ }
102
+ get nextSibling() {
103
+ var _a, _b;
104
+ const i = this.childIndex;
105
+ return (_b = (_a = this.parent) === null || _a === void 0 ? void 0 : _a.children[i + 1]) !== null && _b !== void 0 ? _b : null;
106
+ }
107
+ isAncestorOf(node) {
108
+ if (!node)
109
+ return false;
110
+ let ancestor = node;
111
+ while (ancestor) {
112
+ if (ancestor.id === this.id)
113
+ return true;
114
+ ancestor = ancestor.parent;
115
+ }
116
+ return false;
117
+ }
118
+ select() {
119
+ this.tree.select(this);
120
+ }
121
+ deselect() {
122
+ this.tree.deselect(this);
123
+ }
124
+ selectMulti() {
125
+ this.tree.selectMulti(this);
126
+ }
127
+ selectContiguous() {
128
+ this.tree.selectContiguous(this);
129
+ }
130
+ activate() {
131
+ this.tree.activate(this);
132
+ }
133
+ focus() {
134
+ this.tree.focus(this);
135
+ }
136
+ toggle() {
137
+ this.tree.toggle(this);
138
+ }
139
+ open() {
140
+ this.tree.open(this);
141
+ }
142
+ openParents() {
143
+ this.tree.openParents(this);
144
+ }
145
+ close() {
146
+ this.tree.close(this);
147
+ }
148
+ submit(value) {
149
+ this.tree.submit(this, value);
150
+ }
151
+ reset() {
152
+ this.tree.reset();
153
+ }
154
+ clone() {
155
+ return new NodeApi(Object.assign({}, this));
156
+ }
157
+ edit() {
158
+ return this.tree.edit(this);
159
+ }
160
+ }