@headless-tree/core 0.0.14 → 0.0.15

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 (125) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/lib/cjs/core/create-tree.js +13 -4
  3. package/lib/cjs/features/async-data-loader/feature.js +73 -48
  4. package/lib/cjs/features/async-data-loader/types.d.ts +17 -14
  5. package/lib/cjs/features/drag-and-drop/feature.js +98 -93
  6. package/lib/cjs/features/drag-and-drop/types.d.ts +17 -29
  7. package/lib/cjs/features/drag-and-drop/types.js +7 -7
  8. package/lib/cjs/features/drag-and-drop/utils.d.ts +18 -3
  9. package/lib/cjs/features/drag-and-drop/utils.js +49 -51
  10. package/lib/cjs/features/expand-all/feature.js +26 -3
  11. package/lib/cjs/features/expand-all/types.d.ts +3 -1
  12. package/lib/cjs/features/hotkeys-core/feature.js +7 -3
  13. package/lib/cjs/features/hotkeys-core/types.d.ts +4 -5
  14. package/lib/cjs/features/keyboard-drag-and-drop/feature.d.ts +2 -0
  15. package/lib/cjs/features/keyboard-drag-and-drop/feature.js +207 -0
  16. package/lib/cjs/features/keyboard-drag-and-drop/types.d.ts +27 -0
  17. package/lib/cjs/features/keyboard-drag-and-drop/types.js +11 -0
  18. package/lib/cjs/features/prop-memoization/feature.js +2 -2
  19. package/lib/cjs/features/prop-memoization/types.d.ts +2 -2
  20. package/lib/cjs/features/renaming/feature.js +1 -1
  21. package/lib/cjs/features/search/feature.js +2 -0
  22. package/lib/cjs/features/search/types.d.ts +2 -2
  23. package/lib/cjs/features/selection/feature.js +4 -4
  24. package/lib/cjs/features/selection/types.d.ts +1 -1
  25. package/lib/cjs/features/sync-data-loader/feature.js +31 -5
  26. package/lib/cjs/features/sync-data-loader/types.d.ts +5 -5
  27. package/lib/cjs/features/tree/feature.js +4 -7
  28. package/lib/cjs/features/tree/types.d.ts +7 -5
  29. package/lib/cjs/index.d.ts +2 -0
  30. package/lib/cjs/index.js +2 -0
  31. package/lib/cjs/mddocs-entry.d.ts +10 -0
  32. package/lib/cjs/test-utils/test-tree-do.d.ts +2 -2
  33. package/lib/cjs/test-utils/test-tree-do.js +19 -6
  34. package/lib/cjs/test-utils/test-tree-expect.d.ts +5 -3
  35. package/lib/cjs/test-utils/test-tree-expect.js +3 -0
  36. package/lib/cjs/test-utils/test-tree.d.ts +2 -1
  37. package/lib/cjs/test-utils/test-tree.js +24 -21
  38. package/lib/cjs/types/core.d.ts +2 -1
  39. package/lib/cjs/utilities/create-on-drop-handler.d.ts +2 -2
  40. package/lib/cjs/utilities/create-on-drop-handler.js +13 -4
  41. package/lib/cjs/utilities/insert-items-at-target.d.ts +2 -2
  42. package/lib/cjs/utilities/insert-items-at-target.js +21 -12
  43. package/lib/cjs/utilities/remove-items-from-parents.d.ts +1 -1
  44. package/lib/cjs/utilities/remove-items-from-parents.js +12 -3
  45. package/lib/esm/core/create-tree.js +13 -4
  46. package/lib/esm/features/async-data-loader/feature.js +73 -48
  47. package/lib/esm/features/async-data-loader/types.d.ts +17 -14
  48. package/lib/esm/features/drag-and-drop/feature.js +99 -94
  49. package/lib/esm/features/drag-and-drop/types.d.ts +17 -29
  50. package/lib/esm/features/drag-and-drop/types.js +6 -6
  51. package/lib/esm/features/drag-and-drop/utils.d.ts +18 -3
  52. package/lib/esm/features/drag-and-drop/utils.js +44 -49
  53. package/lib/esm/features/expand-all/feature.js +26 -3
  54. package/lib/esm/features/expand-all/types.d.ts +3 -1
  55. package/lib/esm/features/hotkeys-core/feature.js +7 -3
  56. package/lib/esm/features/hotkeys-core/types.d.ts +4 -5
  57. package/lib/esm/features/keyboard-drag-and-drop/feature.d.ts +2 -0
  58. package/lib/esm/features/keyboard-drag-and-drop/feature.js +204 -0
  59. package/lib/esm/features/keyboard-drag-and-drop/types.d.ts +27 -0
  60. package/lib/esm/features/keyboard-drag-and-drop/types.js +8 -0
  61. package/lib/esm/features/prop-memoization/feature.js +2 -2
  62. package/lib/esm/features/prop-memoization/types.d.ts +2 -2
  63. package/lib/esm/features/renaming/feature.js +1 -1
  64. package/lib/esm/features/search/feature.js +2 -0
  65. package/lib/esm/features/search/types.d.ts +2 -2
  66. package/lib/esm/features/selection/feature.js +4 -4
  67. package/lib/esm/features/selection/types.d.ts +1 -1
  68. package/lib/esm/features/sync-data-loader/feature.js +31 -5
  69. package/lib/esm/features/sync-data-loader/types.d.ts +5 -5
  70. package/lib/esm/features/tree/feature.js +4 -7
  71. package/lib/esm/features/tree/types.d.ts +7 -5
  72. package/lib/esm/index.d.ts +2 -0
  73. package/lib/esm/index.js +2 -0
  74. package/lib/esm/mddocs-entry.d.ts +10 -0
  75. package/lib/esm/test-utils/test-tree-do.d.ts +2 -2
  76. package/lib/esm/test-utils/test-tree-do.js +19 -6
  77. package/lib/esm/test-utils/test-tree-expect.d.ts +5 -3
  78. package/lib/esm/test-utils/test-tree-expect.js +3 -0
  79. package/lib/esm/test-utils/test-tree.d.ts +2 -1
  80. package/lib/esm/test-utils/test-tree.js +24 -21
  81. package/lib/esm/types/core.d.ts +2 -1
  82. package/lib/esm/utilities/create-on-drop-handler.d.ts +2 -2
  83. package/lib/esm/utilities/create-on-drop-handler.js +13 -4
  84. package/lib/esm/utilities/insert-items-at-target.d.ts +2 -2
  85. package/lib/esm/utilities/insert-items-at-target.js +21 -12
  86. package/lib/esm/utilities/remove-items-from-parents.d.ts +1 -1
  87. package/lib/esm/utilities/remove-items-from-parents.js +12 -3
  88. package/package.json +2 -2
  89. package/src/core/core.spec.ts +31 -0
  90. package/src/core/create-tree.ts +15 -5
  91. package/src/features/async-data-loader/async-data-loader.spec.ts +10 -6
  92. package/src/features/async-data-loader/feature.ts +76 -48
  93. package/src/features/async-data-loader/types.ts +18 -11
  94. package/src/features/drag-and-drop/drag-and-drop.spec.ts +75 -89
  95. package/src/features/drag-and-drop/feature.ts +21 -22
  96. package/src/features/drag-and-drop/types.ts +23 -35
  97. package/src/features/drag-and-drop/utils.ts +67 -57
  98. package/src/features/expand-all/feature.ts +29 -5
  99. package/src/features/expand-all/types.ts +3 -1
  100. package/src/features/hotkeys-core/feature.ts +4 -0
  101. package/src/features/hotkeys-core/types.ts +4 -13
  102. package/src/features/keyboard-drag-and-drop/feature.ts +255 -0
  103. package/src/features/keyboard-drag-and-drop/keyboard-drag-and-drop.spec.ts +401 -0
  104. package/src/features/keyboard-drag-and-drop/types.ts +30 -0
  105. package/src/features/prop-memoization/feature.ts +2 -2
  106. package/src/features/prop-memoization/prop-memoization.spec.ts +2 -2
  107. package/src/features/prop-memoization/types.ts +2 -2
  108. package/src/features/renaming/feature.ts +8 -2
  109. package/src/features/search/feature.ts +2 -0
  110. package/src/features/search/types.ts +2 -2
  111. package/src/features/selection/feature.ts +4 -4
  112. package/src/features/selection/types.ts +1 -1
  113. package/src/features/sync-data-loader/feature.ts +26 -7
  114. package/src/features/sync-data-loader/types.ts +5 -5
  115. package/src/features/tree/feature.ts +8 -11
  116. package/src/features/tree/types.ts +7 -5
  117. package/src/index.ts +2 -0
  118. package/src/mddocs-entry.ts +16 -0
  119. package/src/test-utils/test-tree-do.ts +3 -3
  120. package/src/test-utils/test-tree-expect.ts +7 -2
  121. package/src/test-utils/test-tree.ts +26 -22
  122. package/src/types/core.ts +2 -0
  123. package/src/utilities/create-on-drop-handler.ts +4 -4
  124. package/src/utilities/insert-items-at-target.ts +18 -14
  125. package/src/utilities/remove-items-from-parents.ts +6 -3
@@ -1,81 +1,106 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  import { makeStateUpdater } from "../../utils";
2
11
  export const asyncDataLoaderFeature = {
3
12
  key: "async-data-loader",
4
- getInitialState: (initialState) => (Object.assign({ loadingItems: [] }, initialState)),
5
- getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setLoadingItems: makeStateUpdater("loadingItems", tree) }, defaultConfig)),
13
+ getInitialState: (initialState) => (Object.assign({ loadingItemData: [], loadingItemChildrens: [] }, initialState)),
14
+ getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setLoadingItemData: makeStateUpdater("loadingItemData", tree), setLoadingItemChildrens: makeStateUpdater("loadingItemChildrens", tree) }, defaultConfig)),
6
15
  stateHandlerNames: {
7
- loadingItems: "setLoadingItems",
16
+ loadingItemData: "setLoadingItemData",
17
+ loadingItemChildrens: "setLoadingItemChildrens",
8
18
  },
9
19
  treeInstance: {
20
+ waitForItemDataLoaded: (_a, itemId_1) => __awaiter(void 0, [_a, itemId_1], void 0, function* ({ tree }, itemId) {
21
+ tree.retrieveItemData(itemId);
22
+ if (!tree.getState().loadingItemData.includes(itemId)) {
23
+ return;
24
+ }
25
+ yield new Promise((resolve) => {
26
+ var _a, _b;
27
+ var _c, _d;
28
+ const dataRef = tree.getDataRef();
29
+ (_a = (_c = dataRef.current).awaitingItemDataLoading) !== null && _a !== void 0 ? _a : (_c.awaitingItemDataLoading = {});
30
+ (_b = (_d = dataRef.current.awaitingItemDataLoading)[itemId]) !== null && _b !== void 0 ? _b : (_d[itemId] = []);
31
+ dataRef.current.awaitingItemDataLoading[itemId].push(resolve);
32
+ });
33
+ }),
34
+ waitForItemChildrenLoaded: (_a, itemId_1) => __awaiter(void 0, [_a, itemId_1], void 0, function* ({ tree }, itemId) {
35
+ tree.retrieveChildrenIds(itemId);
36
+ if (!tree.getState().loadingItemChildrens.includes(itemId)) {
37
+ return;
38
+ }
39
+ yield new Promise((resolve) => {
40
+ var _a, _b;
41
+ var _c, _d;
42
+ const dataRef = tree.getDataRef();
43
+ (_a = (_c = dataRef.current).awaitingItemChildrensLoading) !== null && _a !== void 0 ? _a : (_c.awaitingItemChildrensLoading = {});
44
+ (_b = (_d = dataRef.current.awaitingItemChildrensLoading)[itemId]) !== null && _b !== void 0 ? _b : (_d[itemId] = []);
45
+ dataRef.current.awaitingItemChildrensLoading[itemId].push(resolve);
46
+ });
47
+ }),
10
48
  retrieveItemData: ({ tree }, itemId) => {
11
- var _a, _b, _c, _d, _e;
12
- var _f, _g;
49
+ var _a, _b, _c, _d;
50
+ var _e, _f;
13
51
  const config = tree.getConfig();
14
52
  const dataRef = tree.getDataRef();
15
- (_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_f.itemData = {});
16
- (_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_g.childrenIds = {});
53
+ (_a = (_e = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_e.itemData = {});
54
+ (_b = (_f = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_f.childrenIds = {});
17
55
  if (dataRef.current.itemData[itemId]) {
18
56
  return dataRef.current.itemData[itemId];
19
57
  }
20
- if (!tree.getState().loadingItems.includes(itemId)) {
21
- tree.applySubStateUpdate("loadingItems", (loadingItems) => [
22
- ...loadingItems,
58
+ if (!tree.getState().loadingItemData.includes(itemId)) {
59
+ tree.applySubStateUpdate("loadingItemData", (loadingItemData) => [
60
+ ...loadingItemData,
23
61
  itemId,
24
62
  ]);
25
- (_c = config.asyncDataLoader) === null || _c === void 0 ? void 0 : _c.getItem(itemId).then((item) => {
26
- var _a;
63
+ (() => __awaiter(void 0, void 0, void 0, function* () {
64
+ var _a, _b, _c;
65
+ const item = yield config.dataLoader.getItem(itemId);
27
66
  dataRef.current.itemData[itemId] = item;
28
67
  (_a = config.onLoadedItem) === null || _a === void 0 ? void 0 : _a.call(config, itemId, item);
29
- tree.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
30
- });
68
+ tree.applySubStateUpdate("loadingItemData", (loadingItemData) => loadingItemData.filter((id) => id !== itemId));
69
+ (_b = dataRef.current.awaitingItemDataLoading) === null || _b === void 0 ? void 0 : _b[itemId].forEach((cb) => cb());
70
+ (_c = dataRef.current.awaitingItemDataLoading) === null || _c === void 0 ? true : delete _c[itemId];
71
+ }))();
31
72
  }
32
- return (_e = (_d = config.createLoadingItemData) === null || _d === void 0 ? void 0 : _d.call(config)) !== null && _e !== void 0 ? _e : null;
73
+ return (_d = (_c = config.createLoadingItemData) === null || _c === void 0 ? void 0 : _c.call(config)) !== null && _d !== void 0 ? _d : null;
33
74
  },
34
75
  retrieveChildrenIds: ({ tree }, itemId) => {
35
- var _a, _b, _c, _d, _e;
36
- var _f, _g;
76
+ var _a;
77
+ var _b;
37
78
  const config = tree.getConfig();
38
79
  const dataRef = tree.getDataRef();
39
- (_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_f.itemData = {});
40
- (_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_g.childrenIds = {});
80
+ (_a = (_b = dataRef.current).childrenIds) !== null && _a !== void 0 ? _a : (_b.childrenIds = {});
41
81
  if (dataRef.current.childrenIds[itemId]) {
42
82
  return dataRef.current.childrenIds[itemId];
43
83
  }
44
- if (tree.getState().loadingItems.includes(itemId)) {
84
+ if (tree.getState().loadingItemChildrens.includes(itemId)) {
45
85
  return [];
46
86
  }
47
- tree.applySubStateUpdate("loadingItems", (loadingItems) => [
48
- ...loadingItems,
49
- itemId,
50
- ]);
51
- if ((_c = config.asyncDataLoader) === null || _c === void 0 ? void 0 : _c.getChildrenWithData) {
52
- (_d = config.asyncDataLoader) === null || _d === void 0 ? void 0 : _d.getChildrenWithData(itemId).then((children) => {
53
- var _a, _b;
54
- for (const { id, data } of children) {
55
- dataRef.current.itemData[id] = data;
56
- (_a = config.onLoadedItem) === null || _a === void 0 ? void 0 : _a.call(config, id, data);
57
- }
58
- const childrenIds = children.map(({ id }) => id);
59
- dataRef.current.childrenIds[itemId] = childrenIds;
60
- (_b = config.onLoadedChildren) === null || _b === void 0 ? void 0 : _b.call(config, itemId, childrenIds);
61
- tree.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
62
- tree.rebuildTree();
63
- });
64
- }
65
- else {
66
- (_e = config.asyncDataLoader) === null || _e === void 0 ? void 0 : _e.getChildren(itemId).then((childrenIds) => {
67
- var _a;
68
- dataRef.current.childrenIds[itemId] = childrenIds;
69
- (_a = config.onLoadedChildren) === null || _a === void 0 ? void 0 : _a.call(config, itemId, childrenIds);
70
- tree.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
71
- tree.rebuildTree();
72
- });
73
- }
87
+ tree.applySubStateUpdate("loadingItemChildrens", (loadingItemChildrens) => [...loadingItemChildrens, itemId]);
88
+ (() => __awaiter(void 0, void 0, void 0, function* () {
89
+ var _a, _b, _c, _d;
90
+ const childrenIds = yield config.dataLoader.getChildren(itemId);
91
+ dataRef.current.childrenIds[itemId] = childrenIds;
92
+ (_a = config.onLoadedChildren) === null || _a === void 0 ? void 0 : _a.call(config, itemId, childrenIds);
93
+ tree.applySubStateUpdate("loadingItemChildrens", (loadingItemChildrens) => loadingItemChildrens.filter((id) => id !== itemId));
94
+ tree.rebuildTree();
95
+ (_c = (_b = dataRef.current.awaitingItemChildrensLoading) === null || _b === void 0 ? void 0 : _b[itemId]) === null || _c === void 0 ? void 0 : _c.forEach((cb) => cb());
96
+ (_d = dataRef.current.awaitingItemChildrensLoading) === null || _d === void 0 ? true : delete _d[itemId];
97
+ }))();
74
98
  return [];
75
99
  },
76
100
  },
77
101
  itemInstance: {
78
- isLoading: ({ tree, item }) => tree.getState().loadingItems.includes(item.getItemMeta().itemId),
102
+ isLoading: ({ tree, item }) => tree.getState().loadingItemData.includes(item.getItemMeta().itemId) ||
103
+ tree.getState().loadingItemChildrens.includes(item.getItemMeta().itemId),
79
104
  invalidateItemData: ({ tree, itemId }) => {
80
105
  var _a;
81
106
  const dataRef = tree.getDataRef();
@@ -1,33 +1,35 @@
1
1
  import { SetStateFn } from "../../types/core";
2
2
  import { SyncDataLoaderFeatureDef } from "../sync-data-loader/types";
3
- export type AsyncTreeDataLoader<T> = {
4
- getItem: (itemId: string) => Promise<T>;
5
- getChildren: (itemId: string) => Promise<string[]>;
6
- getChildrenWithData?: (itemId: string) => Promise<{
7
- id: string;
8
- data: T;
9
- }[]>;
10
- };
11
- export type AsyncDataLoaderRef<T = any> = {
3
+ type AwaitingLoaderCallbacks = Record<string, (() => void)[]>;
4
+ export interface AsyncDataLoaderDataRef<T = any> {
12
5
  itemData: Record<string, T>;
13
6
  childrenIds: Record<string, string[]>;
14
- };
7
+ awaitingItemDataLoading: AwaitingLoaderCallbacks;
8
+ awaitingItemChildrensLoading: AwaitingLoaderCallbacks;
9
+ }
15
10
  /**
16
11
  * @category Async Data Loader/General
17
12
  * */
18
13
  export type AsyncDataLoaderFeatureDef<T> = {
19
14
  state: {
20
- loadingItems: string[];
15
+ loadingItemData: string[];
16
+ loadingItemChildrens: string[];
21
17
  };
22
18
  config: {
23
19
  rootItemId: string;
20
+ /** Will be called when HT retrieves item data for an item whose item data is asynchronously being loaded.
21
+ * Can be used to create placeholder data to use for rendering the tree item while it is loaded. If not defined,
22
+ * the tree item data will be null. */
24
23
  createLoadingItemData?: () => T;
25
- setLoadingItems?: SetStateFn<string[]>;
24
+ setLoadingItemData?: SetStateFn<string[]>;
25
+ setLoadingItemChildrens?: SetStateFn<string[]>;
26
26
  onLoadedItem?: (itemId: string, item: T) => void;
27
27
  onLoadedChildren?: (itemId: string, childrenIds: string[]) => void;
28
- asyncDataLoader?: AsyncTreeDataLoader<T>;
29
28
  };
30
- treeInstance: SyncDataLoaderFeatureDef<T>["treeInstance"];
29
+ treeInstance: SyncDataLoaderFeatureDef<T>["treeInstance"] & {
30
+ waitForItemDataLoaded: (itemId: string) => Promise<void>;
31
+ waitForItemChildrenLoaded: (itemId: string) => Promise<void>;
32
+ };
31
33
  itemInstance: SyncDataLoaderFeatureDef<T>["itemInstance"] & {
32
34
  /** Invalidate fetched data for item, and triggers a refetch and subsequent rerender if the item is visible */
33
35
  invalidateItemData: () => void;
@@ -37,3 +39,4 @@ export type AsyncDataLoaderFeatureDef<T> = {
37
39
  };
38
40
  hotkeys: SyncDataLoaderFeatureDef<T>["hotkeys"];
39
41
  };
42
+ export {};
@@ -1,4 +1,13 @@
1
- import { canDrop, getDragCode, getDropTarget } from "./utils";
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { canDrop, getDragCode, getDragTarget } from "./utils";
2
11
  import { makeStateUpdater } from "../../utils";
3
12
  export const dragAndDropFeature = {
4
13
  key: "drag-and-drop",
@@ -8,16 +17,16 @@ export const dragAndDropFeature = {
8
17
  dnd: "setDndState",
9
18
  },
10
19
  treeInstance: {
11
- getDropTarget: ({ tree }) => {
20
+ getDragTarget: ({ tree }) => {
12
21
  var _a, _b;
13
22
  return (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.dragTarget) !== null && _b !== void 0 ? _b : null;
14
23
  },
15
24
  getDragLineData: ({ tree }) => {
16
25
  var _a, _b, _c, _d, _e, _f;
17
- const target = tree.getDropTarget();
26
+ const target = tree.getDragTarget();
18
27
  const indent = ((_a = target === null || target === void 0 ? void 0 : target.item.getItemMeta().level) !== null && _a !== void 0 ? _a : 0) + 1;
19
28
  const treeBb = (_b = tree.getElement()) === null || _b === void 0 ? void 0 : _b.getBoundingClientRect();
20
- if (!target || !treeBb || target.childIndex === null)
29
+ if (!target || !treeBb || !("childIndex" in target))
21
30
  return null;
22
31
  const leftOffset = target.dragLineLevel * ((_c = tree.getConfig().indent) !== null && _c !== void 0 ? _c : 1);
23
32
  const targetItem = tree.getItems()[target.dragLineIndex];
@@ -27,7 +36,7 @@ export const dragAndDropFeature = {
27
36
  if (bb) {
28
37
  return {
29
38
  indent,
30
- top: bb.bottom - treeBb.bottom,
39
+ top: bb.bottom - treeBb.top,
31
40
  left: bb.left + leftOffset - treeBb.left,
32
41
  width: bb.width - leftOffset,
33
42
  };
@@ -55,109 +64,105 @@ export const dragAndDropFeature = {
55
64
  }
56
65
  : { display: "none" };
57
66
  },
58
- getContainerProps: ({ prev }) => {
59
- const prevProps = prev === null || prev === void 0 ? void 0 : prev();
67
+ getContainerProps: ({ prev }, treeLabel) => {
68
+ const prevProps = prev === null || prev === void 0 ? void 0 : prev(treeLabel);
60
69
  return Object.assign(Object.assign({}, prevProps), { style: Object.assign(Object.assign({}, prevProps === null || prevProps === void 0 ? void 0 : prevProps.style), { position: "relative" }) });
61
70
  },
62
71
  },
63
72
  itemInstance: {
64
- getProps: ({ tree, item, prev }) => {
65
- var _a, _b, _c;
66
- return (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { draggable: (_c = (_b = (_a = tree.getConfig()).isItemDraggable) === null || _b === void 0 ? void 0 : _b.call(_a, item)) !== null && _c !== void 0 ? _c : true, onDragStart: (e) => {
67
- var _a, _b, _c;
68
- const selectedItems = tree.getSelectedItems();
69
- const items = selectedItems.includes(item) ? selectedItems : [item];
70
- const config = tree.getConfig();
71
- if (!selectedItems.includes(item)) {
72
- tree.setSelectedItems([item.getItemMeta().itemId]);
73
- }
74
- if (!((_b = (_a = config.canDrag) === null || _a === void 0 ? void 0 : _a.call(config, items)) !== null && _b !== void 0 ? _b : true)) {
75
- e.preventDefault();
76
- return;
77
- }
78
- if (config.createForeignDragObject) {
79
- const { format, data } = config.createForeignDragObject(items);
80
- (_c = e.dataTransfer) === null || _c === void 0 ? void 0 : _c.setData(format, data);
81
- }
82
- tree.applySubStateUpdate("dnd", {
83
- draggedItems: items,
84
- draggingOverItem: tree.getFocusedItem(),
85
- });
86
- }, onDragOver: (e) => {
87
- var _a, _b, _c;
88
- const dataRef = tree.getDataRef();
89
- const nextDragCode = getDragCode(e, item, tree);
90
- if (nextDragCode === dataRef.current.lastDragCode) {
91
- if (dataRef.current.lastAllowDrop) {
92
- e.preventDefault();
93
- }
94
- return;
95
- }
96
- dataRef.current.lastDragCode = nextDragCode;
97
- const target = getDropTarget(e, item, tree);
98
- if (!((_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) &&
99
- (!e.dataTransfer ||
100
- !((_c = (_b = tree
101
- .getConfig()).canDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(_b, e.dataTransfer, target)))) {
102
- dataRef.current.lastAllowDrop = false;
103
- return;
104
- }
105
- if (!canDrop(e.dataTransfer, target, tree)) {
106
- dataRef.current.lastAllowDrop = false;
107
- return;
108
- }
109
- tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { dragTarget: target, draggingOverItem: item })));
110
- dataRef.current.lastAllowDrop = true;
111
- e.preventDefault();
112
- }, onDragLeave: () => {
113
- const dataRef = tree.getDataRef();
114
- dataRef.current.lastDragCode = "no-drag";
115
- tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { draggingOverItem: undefined, dragTarget: undefined })));
116
- }, onDragEnd: (e) => {
117
- var _a, _b, _c, _d;
118
- const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
119
- tree.applySubStateUpdate("dnd", null);
120
- if (((_b = e.dataTransfer) === null || _b === void 0 ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
121
- return;
122
- }
123
- (_d = (_c = tree.getConfig()).onCompleteForeignDrop) === null || _d === void 0 ? void 0 : _d.call(_c, draggedItems);
124
- }, onDrop: (e) => {
125
- var _a, _b, _c;
126
- const dataRef = tree.getDataRef();
127
- const target = getDropTarget(e, item, tree);
128
- if (!canDrop(e.dataTransfer, target, tree)) {
129
- return;
130
- }
73
+ getProps: ({ tree, item, prev }) => (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { draggable: true, onDragStart: (e) => {
74
+ var _a, _b, _c;
75
+ const selectedItems = tree.getSelectedItems();
76
+ const items = selectedItems.includes(item) ? selectedItems : [item];
77
+ const config = tree.getConfig();
78
+ if (!selectedItems.includes(item)) {
79
+ tree.setSelectedItems([item.getItemMeta().itemId]);
80
+ }
81
+ if (!((_b = (_a = config.canDrag) === null || _a === void 0 ? void 0 : _a.call(config, items)) !== null && _b !== void 0 ? _b : true)) {
131
82
  e.preventDefault();
132
- const config = tree.getConfig();
133
- const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
134
- dataRef.current.lastDragCode = undefined;
135
- tree.applySubStateUpdate("dnd", null);
136
- if (draggedItems) {
137
- (_b = config.onDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target);
138
- }
139
- else if (e.dataTransfer) {
140
- (_c = config.onDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(config, e.dataTransfer, target);
83
+ return;
84
+ }
85
+ if (config.createForeignDragObject) {
86
+ const { format, data } = config.createForeignDragObject(items);
87
+ (_c = e.dataTransfer) === null || _c === void 0 ? void 0 : _c.setData(format, data);
88
+ }
89
+ tree.applySubStateUpdate("dnd", {
90
+ draggedItems: items,
91
+ draggingOverItem: tree.getFocusedItem(),
92
+ });
93
+ }, onDragOver: (e) => {
94
+ var _a, _b, _c;
95
+ const dataRef = tree.getDataRef();
96
+ const nextDragCode = getDragCode(e, item, tree);
97
+ if (nextDragCode === dataRef.current.lastDragCode) {
98
+ if (dataRef.current.lastAllowDrop) {
99
+ e.preventDefault();
141
100
  }
142
- // TODO rebuild tree?
143
- } }));
144
- },
145
- isDropTarget: ({ tree, item }) => {
146
- const target = tree.getDropTarget();
101
+ return;
102
+ }
103
+ dataRef.current.lastDragCode = nextDragCode;
104
+ const target = getDragTarget(e, item, tree);
105
+ if (!((_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) &&
106
+ (!e.dataTransfer ||
107
+ !((_c = (_b = tree
108
+ .getConfig()).canDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(_b, e.dataTransfer, target)))) {
109
+ dataRef.current.lastAllowDrop = false;
110
+ return;
111
+ }
112
+ if (!canDrop(e.dataTransfer, target, tree)) {
113
+ dataRef.current.lastAllowDrop = false;
114
+ return;
115
+ }
116
+ tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { dragTarget: target, draggingOverItem: item })));
117
+ dataRef.current.lastAllowDrop = true;
118
+ e.preventDefault();
119
+ }, onDragLeave: () => {
120
+ const dataRef = tree.getDataRef();
121
+ dataRef.current.lastDragCode = "no-drag";
122
+ tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { draggingOverItem: undefined, dragTarget: undefined })));
123
+ }, onDragEnd: (e) => {
124
+ var _a, _b, _c, _d;
125
+ const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
126
+ tree.applySubStateUpdate("dnd", null);
127
+ if (((_b = e.dataTransfer) === null || _b === void 0 ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
128
+ return;
129
+ }
130
+ (_d = (_c = tree.getConfig()).onCompleteForeignDrop) === null || _d === void 0 ? void 0 : _d.call(_c, draggedItems);
131
+ }, onDrop: (e) => __awaiter(void 0, void 0, void 0, function* () {
132
+ var _a, _b, _c;
133
+ const dataRef = tree.getDataRef();
134
+ const target = getDragTarget(e, item, tree);
135
+ if (!canDrop(e.dataTransfer, target, tree)) {
136
+ return;
137
+ }
138
+ e.preventDefault();
139
+ const config = tree.getConfig();
140
+ const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
141
+ dataRef.current.lastDragCode = undefined;
142
+ tree.applySubStateUpdate("dnd", null);
143
+ if (draggedItems) {
144
+ yield ((_b = config.onDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target));
145
+ }
146
+ else if (e.dataTransfer) {
147
+ yield ((_c = config.onDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(config, e.dataTransfer, target));
148
+ }
149
+ }) })),
150
+ isDragTarget: ({ tree, item }) => {
151
+ const target = tree.getDragTarget();
147
152
  return target ? target.item.getId() === item.getId() : false;
148
153
  },
149
- isDropTargetAbove: ({ tree, item }) => {
150
- const target = tree.getDropTarget();
154
+ isDragTargetAbove: ({ tree, item }) => {
155
+ const target = tree.getDragTarget();
151
156
  if (!target ||
152
- target.childIndex === null ||
157
+ !("childIndex" in target) ||
153
158
  target.item !== item.getParent())
154
159
  return false;
155
160
  return target.childIndex === item.getItemMeta().posInSet;
156
161
  },
157
- isDropTargetBelow: ({ tree, item }) => {
158
- const target = tree.getDropTarget();
162
+ isDragTargetBelow: ({ tree, item }) => {
163
+ const target = tree.getDragTarget();
159
164
  if (!target ||
160
- target.childIndex === null ||
165
+ !("childIndex" in target) ||
161
166
  target.item !== item.getParent())
162
167
  return false;
163
168
  return target.childIndex - 1 === item.getItemMeta().posInSet;
@@ -1,20 +1,20 @@
1
1
  import { ItemInstance, SetStateFn } from "../../types/core";
2
- export type DndDataRef = {
2
+ export interface DndDataRef {
3
3
  lastDragCode?: string;
4
4
  lastAllowDrop?: boolean;
5
- };
6
- export type DndState<T> = {
5
+ }
6
+ export interface DndState<T> {
7
7
  draggedItems?: ItemInstance<T>[];
8
8
  draggingOverItem?: ItemInstance<T>;
9
- dragTarget?: DropTarget<T>;
10
- };
11
- export type DragLineData = {
9
+ dragTarget?: DragTarget<T>;
10
+ }
11
+ export interface DragLineData {
12
12
  indent: number;
13
13
  top: number;
14
14
  left: number;
15
15
  width: number;
16
- };
17
- export type DropTarget<T> = {
16
+ }
17
+ export type DragTarget<T> = {
18
18
  item: ItemInstance<T>;
19
19
  childIndex: number;
20
20
  insertionIndex: number;
@@ -22,12 +22,8 @@ export type DropTarget<T> = {
22
22
  dragLineLevel: number;
23
23
  } | {
24
24
  item: ItemInstance<T>;
25
- childIndex: null;
26
- insertionIndex: null;
27
- dragLineIndex: null;
28
- dragLineLevel: null;
29
25
  };
30
- export declare enum DropTargetPosition {
26
+ export declare enum DragTargetPosition {
31
27
  Top = "top",
32
28
  Bottom = "bottom",
33
29
  Item = "item"
@@ -43,35 +39,27 @@ export type DragAndDropFeatureDef<T> = {
43
39
  * If `canReorder` is `false`, this is ignored. */
44
40
  reorderAreaPercentage?: number;
45
41
  canReorder?: boolean;
46
- isItemDraggable?: (item: ItemInstance<T>) => boolean;
47
42
  canDrag?: (items: ItemInstance<T>[]) => boolean;
48
- canDrop?: (items: ItemInstance<T>[], target: DropTarget<T>) => boolean;
43
+ canDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => boolean;
49
44
  indent?: number;
50
45
  createForeignDragObject?: (items: ItemInstance<T>[]) => {
51
46
  format: string;
52
47
  data: any;
53
48
  };
54
- canDropForeignDragObject?: (dataTransfer: DataTransfer, target: DropTarget<T>) => boolean;
55
- onDrop?: (items: ItemInstance<T>[], target: DropTarget<T>) => void;
56
- onDropForeignDragObject?: (dataTransfer: DataTransfer, target: DropTarget<T>) => void;
57
- /** Runs in the onDragEnd event, if `ev.dataTransfer.dropEffect` is not `none`, i.e. the drop
58
- * was not aborted. No target is provided as parameter since the target may be a foreign drop target.
59
- * This is useful to seperate out the logic to move dragged items out of their previous parents.
60
- * Use `onDrop` to handle drop-related logic.
61
- *
62
- * This ignores the `canDrop` handler, since the drop target is unknown in this handler.
63
- */
49
+ canDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => boolean;
50
+ onDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => void | Promise<void>;
51
+ onDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => void | Promise<void>;
64
52
  onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
65
53
  };
66
54
  treeInstance: {
67
- getDropTarget: () => DropTarget<T> | null;
55
+ getDragTarget: () => DragTarget<T> | null;
68
56
  getDragLineData: () => DragLineData | null;
69
57
  getDragLineStyle: (topOffset?: number, leftOffset?: number) => Record<string, any>;
70
58
  };
71
59
  itemInstance: {
72
- isDropTarget: () => boolean;
73
- isDropTargetAbove: () => boolean;
74
- isDropTargetBelow: () => boolean;
60
+ isDragTarget: () => boolean;
61
+ isDragTargetAbove: () => boolean;
62
+ isDragTargetBelow: () => boolean;
75
63
  isDraggingOver: () => boolean;
76
64
  };
77
65
  hotkeys: never;
@@ -1,6 +1,6 @@
1
- export var DropTargetPosition;
2
- (function (DropTargetPosition) {
3
- DropTargetPosition["Top"] = "top";
4
- DropTargetPosition["Bottom"] = "bottom";
5
- DropTargetPosition["Item"] = "item";
6
- })(DropTargetPosition || (DropTargetPosition = {}));
1
+ export var DragTargetPosition;
2
+ (function (DragTargetPosition) {
3
+ DragTargetPosition["Top"] = "top";
4
+ DragTargetPosition["Bottom"] = "bottom";
5
+ DragTargetPosition["Item"] = "item";
6
+ })(DragTargetPosition || (DragTargetPosition = {}));
@@ -1,5 +1,20 @@
1
1
  import { ItemInstance, TreeInstance } from "../../types/core";
2
- import { DropTarget } from "./types";
3
- export declare const canDrop: (dataTransfer: DataTransfer | null, target: DropTarget<any>, tree: TreeInstance<any>) => boolean;
2
+ import { DragTarget } from "./types";
3
+ export declare enum ItemDropCategory {
4
+ Item = 0,
5
+ ExpandedFolder = 1,
6
+ LastInGroup = 2
7
+ }
8
+ export declare const canDrop: (dataTransfer: DataTransfer | null, target: DragTarget<any>, tree: TreeInstance<any>) => boolean;
9
+ export declare const getItemDropCategory: (item: ItemInstance<any>) => ItemDropCategory;
10
+ export declare const getInsertionIndex: <T>(children: ItemInstance<T>[], childIndex: number, draggedItems: ItemInstance<T>[] | undefined) => number;
4
11
  export declare const getDragCode: (e: any, item: ItemInstance<any>, tree: TreeInstance<any>) => string;
5
- export declare const getDropTarget: (e: any, item: ItemInstance<any>, tree: TreeInstance<any>, canReorder?: boolean | undefined) => DropTarget<any>;
12
+ /** @param item refers to the bottom-most item of the container, at which bottom is being reparented on (e.g. root-1-2-6) */
13
+ export declare const getReparentTarget: <T>(item: ItemInstance<T>, reparentLevel: number, draggedItems: ItemInstance<T>[] | undefined) => {
14
+ item: ItemInstance<any>;
15
+ childIndex: number;
16
+ insertionIndex: number;
17
+ dragLineIndex: number;
18
+ dragLineLevel: number;
19
+ };
20
+ export declare const getDragTarget: (e: any, item: ItemInstance<any>, tree: TreeInstance<any>, canReorder?: boolean | undefined) => DragTarget<any>;