@headless-tree/core 0.0.14 → 1.0.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 (125) hide show
  1. package/CHANGELOG.md +13 -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 +25 -3
  9. package/lib/cjs/features/drag-and-drop/utils.js +51 -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 +206 -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 +33 -11
  19. package/lib/cjs/features/prop-memoization/types.d.ts +8 -3
  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 -9
  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 +25 -3
  52. package/lib/esm/features/drag-and-drop/utils.js +45 -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 +203 -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 +33 -11
  62. package/lib/esm/features/prop-memoization/types.d.ts +8 -3
  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 -9
  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 +26 -22
  96. package/src/features/drag-and-drop/types.ts +23 -35
  97. package/src/features/drag-and-drop/utils.ts +70 -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 +402 -0
  104. package/src/features/keyboard-drag-and-drop/types.ts +30 -0
  105. package/src/features/prop-memoization/feature.ts +27 -8
  106. package/src/features/prop-memoization/prop-memoization.spec.ts +2 -2
  107. package/src/features/prop-memoization/types.ts +8 -3
  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 -13
  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
@@ -27,7 +27,7 @@ export const treeFeature: FeatureImplementation<any> = {
27
27
  const { rootItemId } = tree.getConfig();
28
28
  const { expandedItems } = tree.getState();
29
29
  const flatItems: ItemMeta[] = [];
30
- const expandedItemsSet = new Set(expandedItems);
30
+ const expandedItemsSet = new Set(expandedItems); // TODO support setting state expandedItems as set instead of array
31
31
 
32
32
  const recursiveAdd = (
33
33
  itemId: string,
@@ -46,7 +46,6 @@ export const treeFeature: FeatureImplementation<any> = {
46
46
  });
47
47
 
48
48
  if (expandedItemsSet.has(itemId)) {
49
- // TODO THIS MADE A HUGE DIFFERENCE!
50
49
  const children = tree.retrieveChildrenIds(itemId) ?? [];
51
50
  let i = 0;
52
51
  for (const childId of children) {
@@ -64,7 +63,6 @@ export const treeFeature: FeatureImplementation<any> = {
64
63
  return flatItems;
65
64
  },
66
65
 
67
- // TODO memo
68
66
  getFocusedItem: ({ tree }) => {
69
67
  return (
70
68
  tree.getItemInstance(tree.getState().focusedItem ?? "") ??
@@ -96,12 +94,11 @@ export const treeFeature: FeatureImplementation<any> = {
96
94
  });
97
95
  },
98
96
 
99
- // TODO add label parameter
100
- getContainerProps: ({ prev, tree }) => ({
97
+ getContainerProps: ({ prev, tree }, treeLabel) => ({
101
98
  ...prev?.(),
102
99
  role: "tree",
103
- "aria-label": "",
104
- ref: tree.registerElement, // TODO memo
100
+ "aria-label": treeLabel ?? "",
101
+ ref: tree.registerElement,
105
102
  }),
106
103
 
107
104
  // relevant for hotkeys of this feature
@@ -119,7 +116,7 @@ export const treeFeature: FeatureImplementation<any> = {
119
116
  const itemMeta = item.getItemMeta();
120
117
  return {
121
118
  ...prev?.(),
122
- ref: item.registerElement, // TODO memo
119
+ ref: item.registerElement,
123
120
  role: "treeitem",
124
121
  "aria-setsize": itemMeta.setSize,
125
122
  "aria-posinset": itemMeta.posInSet,
@@ -152,7 +149,7 @@ export const treeFeature: FeatureImplementation<any> = {
152
149
  return;
153
150
  }
154
151
 
155
- if (tree.getState().loadingItems?.includes(itemId)) {
152
+ if (tree.getState().loadingItemChildrens?.includes(itemId)) {
156
153
  return;
157
154
  }
158
155
 
@@ -202,10 +199,8 @@ export const treeFeature: FeatureImplementation<any> = {
202
199
  ? tree.getItemInstance(item.getItemMeta().parentId)
203
200
  : undefined,
204
201
  getIndexInParent: ({ item }) => item.getItemMeta().posInSet,
205
- getChildren: ({ tree, item }) =>
206
- tree
207
- .retrieveChildrenIds(item.getItemMeta().itemId)
208
- .map((id) => tree.getItemInstance(id)),
202
+ getChildren: ({ tree, itemId }) =>
203
+ tree.retrieveChildrenIds(itemId).map((id) => tree.getItemInstance(id)),
209
204
  getTree: ({ tree }) => tree as any,
210
205
  getItemAbove: ({ tree, item }) =>
211
206
  tree.getItems()[item.getItemMeta().index - 1],
@@ -1,18 +1,18 @@
1
1
  import { ItemInstance, SetStateFn, TreeInstance } from "../../types/core";
2
2
 
3
- export type ItemMeta = {
3
+ export interface ItemMeta {
4
4
  itemId: string;
5
5
  parentId: string;
6
6
  level: number;
7
7
  index: number;
8
8
  setSize: number;
9
9
  posInSet: number;
10
- };
10
+ }
11
11
 
12
- export type TreeItemDataRef = {
12
+ export interface TreeItemDataRef {
13
13
  memoizedValues: Record<string, any>;
14
14
  memoizedDeps: Record<string, any[] | undefined>;
15
- };
15
+ }
16
16
 
17
17
  export type TreeFeatureDef<T> = {
18
18
  state: {
@@ -38,7 +38,9 @@ export type TreeFeatureDef<T> = {
38
38
  focusPreviousItem: () => void;
39
39
  updateDomFocus: () => void;
40
40
 
41
- getContainerProps: () => Record<string, any>;
41
+ /** Pass to the container rendering the tree children. The `treeLabel` parameter
42
+ * will be passed as `aria-label` parameter, and is recommended to be set. */
43
+ getContainerProps: (treeLabel?: string) => Record<string, any>;
42
44
  };
43
45
  itemInstance: {
44
46
  getId: () => string;
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ export * from "./core/create-tree";
4
4
  export * from "./features/tree/types";
5
5
  export { MainFeatureDef, InstanceBuilder } from "./features/main/types";
6
6
  export * from "./features/drag-and-drop/types";
7
+ export * from "./features/keyboard-drag-and-drop/types";
7
8
  export * from "./features/selection/types";
8
9
  export * from "./features/async-data-loader/types";
9
10
  export * from "./features/sync-data-loader/types";
@@ -18,6 +19,7 @@ export * from "./features/hotkeys-core/feature";
18
19
  export * from "./features/async-data-loader/feature";
19
20
  export * from "./features/sync-data-loader/feature";
20
21
  export * from "./features/drag-and-drop/feature";
22
+ export * from "./features/keyboard-drag-and-drop/feature";
21
23
  export * from "./features/search/feature";
22
24
  export * from "./features/renaming/feature";
23
25
  export * from "./features/expand-all/feature";
@@ -9,6 +9,7 @@ import { SelectionFeatureDef } from "./features/selection/types";
9
9
  import { SyncDataLoaderFeatureDef } from "./features/sync-data-loader/types";
10
10
  import { TreeFeatureDef } from "./features/tree/types";
11
11
  import { PropMemoizationFeatureDef } from "./features/prop-memoization/types";
12
+ import { KeyboardDragAndDropFeatureDef } from "./features/keyboard-drag-and-drop/types";
12
13
 
13
14
  export * from ".";
14
15
 
@@ -49,6 +50,21 @@ export type DragAndDropFeatureItemInstance<T> =
49
50
  DragAndDropFeatureDef<T>["itemInstance"];
50
51
  export type DragAndDropFeatureHotkeys<T> = DragAndDropFeatureDef<T>["hotkeys"];
51
52
 
53
+ /** @interface */
54
+ export type KeyboardDragAndDropFeatureConfig<T> =
55
+ KeyboardDragAndDropFeatureDef<T>["config"];
56
+ /** @interface */
57
+ export type KeyboardDragAndDropFeatureState<T> =
58
+ KeyboardDragAndDropFeatureDef<T>["state"];
59
+ /** @interface */
60
+ export type KeyboardDragAndDropFeatureTreeInstance<T> =
61
+ KeyboardDragAndDropFeatureDef<T>["treeInstance"];
62
+ /** @interface */
63
+ export type KeyboardDragAndDropFeatureItemInstance<T> =
64
+ KeyboardDragAndDropFeatureDef<T>["itemInstance"];
65
+ export type KeyboardDragAndDropFeatureHotkeys<T> =
66
+ KeyboardDragAndDropFeatureDef<T>["hotkeys"];
67
+
52
68
  /** @interface */
53
69
  export type ExpandAllFeatureConfig = ExpandAllFeatureDef["config"];
54
70
  /** @interface */
@@ -108,13 +108,13 @@ export class TestTreeDo<T> {
108
108
  return e;
109
109
  }
110
110
 
111
- drop(itemId: string, event?: DragEvent) {
111
+ async drop(itemId: string, event?: DragEvent) {
112
112
  const e = event ?? TestTree.dragEvent();
113
- this.itemProps(itemId).onDrop(e);
113
+ await this.itemProps(itemId).onDrop(e);
114
114
  return e;
115
115
  }
116
116
 
117
- dragOverAndDrop(itemId: string, event?: DragEvent) {
117
+ async dragOverAndDrop(itemId: string, event?: DragEvent) {
118
118
  const e = event ?? TestTree.dragEvent();
119
119
  this.dragOver(itemId, e);
120
120
  return this.drop(itemId, e);
@@ -2,7 +2,8 @@
2
2
  import { Mock, expect } from "vitest";
3
3
  import { DragEvent } from "react";
4
4
  import { TestTree } from "./test-tree";
5
- import { DropTarget } from "../features/drag-and-drop/types";
5
+ import { DragTarget } from "../features/drag-and-drop/types";
6
+ import { TreeState } from "../types/core";
6
7
 
7
8
  export class TestTreeExpect<T> {
8
9
  protected itemInstance(itemId: string) {
@@ -39,7 +40,11 @@ export class TestTreeExpect<T> {
39
40
  expect(itemChildren).toEqual(children);
40
41
  }
41
42
 
42
- dropped(draggedItems: string[], target: DropTarget<any>) {
43
+ substate<K extends keyof TreeState<T>>(key: K, value: TreeState<T>[K]) {
44
+ expect(this.tree.instance.getState()[key]).toEqual(value);
45
+ }
46
+
47
+ dropped(draggedItems: string[], target: DragTarget<any>) {
43
48
  expect(this.tree.instance.getConfig().onDrop).toBeCalledWith(
44
49
  draggedItems.map((id) => this.tree.item(id)),
45
50
  target,
@@ -8,6 +8,7 @@ import { TestTreeExpect } from "./test-tree-expect";
8
8
  import { syncDataLoaderFeature } from "../features/sync-data-loader/feature";
9
9
  import { asyncDataLoaderFeature } from "../features/async-data-loader/feature";
10
10
  import { buildProxiedInstance } from "../core/build-proxified-instance";
11
+ import { TreeDataLoader } from "../features/sync-data-loader/types";
11
12
 
12
13
  vi.useFakeTimers({ shouldAdvanceTime: true });
13
14
 
@@ -20,13 +21,32 @@ export class TestTree<T = string> {
20
21
 
21
22
  private static asyncLoaderResolvers: (() => void)[] = [];
22
23
 
24
+ private asyncDataLoaderImp: TreeDataLoader<T> = {
25
+ getItem: async (id: string) => {
26
+ await new Promise<void>((r) => {
27
+ (r as any).debugName = `Loading getItem ${id}`;
28
+ TestTree.asyncLoaderResolvers.push(r);
29
+ });
30
+ return id as T;
31
+ },
32
+ getChildren: async (id: string) => {
33
+ await new Promise<void>((r) => {
34
+ (r as any).debugName = `Loading getChildren ${id}`;
35
+ TestTree.asyncLoaderResolvers.push(r);
36
+ });
37
+ return [`${id}1`, `${id}2`, `${id}3`, `${id}4`];
38
+ },
39
+ };
40
+
23
41
  suits = {
24
42
  sync: () => ({
25
43
  tree: this.withFeatures(syncDataLoaderFeature),
26
44
  title: "Synchronous Data Loader",
27
45
  }),
28
46
  async: () => ({
29
- tree: this.withFeatures(asyncDataLoaderFeature),
47
+ tree: this.withFeatures(asyncDataLoaderFeature).with({
48
+ dataLoader: this.asyncDataLoaderImp,
49
+ }),
30
50
  title: "Asynchronous Data Loader",
31
51
  }),
32
52
  proxifiedSync: () => ({
@@ -65,12 +85,12 @@ export class TestTree<T = string> {
65
85
  private constructor(private config: TreeConfig<T>) {}
66
86
 
67
87
  static async resolveAsyncLoaders() {
68
- while (TestTree.asyncLoaderResolvers.length) {
88
+ do {
69
89
  TestTree.asyncLoaderResolvers.shift()?.();
70
90
  await new Promise<void>((r) => {
71
91
  setTimeout(r);
72
92
  });
73
- }
93
+ } while (TestTree.asyncLoaderResolvers.length);
74
94
  }
75
95
 
76
96
  async resolveAsyncVisibleItems() {
@@ -88,22 +108,6 @@ export class TestTree<T = string> {
88
108
  getItem: (id) => id,
89
109
  getChildren: (id) => [`${id}1`, `${id}2`, `${id}3`, `${id}4`],
90
110
  },
91
- asyncDataLoader: {
92
- getItem: async (id) => {
93
- await new Promise<void>((r) => {
94
- (r as any).debugName = `Loading getItem ${id}`;
95
- TestTree.asyncLoaderResolvers.push(r);
96
- });
97
- return id;
98
- },
99
- getChildren: async (id) => {
100
- await new Promise<void>((r) => {
101
- (r as any).debugName = `Loading getChildren ${id}`;
102
- TestTree.asyncLoaderResolvers.push(r);
103
- });
104
- return [`${id}1`, `${id}2`, `${id}3`, `${id}4`];
105
- },
106
- },
107
111
  getItemName: (item) => item.getItemData(),
108
112
  indent: 20,
109
113
  isItemFolder: (item) => item.getItemMeta().level < 2,
@@ -203,7 +207,7 @@ export class TestTree<T = string> {
203
207
  } as HTMLElement);
204
208
  }
205
209
 
206
- static dragEvent(pageX = 1000, pageY = 0) {
210
+ static dragEvent(clientX = 1000, clientY = 0) {
207
211
  return {
208
212
  preventDefault: vi.fn(),
209
213
  stopPropagation: vi.fn(),
@@ -212,8 +216,8 @@ export class TestTree<T = string> {
212
216
  getData: vi.fn(),
213
217
  dropEffect: "unchaged-from-test",
214
218
  },
215
- pageX,
216
- pageY,
219
+ clientX,
220
+ clientY,
217
221
  } as unknown as DragEvent;
218
222
  }
219
223
 
package/src/types/core.ts CHANGED
@@ -12,6 +12,7 @@ import { SearchFeatureDef } from "../features/search/types";
12
12
  import { RenamingFeatureDef } from "../features/renaming/types";
13
13
  import { ExpandAllFeatureDef } from "../features/expand-all/types";
14
14
  import { PropMemoizationFeatureDef } from "../features/prop-memoization/types";
15
+ import { KeyboardDragAndDropFeatureDef } from "../features/keyboard-drag-and-drop/types";
15
16
 
16
17
  export type Updater<T> = T | ((old: T) => T);
17
18
  export type SetStateFn<T> = (updaterOrValue: Updater<T>) => void;
@@ -53,6 +54,7 @@ export type RegisteredFeatures<T> =
53
54
  | TreeFeatureDef<T>
54
55
  | SelectionFeatureDef<T>
55
56
  | DragAndDropFeatureDef<T>
57
+ | KeyboardDragAndDropFeatureDef<T>
56
58
  | HotkeysCoreFeatureDef<T>
57
59
  | SyncDataLoaderFeatureDef<T>
58
60
  | AsyncDataLoaderFeatureDef<T>
@@ -1,5 +1,5 @@
1
1
  import { ItemInstance } from "../types/core";
2
- import { DropTarget } from "../features/drag-and-drop/types";
2
+ import { DragTarget } from "../features/drag-and-drop/types";
3
3
  import { removeItemsFromParents } from "./remove-items-from-parents";
4
4
  import { insertItemsAtTarget } from "./insert-items-at-target";
5
5
 
@@ -7,8 +7,8 @@ export const createOnDropHandler =
7
7
  <T>(
8
8
  onChangeChildren: (item: ItemInstance<T>, newChildren: string[]) => void,
9
9
  ) =>
10
- (items: ItemInstance<T>[], target: DropTarget<T>) => {
10
+ async (items: ItemInstance<T>[], target: DragTarget<T>) => {
11
11
  const itemIds = items.map((item) => item.getId());
12
- removeItemsFromParents(items, onChangeChildren);
13
- insertItemsAtTarget(itemIds, target, onChangeChildren);
12
+ await removeItemsFromParents(items, onChangeChildren);
13
+ await insertItemsAtTarget(itemIds, target, onChangeChildren);
14
14
  };
@@ -1,18 +1,23 @@
1
1
  import { ItemInstance } from "../types/core";
2
- import { DropTarget } from "../features/drag-and-drop/types";
2
+ import { DragTarget } from "../features/drag-and-drop/types";
3
3
 
4
- export const insertItemsAtTarget = <T>(
4
+ export const insertItemsAtTarget = async <T>(
5
5
  itemIds: string[],
6
- target: DropTarget<T>,
7
- onChangeChildren: (item: ItemInstance<T>, newChildrenIds: string[]) => void,
6
+ target: DragTarget<T>,
7
+ onChangeChildren: (
8
+ item: ItemInstance<T>,
9
+ newChildrenIds: string[],
10
+ ) => Promise<void> | void,
8
11
  ) => {
12
+ await target.item.getTree().waitForItemChildrenLoaded(target.item.getId());
13
+ const oldChildrenIds = target.item
14
+ .getTree()
15
+ .retrieveChildrenIds(target.item.getId());
16
+
9
17
  // add moved items to new common parent, if dropped onto parent
10
- if (target.childIndex === null) {
11
- const newChildren = [
12
- ...target.item.getChildren().map((item) => item.getId()),
13
- ...itemIds,
14
- ];
15
- onChangeChildren(target.item, newChildren);
18
+ if (!("childIndex" in target)) {
19
+ const newChildren = [...oldChildrenIds, ...itemIds];
20
+ await onChangeChildren(target.item, newChildren);
16
21
  if (target.item && "updateCachedChildrenIds" in target.item) {
17
22
  target.item.updateCachedChildrenIds(newChildren);
18
23
  }
@@ -21,14 +26,13 @@ export const insertItemsAtTarget = <T>(
21
26
  }
22
27
 
23
28
  // add moved items to new common parent, if dropped between siblings
24
- const oldChildren = target.item.getChildren();
25
29
  const newChildren = [
26
- ...oldChildren.slice(0, target.insertionIndex).map((item) => item.getId()),
30
+ ...oldChildrenIds.slice(0, target.insertionIndex),
27
31
  ...itemIds,
28
- ...oldChildren.slice(target.insertionIndex).map((item) => item.getId()),
32
+ ...oldChildrenIds.slice(target.insertionIndex),
29
33
  ];
30
34
 
31
- onChangeChildren(target.item, newChildren);
35
+ await onChangeChildren(target.item, newChildren);
32
36
 
33
37
  if (target.item && "updateCachedChildrenIds" in target.item) {
34
38
  target.item.updateCachedChildrenIds(newChildren);
@@ -1,8 +1,11 @@
1
1
  import { ItemInstance } from "../types/core";
2
2
 
3
- export const removeItemsFromParents = <T>(
3
+ export const removeItemsFromParents = async <T>(
4
4
  movedItems: ItemInstance<T>[],
5
- onChangeChildren: (item: ItemInstance<T>, newChildrenIds: string[]) => void,
5
+ onChangeChildren: (
6
+ item: ItemInstance<T>,
7
+ newChildrenIds: string[],
8
+ ) => void | Promise<void>,
6
9
  ) => {
7
10
  const movedItemsIds = movedItems.map((item) => item.getId());
8
11
  const uniqueParents = [
@@ -15,7 +18,7 @@ export const removeItemsFromParents = <T>(
15
18
  const newChildren = siblings
16
19
  .filter((sibling) => !movedItemsIds.includes(sibling.getId()))
17
20
  .map((i) => i.getId());
18
- onChangeChildren(parent, newChildren);
21
+ await onChangeChildren(parent, newChildren);
19
22
  if (parent && "updateCachedChildrenIds" in parent) {
20
23
  parent?.updateCachedChildrenIds(newChildren);
21
24
  }