@headless-tree/core 0.0.5 → 0.0.6

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 (90) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/lib/cjs/core/create-tree.js +7 -6
  3. package/lib/cjs/features/async-data-loader/feature.js +30 -21
  4. package/lib/cjs/features/drag-and-drop/feature.js +29 -17
  5. package/lib/cjs/features/drag-and-drop/types.d.ts +14 -1
  6. package/lib/cjs/features/drag-and-drop/utils.d.ts +1 -1
  7. package/lib/cjs/features/drag-and-drop/utils.js +34 -17
  8. package/lib/cjs/features/expand-all/feature.js +12 -9
  9. package/lib/cjs/features/expand-all/types.d.ts +2 -2
  10. package/lib/cjs/features/main/types.d.ts +3 -1
  11. package/lib/cjs/features/renaming/feature.js +10 -9
  12. package/lib/cjs/features/search/feature.js +21 -7
  13. package/lib/cjs/features/search/types.d.ts +1 -1
  14. package/lib/cjs/features/selection/feature.js +5 -3
  15. package/lib/cjs/features/sync-data-loader/feature.js +6 -0
  16. package/lib/cjs/features/sync-data-loader/types.d.ts +1 -1
  17. package/lib/cjs/features/tree/feature.js +23 -23
  18. package/lib/cjs/features/tree/types.d.ts +2 -2
  19. package/lib/cjs/index.d.ts +3 -1
  20. package/lib/cjs/index.js +3 -1
  21. package/lib/cjs/types/core.d.ts +1 -3
  22. package/lib/cjs/utilities/create-on-drop-handler.d.ts +3 -0
  23. package/lib/cjs/utilities/create-on-drop-handler.js +11 -0
  24. package/lib/cjs/utilities/insert-items-at-target.d.ts +3 -0
  25. package/lib/cjs/utilities/insert-items-at-target.js +24 -0
  26. package/lib/cjs/utilities/remove-items-from-parents.d.ts +2 -0
  27. package/lib/cjs/utilities/remove-items-from-parents.js +17 -0
  28. package/lib/cjs/utils.d.ts +1 -4
  29. package/lib/cjs/utils.js +1 -53
  30. package/lib/esm/core/create-tree.js +7 -6
  31. package/lib/esm/features/async-data-loader/feature.js +30 -21
  32. package/lib/esm/features/drag-and-drop/feature.js +29 -17
  33. package/lib/esm/features/drag-and-drop/types.d.ts +14 -1
  34. package/lib/esm/features/drag-and-drop/utils.d.ts +1 -1
  35. package/lib/esm/features/drag-and-drop/utils.js +35 -18
  36. package/lib/esm/features/expand-all/feature.js +12 -9
  37. package/lib/esm/features/expand-all/types.d.ts +2 -2
  38. package/lib/esm/features/main/types.d.ts +3 -1
  39. package/lib/esm/features/renaming/feature.js +10 -9
  40. package/lib/esm/features/search/feature.js +21 -7
  41. package/lib/esm/features/search/types.d.ts +1 -1
  42. package/lib/esm/features/selection/feature.js +5 -3
  43. package/lib/esm/features/sync-data-loader/feature.js +6 -0
  44. package/lib/esm/features/sync-data-loader/types.d.ts +1 -1
  45. package/lib/esm/features/tree/feature.js +23 -23
  46. package/lib/esm/features/tree/types.d.ts +2 -2
  47. package/lib/esm/index.d.ts +3 -1
  48. package/lib/esm/index.js +3 -1
  49. package/lib/esm/types/core.d.ts +1 -3
  50. package/lib/esm/utilities/create-on-drop-handler.d.ts +3 -0
  51. package/lib/esm/utilities/create-on-drop-handler.js +7 -0
  52. package/lib/esm/utilities/insert-items-at-target.d.ts +3 -0
  53. package/lib/esm/utilities/insert-items-at-target.js +20 -0
  54. package/lib/esm/utilities/remove-items-from-parents.d.ts +2 -0
  55. package/lib/esm/utilities/remove-items-from-parents.js +13 -0
  56. package/lib/esm/utils.d.ts +1 -4
  57. package/lib/esm/utils.js +0 -50
  58. package/package.json +1 -1
  59. package/src/core/create-tree.ts +11 -7
  60. package/src/features/async-data-loader/feature.ts +15 -5
  61. package/src/features/drag-and-drop/feature.ts +34 -12
  62. package/src/features/drag-and-drop/types.ts +23 -6
  63. package/src/features/drag-and-drop/utils.ts +53 -24
  64. package/src/features/expand-all/feature.ts +10 -8
  65. package/src/features/expand-all/types.ts +2 -2
  66. package/src/features/main/types.ts +6 -0
  67. package/src/features/renaming/feature.ts +10 -5
  68. package/src/features/search/feature.ts +22 -5
  69. package/src/features/search/types.ts +1 -0
  70. package/src/features/selection/feature.ts +6 -1
  71. package/src/features/sync-data-loader/feature.ts +17 -2
  72. package/src/features/sync-data-loader/types.ts +1 -1
  73. package/src/features/tree/feature.ts +23 -21
  74. package/src/features/tree/types.ts +4 -2
  75. package/src/index.ts +4 -1
  76. package/src/types/core.ts +4 -4
  77. package/src/utilities/create-on-drop-handler.ts +14 -0
  78. package/src/utilities/insert-items-at-target.ts +30 -0
  79. package/src/utilities/remove-items-from-parents.ts +21 -0
  80. package/src/utils.ts +1 -69
  81. package/lib/cjs/data-adapters/nested-data-adapter.d.ts +0 -9
  82. package/lib/cjs/data-adapters/nested-data-adapter.js +0 -32
  83. package/lib/cjs/data-adapters/types.d.ts +0 -7
  84. package/lib/cjs/data-adapters/types.js +0 -2
  85. package/lib/esm/data-adapters/nested-data-adapter.d.ts +0 -9
  86. package/lib/esm/data-adapters/nested-data-adapter.js +0 -28
  87. package/lib/esm/data-adapters/types.d.ts +0 -7
  88. package/lib/esm/data-adapters/types.js +0 -1
  89. package/src/data-adapters/nested-data-adapter.ts +0 -48
  90. package/src/data-adapters/types.ts +0 -9
@@ -16,6 +16,10 @@ exports.treeFeature = {
16
16
  dependingFeatures: ["main"],
17
17
  getInitialState: (initialState) => (Object.assign({ expandedItems: [], focusedItem: null }, initialState)),
18
18
  getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setExpandedItems: (0, utils_1.makeStateUpdater)("expandedItems", tree), setFocusedItem: (0, utils_1.makeStateUpdater)("focusedItem", tree) }, defaultConfig)),
19
+ stateHandlerNames: {
20
+ expandedItems: "setExpandedItems",
21
+ focusedItem: "setFocusedItem",
22
+ },
19
23
  createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { retrieveItemData: () => {
20
24
  throw new Error("No data-loader registered");
21
25
  }, retrieveChildrenIds: () => {
@@ -23,7 +27,6 @@ exports.treeFeature = {
23
27
  }, isItemExpanded: (itemId) => instance.getState().expandedItems.includes(itemId), getItemsMeta: () => {
24
28
  const { rootItemId } = instance.getConfig();
25
29
  const { expandedItems } = instance.getState();
26
- // console.log("!", instance.getConfig());
27
30
  const flatItems = [];
28
31
  const recursiveAdd = (itemId, parentId, level, setSize, posInSet) => {
29
32
  var _a;
@@ -50,23 +53,23 @@ exports.treeFeature = {
50
53
  }
51
54
  return flatItems;
52
55
  }, expandItem: (itemId) => {
53
- var _a, _b, _c;
56
+ var _a;
54
57
  if (!instance.getItemInstance(itemId).isFolder()) {
55
58
  return;
56
59
  }
57
60
  if ((_a = instance.getState().loadingItems) === null || _a === void 0 ? void 0 : _a.includes(itemId)) {
58
61
  return;
59
62
  }
60
- (_c = (_b = instance
61
- .getConfig()).setExpandedItems) === null || _c === void 0 ? void 0 : _c.call(_b, (expandedItems) => [...expandedItems, itemId]);
63
+ instance.applySubStateUpdate("expandedItems", (expandedItems) => [
64
+ ...expandedItems,
65
+ itemId,
66
+ ]);
62
67
  instance.rebuildTree();
63
68
  }, collapseItem: (itemId) => {
64
- var _a, _b;
65
69
  if (!instance.getItemInstance(itemId).isFolder()) {
66
70
  return;
67
71
  }
68
- (_b = (_a = instance
69
- .getConfig()).setExpandedItems) === null || _b === void 0 ? void 0 : _b.call(_a, (expandedItems) => expandedItems.filter((id) => id !== itemId));
72
+ instance.applySubStateUpdate("expandedItems", (expandedItems) => expandedItems.filter((id) => id !== itemId));
70
73
  instance.rebuildTree();
71
74
  },
72
75
  // TODO memo
@@ -74,8 +77,7 @@ exports.treeFeature = {
74
77
  var _a, _b;
75
78
  return ((_b = instance.getItemInstance((_a = instance.getState().focusedItem) !== null && _a !== void 0 ? _a : "")) !== null && _b !== void 0 ? _b : instance.getItems()[0]);
76
79
  }, focusItem: (itemId) => {
77
- var _a, _b;
78
- (_b = (_a = instance.getConfig()).setFocusedItem) === null || _b === void 0 ? void 0 : _b.call(_a, itemId);
80
+ instance.applySubStateUpdate("focusedItem", itemId);
79
81
  }, focusNextItem: () => {
80
82
  const { index } = instance.getFocusedItem().getItemMeta();
81
83
  const nextIndex = Math.min(index + 1, instance.getItems().length - 1);
@@ -84,7 +86,7 @@ exports.treeFeature = {
84
86
  const { index } = instance.getFocusedItem().getItemMeta();
85
87
  const nextIndex = Math.max(index - 1, 0);
86
88
  instance.focusItem(instance.getItems()[nextIndex].getId());
87
- }, updateDomFocus: (scrollIntoView) => {
89
+ }, updateDomFocus: () => {
88
90
  // Required because if the state is managed outside in react, the state only updated during next render
89
91
  setTimeout(() => __awaiter(void 0, void 0, void 0, function* () {
90
92
  var _a, _b;
@@ -95,9 +97,6 @@ exports.treeFeature = {
95
97
  if (!focusedElement)
96
98
  return;
97
99
  focusedElement.focus();
98
- // if (scrollIntoView) {
99
- // focusedElement.scrollIntoView();
100
- // }
101
100
  }));
102
101
  }, getContainerProps: () => {
103
102
  var _a;
@@ -105,11 +104,15 @@ exports.treeFeature = {
105
104
  } })),
106
105
  createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { isLoading: () => {
107
106
  throw new Error("No data-loader registered");
108
- }, getId: () => item.getItemMeta().itemId, getProps: () => {
107
+ }, scrollTo: (scrollIntoViewArg) => __awaiter(void 0, void 0, void 0, function* () {
108
+ var _a, _b;
109
+ (_b = (_a = tree.getConfig()).scrollToItem) === null || _b === void 0 ? void 0 : _b.call(_a, item);
110
+ yield (0, utils_1.poll)(() => item.getElement() !== null, 20);
111
+ item.getElement().scrollIntoView(scrollIntoViewArg);
112
+ }), getId: () => item.getItemMeta().itemId, getProps: () => {
109
113
  var _a;
110
114
  const itemMeta = item.getItemMeta();
111
- return Object.assign(Object.assign({}, (_a = prev.getProps) === null || _a === void 0 ? void 0 : _a.call(prev)), { role: "treeitem", "aria-setsize": itemMeta.setSize, "aria-posinset": itemMeta.posInSet, "aria-selected": false, "aria-label": item.getItemName(), "aria-level": itemMeta.level, tabIndex: item.isFocused() ? 0 : -1, onClick: item.getMemoizedProp("tree/onClick", () => (e) => {
112
- console.log("onClick", item.getId());
115
+ return Object.assign(Object.assign({}, (_a = prev.getProps) === null || _a === void 0 ? void 0 : _a.call(prev)), { role: "treeitem", "aria-setsize": itemMeta.setSize, "aria-posinset": itemMeta.posInSet, "aria-selected": "false", "aria-label": item.getItemName(), "aria-level": itemMeta.level, tabIndex: item.isFocused() ? 0 : -1, onClick: item.getMemoizedProp("tree/onClick", () => (e) => {
113
116
  item.setFocused();
114
117
  item.primaryAction();
115
118
  if (e.ctrlKey || e.shiftKey || e.metaKey) {
@@ -138,12 +141,9 @@ exports.treeFeature = {
138
141
  }
139
142
  }
140
143
  return tree.getItemInstance(tree.getConfig().rootItemId);
141
- }, () => [item.getItemMeta()]), getIndexInParent: () => {
142
- var _a, _b;
143
- return item.getItemMeta().index -
144
- ((_b = (_a = item.getParent()) === null || _a === void 0 ? void 0 : _a.getItemMeta().index) !== null && _b !== void 0 ? _b : 0) -
145
- 1;
146
- }, getChildren: () => tree
144
+ }, () => [item.getItemMeta()]),
145
+ // TODO remove
146
+ getIndexInParent: () => item.getItemMeta().posInSet, getChildren: () => tree
147
147
  .retrieveChildrenIds(item.getItemMeta().itemId)
148
148
  .map((id) => tree.getItemInstance(id)), getTree: () => tree, getItemAbove: () => tree.getItems()[item.getItemMeta().index - 1], getItemBelow: () => tree.getItems()[item.getItemMeta().index + 1], getMemoizedProp: (name, create, deps) => {
149
149
  var _a, _b, _c, _d, _e;
@@ -206,7 +206,7 @@ exports.treeFeature = {
206
206
  if ((!item.isExpanded() || !item.isFolder()) &&
207
207
  item.getItemMeta().level !== 0) {
208
208
  (_a = item.getParent()) === null || _a === void 0 ? void 0 : _a.setFocused();
209
- tree.updateDomFocus(true);
209
+ tree.updateDomFocus();
210
210
  }
211
211
  else {
212
212
  item.collapse();
@@ -34,8 +34,7 @@ export type TreeFeatureDef<T> = {
34
34
  getFocusedItem: () => ItemInstance<any>;
35
35
  focusNextItem: () => void;
36
36
  focusPreviousItem: () => void;
37
- scrollToItem: (item: ItemInstance<any>) => void;
38
- updateDomFocus: (scrollIntoView?: boolean) => void;
37
+ updateDomFocus: () => void;
39
38
  getContainerProps: () => Record<string, any>;
40
39
  };
41
40
  itemInstance: {
@@ -57,6 +56,7 @@ export type TreeFeatureDef<T> = {
57
56
  getItemAbove: () => ItemInstance<T> | null;
58
57
  getItemBelow: () => ItemInstance<T> | null;
59
58
  getMemoizedProp: <X>(name: string, create: () => X, deps?: any[]) => X;
59
+ scrollTo: (scrollIntoViewArg?: boolean | ScrollIntoViewOptions) => Promise<void>;
60
60
  };
61
61
  hotkeys: "focusNextItem" | "focusPreviousItem" | "expandOrDown" | "collapseOrUp" | "focusFirstItem" | "focusLastItem";
62
62
  };
@@ -18,4 +18,6 @@ export * from "./features/drag-and-drop/feature";
18
18
  export * from "./features/search/feature";
19
19
  export * from "./features/renaming/feature";
20
20
  export * from "./features/expand-all/feature";
21
- export * from "./data-adapters/nested-data-adapter";
21
+ export * from "./utilities/create-on-drop-handler";
22
+ export * from "./utilities/insert-items-at-target";
23
+ export * from "./utilities/remove-items-from-parents";
package/lib/cjs/index.js CHANGED
@@ -34,4 +34,6 @@ __exportStar(require("./features/drag-and-drop/feature"), exports);
34
34
  __exportStar(require("./features/search/feature"), exports);
35
35
  __exportStar(require("./features/renaming/feature"), exports);
36
36
  __exportStar(require("./features/expand-all/feature"), exports);
37
- __exportStar(require("./data-adapters/nested-data-adapter"), exports);
37
+ __exportStar(require("./utilities/create-on-drop-handler"), exports);
38
+ __exportStar(require("./utilities/insert-items-at-target"), exports);
39
+ __exportStar(require("./utilities/remove-items-from-parents"), exports);
@@ -52,6 +52,7 @@ export type CustomHotkeysConfig<T, F extends FeatureDef = FeatureDefs<T>> = Part
52
52
  export type FeatureImplementation<T = any, D extends FeatureDef = any, F extends FeatureDef = EmptyFeatureDef> = {
53
53
  key?: string;
54
54
  dependingFeatures?: string[];
55
+ stateHandlerNames?: Partial<Record<keyof MergedFeatures<F>["state"], keyof MergedFeatures<F>["config"]>>;
55
56
  getInitialState?: (initialState: Partial<MergedFeatures<F>["state"]>, tree: MergedFeatures<F>["treeInstance"]) => Partial<D["state"] & MergedFeatures<F>["state"]>;
56
57
  getDefaultConfig?: (defaultConfig: Partial<MergedFeatures<F>["config"]>, tree: MergedFeatures<F>["treeInstance"]) => Partial<D["config"] & MergedFeatures<F>["config"]>;
57
58
  createTreeInstance?: (prev: MergedFeatures<F>["treeInstance"], instance: MergedFeatures<F>["treeInstance"]) => D["treeInstance"] & MergedFeatures<F>["treeInstance"];
@@ -60,9 +61,6 @@ export type FeatureImplementation<T = any, D extends FeatureDef = any, F extends
60
61
  onTreeUnmount?: (instance: MergedFeatures<F>["treeInstance"], treeElement: HTMLElement) => void;
61
62
  onItemMount?: (instance: MergedFeatures<F>["itemInstance"], itemElement: HTMLElement, tree: MergedFeatures<F>["treeInstance"]) => void;
62
63
  onItemUnmount?: (instance: MergedFeatures<F>["itemInstance"], itemElement: HTMLElement, tree: MergedFeatures<F>["treeInstance"]) => void;
63
- setState?: (instance: MergedFeatures<F>["treeInstance"]) => void;
64
- onConfigChange?: (instance: MergedFeatures<F>["treeInstance"]) => void;
65
- onStateOrConfigChange?: (instance: MergedFeatures<F>["treeInstance"]) => void;
66
64
  hotkeys?: HotkeysConfig<T, D>;
67
65
  };
68
66
  export {};
@@ -0,0 +1,3 @@
1
+ import { ItemInstance } from "../types/core";
2
+ import { DropTarget } from "../features/drag-and-drop/types";
3
+ export declare const createOnDropHandler: <T>(onChangeChildren: (item: ItemInstance<T>, newChildren: string[]) => void) => (items: ItemInstance<T>[], target: DropTarget<T>) => void;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createOnDropHandler = void 0;
4
+ const remove_items_from_parents_1 = require("./remove-items-from-parents");
5
+ const insert_items_at_target_1 = require("./insert-items-at-target");
6
+ const createOnDropHandler = (onChangeChildren) => (items, target) => {
7
+ const itemIds = items.map((item) => item.getId());
8
+ (0, remove_items_from_parents_1.removeItemsFromParents)(items, onChangeChildren);
9
+ (0, insert_items_at_target_1.insertItemsAtTarget)(itemIds, target, onChangeChildren);
10
+ };
11
+ exports.createOnDropHandler = createOnDropHandler;
@@ -0,0 +1,3 @@
1
+ import { ItemInstance } from "../types/core";
2
+ import { DropTarget } from "../features/drag-and-drop/types";
3
+ export declare const insertItemsAtTarget: <T>(itemIds: string[], target: DropTarget<T>, onChangeChildren: (item: ItemInstance<T>, newChildrenIds: string[]) => void) => void;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.insertItemsAtTarget = void 0;
4
+ const insertItemsAtTarget = (itemIds, target, onChangeChildren) => {
5
+ // add moved items to new common parent, if dropped onto parent
6
+ if (target.childIndex === null) {
7
+ onChangeChildren(target.item, [
8
+ ...target.item.getChildren().map((item) => item.getId()),
9
+ ...itemIds,
10
+ ]);
11
+ // TODO items[0].getTree().rebuildTree();
12
+ return;
13
+ }
14
+ // add moved items to new common parent, if dropped between siblings
15
+ const oldChildren = target.item.getChildren();
16
+ const newChildren = [
17
+ ...oldChildren.slice(0, target.insertionIndex).map((item) => item.getId()),
18
+ ...itemIds,
19
+ ...oldChildren.slice(target.insertionIndex).map((item) => item.getId()),
20
+ ];
21
+ onChangeChildren(target.item, newChildren);
22
+ target.item.getTree().rebuildTree();
23
+ };
24
+ exports.insertItemsAtTarget = insertItemsAtTarget;
@@ -0,0 +1,2 @@
1
+ import { ItemInstance } from "../types/core";
2
+ export declare const removeItemsFromParents: <T>(movedItems: ItemInstance<T>[], onChangeChildren: (item: ItemInstance<T>, newChildrenIds: string[]) => void) => void;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.removeItemsFromParents = void 0;
4
+ const removeItemsFromParents = (movedItems, onChangeChildren) => {
5
+ var _a;
6
+ // TODO bulk sibling changes together
7
+ for (const item of movedItems) {
8
+ const siblings = (_a = item.getParent()) === null || _a === void 0 ? void 0 : _a.getChildren();
9
+ if (siblings) {
10
+ onChangeChildren(item.getParent(), siblings
11
+ .filter((sibling) => sibling.getId() !== item.getId())
12
+ .map((i) => i.getId()));
13
+ }
14
+ }
15
+ movedItems[0].getTree().rebuildTree();
16
+ };
17
+ exports.removeItemsFromParents = removeItemsFromParents;
@@ -1,9 +1,6 @@
1
- import { ItemInstance, TreeState, Updater } from "./types/core";
2
- import { DropTarget } from "./features/drag-and-drop/types";
1
+ import { TreeState, Updater } from "./types/core";
3
2
  export type NoInfer<T> = [T][T extends any ? 0 : never];
4
3
  export declare const memo: <D extends readonly any[], R>(fn: (...args_0: D) => R, deps: () => [...D]) => () => R;
5
4
  export declare function functionalUpdate<T>(updater: Updater<T>, input: T): T;
6
5
  export declare function makeStateUpdater<K extends keyof TreeState<any>>(key: K, instance: unknown): (updater: Updater<TreeState<any>[K]>) => void;
7
- export declare const scrollIntoView: (element: Element | undefined | null) => void;
8
- export declare const performItemsMove: <T>(items: ItemInstance<T>[], target: DropTarget<T>, onChangeChildren: (item: ItemInstance<T>, newChildren: ItemInstance<T>[]) => void) => void;
9
6
  export declare const poll: (fn: () => boolean, interval?: number, timeout?: number) => Promise<void>;
package/lib/cjs/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.poll = exports.performItemsMove = exports.scrollIntoView = exports.makeStateUpdater = exports.functionalUpdate = exports.memo = void 0;
3
+ exports.poll = exports.makeStateUpdater = exports.functionalUpdate = exports.memo = void 0;
4
4
  const memo = (fn, deps) => {
5
5
  let value;
6
6
  let oldDeps = null;
@@ -37,58 +37,6 @@ function makeStateUpdater(key, instance) {
37
37
  };
38
38
  }
39
39
  exports.makeStateUpdater = makeStateUpdater;
40
- const scrollIntoView = (element) => {
41
- if (!element) {
42
- return;
43
- }
44
- if (element.scrollIntoViewIfNeeded) {
45
- element.scrollIntoViewIfNeeded();
46
- }
47
- else {
48
- const boundingBox = element.getBoundingClientRect();
49
- const isElementInViewport = boundingBox.top >= 0 &&
50
- boundingBox.left >= 0 &&
51
- boundingBox.bottom <=
52
- (window.innerHeight || document.documentElement.clientHeight) &&
53
- boundingBox.right <=
54
- (window.innerWidth || document.documentElement.clientWidth);
55
- if (!isElementInViewport) {
56
- element.scrollIntoView();
57
- }
58
- }
59
- };
60
- exports.scrollIntoView = scrollIntoView;
61
- const performItemsMove = (items, target, onChangeChildren) => {
62
- var _a;
63
- const numberOfDragItemsBeforeTarget = !target.childIndex
64
- ? 0
65
- : target.item
66
- .getChildren()
67
- .slice(0, target.childIndex)
68
- .filter((child) => items.some((item) => item.getId() === child.getId()))
69
- .length;
70
- // TODO bulk sibling changes together
71
- for (const item of items) {
72
- const siblings = (_a = item.getParent()) === null || _a === void 0 ? void 0 : _a.getChildren();
73
- if (siblings) {
74
- onChangeChildren(item.getParent(), siblings.filter((sibling) => sibling.getId() !== item.getId()));
75
- }
76
- }
77
- if (target.childIndex === null) {
78
- onChangeChildren(target.item, [...target.item.getChildren(), ...items]);
79
- items[0].getTree().rebuildTree();
80
- return;
81
- }
82
- const oldChildren = target.item.getChildren();
83
- const newChildren = [
84
- ...oldChildren.slice(0, target.childIndex - numberOfDragItemsBeforeTarget),
85
- ...items,
86
- ...oldChildren.slice(target.childIndex - numberOfDragItemsBeforeTarget),
87
- ];
88
- onChangeChildren(target.item, newChildren);
89
- items[0].getTree().rebuildTree();
90
- };
91
- exports.performItemsMove = performItemsMove;
92
40
  const poll = (fn, interval = 100, timeout = 1000) => new Promise((resolve) => {
93
41
  let clear;
94
42
  const i = setInterval(() => {
@@ -13,6 +13,7 @@ export const createTree = (initialConfig) => {
13
13
  const additionalFeatures = [treeFeature, ...((_a = initialConfig.features) !== null && _a !== void 0 ? _a : [])];
14
14
  let state = additionalFeatures.reduce((acc, feature) => { var _a, _b; return (_b = (_a = feature.getInitialState) === null || _a === void 0 ? void 0 : _a.call(feature, acc, treeInstance)) !== null && _b !== void 0 ? _b : acc; }, (_c = (_b = initialConfig.initialState) !== null && _b !== void 0 ? _b : initialConfig.state) !== null && _c !== void 0 ? _c : {});
15
15
  let config = additionalFeatures.reduce((acc, feature) => { var _a, _b; return (_b = (_a = feature.getDefaultConfig) === null || _a === void 0 ? void 0 : _a.call(feature, acc, treeInstance)) !== null && _b !== void 0 ? _b : acc; }, initialConfig);
16
+ const stateHandlerNames = additionalFeatures.reduce((acc, feature) => (Object.assign(Object.assign({}, acc), feature.stateHandlerNames)), {});
16
17
  let treeElement;
17
18
  const treeDataRef = { current: {} };
18
19
  const itemInstancesMap = {};
@@ -57,10 +58,13 @@ export const createTree = (initialConfig) => {
57
58
  key: "main",
58
59
  createTreeInstance: (prev) => (Object.assign(Object.assign({}, prev), { getState: () => state, setState: (updater) => {
59
60
  var _a;
60
- state = typeof updater === "function" ? updater(state) : updater;
61
+ // Not necessary, since I think the subupdate below keeps the state fresh anyways?
62
+ // state = typeof updater === "function" ? updater(state) : updater;
61
63
  (_a = config.setState) === null || _a === void 0 ? void 0 : _a.call(config, state);
62
- eachFeature((feature) => { var _a; return (_a = feature.setState) === null || _a === void 0 ? void 0 : _a.call(feature, treeInstance); });
63
- eachFeature((feature) => { var _a; return (_a = feature.onStateOrConfigChange) === null || _a === void 0 ? void 0 : _a.call(feature, treeInstance); });
64
+ }, applySubStateUpdate: (stateName, updater) => {
65
+ state[stateName] =
66
+ typeof updater === "function" ? updater(state[stateName]) : updater;
67
+ config[stateHandlerNames[stateName]](state[stateName]);
64
68
  }, rebuildTree: () => {
65
69
  var _a;
66
70
  rebuildItemMeta(mainFeature);
@@ -69,10 +73,7 @@ export const createTree = (initialConfig) => {
69
73
  config = typeof updater === "function" ? updater(config) : updater;
70
74
  if (config.state) {
71
75
  state = Object.assign(Object.assign({}, state), config.state);
72
- eachFeature((feature) => { var _a; return (_a = feature.setState) === null || _a === void 0 ? void 0 : _a.call(feature, treeInstance); });
73
76
  }
74
- eachFeature((feature) => { var _a; return (_a = feature.onConfigChange) === null || _a === void 0 ? void 0 : _a.call(feature, treeInstance); });
75
- eachFeature((feature) => { var _a; return (_a = feature.onStateOrConfigChange) === null || _a === void 0 ? void 0 : _a.call(feature, treeInstance); });
76
77
  }, getItemInstance: (itemId) => itemInstancesMap[itemId], getItems: () => itemInstances, registerElement: (element) => {
77
78
  if (treeElement === element) {
78
79
  return;
@@ -4,43 +4,52 @@ export const asyncDataLoaderFeature = {
4
4
  dependingFeatures: ["main"],
5
5
  getInitialState: (initialState) => (Object.assign({ loadingItems: [] }, initialState)),
6
6
  getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setLoadingItems: makeStateUpdater("loadingItems", tree) }, defaultConfig)),
7
+ stateHandlerNames: {
8
+ loadingItems: "setLoadingItems",
9
+ },
7
10
  createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { retrieveItemData: (itemId) => {
8
- var _a, _b, _c, _d, _e, _f;
9
- var _g, _h;
11
+ var _a, _b, _c, _d, _e;
12
+ var _f, _g;
10
13
  const config = instance.getConfig();
11
14
  const dataRef = instance.getDataRef();
12
- (_a = (_g = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_g.itemData = {});
13
- (_b = (_h = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_h.childrenIds = {});
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 = {});
14
17
  if (dataRef.current.itemData[itemId]) {
15
18
  return dataRef.current.itemData[itemId];
16
19
  }
17
20
  if (!instance.getState().loadingItems.includes(itemId)) {
18
- (_c = config.setLoadingItems) === null || _c === void 0 ? void 0 : _c.call(config, (loadingItems) => [...loadingItems, itemId]);
19
- (_d = config.asyncDataLoader) === null || _d === void 0 ? void 0 : _d.getItem(itemId).then((item) => {
20
- var _a, _b;
21
+ instance.applySubStateUpdate("loadingItems", (loadingItems) => [
22
+ ...loadingItems,
23
+ itemId,
24
+ ]);
25
+ (_c = config.asyncDataLoader) === null || _c === void 0 ? void 0 : _c.getItem(itemId).then((item) => {
26
+ var _a;
21
27
  dataRef.current.itemData[itemId] = item;
22
28
  (_a = config.onLoadedItem) === null || _a === void 0 ? void 0 : _a.call(config, itemId, item);
23
- (_b = config.setLoadingItems) === null || _b === void 0 ? void 0 : _b.call(config, (loadingItems) => loadingItems.filter((id) => id !== itemId));
29
+ instance.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
24
30
  });
25
31
  }
26
- return (_f = (_e = config.createLoadingItemData) === null || _e === void 0 ? void 0 : _e.call(config)) !== null && _f !== void 0 ? _f : null;
32
+ return (_e = (_d = config.createLoadingItemData) === null || _d === void 0 ? void 0 : _d.call(config)) !== null && _e !== void 0 ? _e : null;
27
33
  }, retrieveChildrenIds: (itemId) => {
28
- var _a, _b, _c, _d, _e, _f;
29
- var _g, _h;
34
+ var _a, _b, _c, _d, _e;
35
+ var _f, _g;
30
36
  const config = instance.getConfig();
31
37
  const dataRef = instance.getDataRef();
32
- (_a = (_g = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_g.itemData = {});
33
- (_b = (_h = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_h.childrenIds = {});
38
+ (_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_f.itemData = {});
39
+ (_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_g.childrenIds = {});
34
40
  if (dataRef.current.childrenIds[itemId]) {
35
41
  return dataRef.current.childrenIds[itemId];
36
42
  }
37
43
  if (instance.getState().loadingItems.includes(itemId)) {
38
44
  return [];
39
45
  }
40
- (_c = config.setLoadingItems) === null || _c === void 0 ? void 0 : _c.call(config, (loadingItems) => [...loadingItems, itemId]);
41
- if ((_d = config.asyncDataLoader) === null || _d === void 0 ? void 0 : _d.getChildrenWithData) {
42
- (_e = config.asyncDataLoader) === null || _e === void 0 ? void 0 : _e.getChildrenWithData(itemId).then((children) => {
43
- var _a, _b, _c;
46
+ instance.applySubStateUpdate("loadingItems", (loadingItems) => [
47
+ ...loadingItems,
48
+ itemId,
49
+ ]);
50
+ if ((_c = config.asyncDataLoader) === null || _c === void 0 ? void 0 : _c.getChildrenWithData) {
51
+ (_d = config.asyncDataLoader) === null || _d === void 0 ? void 0 : _d.getChildrenWithData(itemId).then((children) => {
52
+ var _a, _b;
44
53
  for (const { id, data } of children) {
45
54
  dataRef.current.itemData[id] = data;
46
55
  (_a = config.onLoadedItem) === null || _a === void 0 ? void 0 : _a.call(config, id, data);
@@ -48,16 +57,16 @@ export const asyncDataLoaderFeature = {
48
57
  const childrenIds = children.map(({ id }) => id);
49
58
  dataRef.current.childrenIds[itemId] = childrenIds;
50
59
  (_b = config.onLoadedChildren) === null || _b === void 0 ? void 0 : _b.call(config, itemId, childrenIds);
51
- (_c = config.setLoadingItems) === null || _c === void 0 ? void 0 : _c.call(config, (loadingItems) => loadingItems.filter((id) => id !== itemId));
60
+ instance.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
52
61
  instance.rebuildTree();
53
62
  });
54
63
  }
55
64
  else {
56
- (_f = config.asyncDataLoader) === null || _f === void 0 ? void 0 : _f.getChildren(itemId).then((childrenIds) => {
57
- var _a, _b;
65
+ (_e = config.asyncDataLoader) === null || _e === void 0 ? void 0 : _e.getChildren(itemId).then((childrenIds) => {
66
+ var _a;
58
67
  dataRef.current.childrenIds[itemId] = childrenIds;
59
68
  (_a = config.onLoadedChildren) === null || _a === void 0 ? void 0 : _a.call(config, itemId, childrenIds);
60
- (_b = config.setLoadingItems) === null || _b === void 0 ? void 0 : _b.call(config, (loadingItems) => loadingItems.filter((id) => id !== itemId));
69
+ instance.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
61
70
  instance.rebuildTree();
62
71
  });
63
72
  }
@@ -3,7 +3,10 @@ import { makeStateUpdater } from "../../utils";
3
3
  export const dragAndDropFeature = {
4
4
  key: "dragAndDrop",
5
5
  dependingFeatures: ["main", "tree", "selection"],
6
- getDefaultConfig: (defaultConfig, tree) => (Object.assign({ canDrop: (_, target) => target.item.isFolder(), setDndState: makeStateUpdater("dnd", tree) }, defaultConfig)),
6
+ getDefaultConfig: (defaultConfig, tree) => (Object.assign({ canDrop: (_, target) => target.item.isFolder(), canDropForeignDragObject: () => false, setDndState: makeStateUpdater("dnd", tree) }, defaultConfig)),
7
+ stateHandlerNames: {
8
+ dnd: "setDndState",
9
+ },
7
10
  createTreeInstance: (prev, tree) => (Object.assign(Object.assign({}, prev), { getDropTarget: () => {
8
11
  var _a, _b;
9
12
  return (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.dragTarget) !== null && _b !== void 0 ? _b : null;
@@ -11,7 +14,7 @@ export const dragAndDropFeature = {
11
14
  createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { getProps: () => {
12
15
  var _a, _b, _c;
13
16
  return (Object.assign(Object.assign({}, prev.getProps()), { draggable: (_c = (_b = (_a = tree.getConfig()).isItemDraggable) === null || _b === void 0 ? void 0 : _b.call(_a, item)) !== null && _c !== void 0 ? _c : true, onDragStart: item.getMemoizedProp("dnd/onDragStart", () => (e) => {
14
- var _a, _b, _c, _d, _e;
17
+ var _a, _b, _c;
15
18
  const selectedItems = tree.getSelectedItems();
16
19
  const items = selectedItems.includes(item) ? selectedItems : [item];
17
20
  const config = tree.getConfig();
@@ -26,12 +29,12 @@ export const dragAndDropFeature = {
26
29
  const { format, data } = config.createForeignDragObject(items);
27
30
  (_c = e.dataTransfer) === null || _c === void 0 ? void 0 : _c.setData(format, data);
28
31
  }
29
- (_e = (_d = tree.getConfig()).setDndState) === null || _e === void 0 ? void 0 : _e.call(_d, {
32
+ tree.applySubStateUpdate("dnd", {
30
33
  draggedItems: items,
31
34
  draggingOverItem: tree.getFocusedItem(),
32
35
  });
33
36
  }), onDragOver: item.getMemoizedProp("dnd/onDragOver", () => (e) => {
34
- var _a, _b, _c, _d, _e;
37
+ var _a, _b, _c;
35
38
  const target = getDropTarget(e, item, tree);
36
39
  const dataRef = tree.getDataRef();
37
40
  if (!((_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) &&
@@ -47,14 +50,21 @@ export const dragAndDropFeature = {
47
50
  return;
48
51
  }
49
52
  dataRef.current.lastDragCode = nextDragCode;
50
- (_e = (_d = tree.getConfig()).setDndState) === null || _e === void 0 ? void 0 : _e.call(_d, (state) => (Object.assign(Object.assign({}, state), { dragTarget: target, draggingOverItem: item })));
53
+ tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { dragTarget: target, draggingOverItem: item })));
51
54
  }), onDragLeave: item.getMemoizedProp("dnd/onDragLeave", () => () => {
52
- var _a, _b;
53
55
  const dataRef = tree.getDataRef();
54
56
  dataRef.current.lastDragCode = "no-drag";
55
- (_b = (_a = tree.getConfig()).setDndState) === null || _b === void 0 ? void 0 : _b.call(_a, (state) => (Object.assign(Object.assign({}, state), { draggingOverItem: undefined, dragTarget: undefined })));
57
+ tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { draggingOverItem: undefined, dragTarget: undefined })));
58
+ }), onDragEnd: item.getMemoizedProp("dnd/onDragEnd", () => (e) => {
59
+ var _a, _b, _c;
60
+ const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
61
+ tree.applySubStateUpdate("dnd", null);
62
+ if (e.dataTransfer.dropEffect === "none" || !draggedItems) {
63
+ return;
64
+ }
65
+ (_c = (_b = tree.getConfig()).onCompleteForeignDrop) === null || _c === void 0 ? void 0 : _c.call(_b, draggedItems);
56
66
  }), onDrop: item.getMemoizedProp("dnd/onDrop", () => (e) => {
57
- var _a, _b, _c, _d, _e;
67
+ var _a, _b, _c;
58
68
  const dataRef = tree.getDataRef();
59
69
  const target = getDropTarget(e, item, tree);
60
70
  if (!canDrop(e.dataTransfer, target, tree)) {
@@ -64,12 +74,12 @@ export const dragAndDropFeature = {
64
74
  const config = tree.getConfig();
65
75
  const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
66
76
  dataRef.current.lastDragCode = undefined;
67
- (_c = (_b = tree.getConfig()).setDndState) === null || _c === void 0 ? void 0 : _c.call(_b, null);
77
+ tree.applySubStateUpdate("dnd", null);
68
78
  if (draggedItems) {
69
- (_d = config.onDrop) === null || _d === void 0 ? void 0 : _d.call(config, draggedItems, target);
79
+ (_b = config.onDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target);
70
80
  }
71
81
  else {
72
- (_e = config.onDropForeignDragObject) === null || _e === void 0 ? void 0 : _e.call(config, e.dataTransfer, target);
82
+ (_c = config.onDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(config, e.dataTransfer, target);
73
83
  }
74
84
  // TODO rebuild tree?
75
85
  }) }));
@@ -78,16 +88,18 @@ export const dragAndDropFeature = {
78
88
  return target ? target.item.getId() === item.getId() : false;
79
89
  }, isDropTargetAbove: () => {
80
90
  const target = tree.getDropTarget();
81
- if (!target || target.childIndex === null)
91
+ if (!target ||
92
+ target.childIndex === null ||
93
+ target.item !== item.getParent())
82
94
  return false;
83
- const targetIndex = target.item.getItemMeta().index;
84
- return targetIndex + target.childIndex + 1 === item.getItemMeta().index;
95
+ return target.childIndex === item.getItemMeta().posInSet;
85
96
  }, isDropTargetBelow: () => {
86
97
  const target = tree.getDropTarget();
87
- if (!target || target.childIndex === null)
98
+ if (!target ||
99
+ target.childIndex === null ||
100
+ target.item !== item.getParent())
88
101
  return false;
89
- const targetIndex = target.item.getItemMeta().index;
90
- return targetIndex + target.childIndex === item.getItemMeta().index;
102
+ return target.childIndex - 1 === item.getItemMeta().posInSet;
91
103
  }, isDraggingOver: () => {
92
104
  var _a, _b;
93
105
  return ((_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggingOverItem) === null || _b === void 0 ? void 0 : _b.getId()) === item.getId();
@@ -9,7 +9,12 @@ export type DndState<T> = {
9
9
  };
10
10
  export type DropTarget<T> = {
11
11
  item: ItemInstance<T>;
12
- childIndex: number | null;
12
+ childIndex: number;
13
+ insertionIndex: number;
14
+ } | {
15
+ item: ItemInstance<T>;
16
+ childIndex: null;
17
+ insertionIndex: null;
13
18
  };
14
19
  export declare enum DropTargetPosition {
15
20
  Top = "top",
@@ -35,6 +40,14 @@ export type DragAndDropFeatureDef<T> = {
35
40
  canDropForeignDragObject?: (dataTransfer: DataTransfer, target: DropTarget<T>) => boolean;
36
41
  onDrop?: (items: ItemInstance<T>[], target: DropTarget<T>) => void;
37
42
  onDropForeignDragObject?: (dataTransfer: DataTransfer, target: DropTarget<T>) => void;
43
+ /** Runs in the onDragEnd event, if `ev.dataTransfer.dropEffect` is not `none`, i.e. the drop
44
+ * was not aborted. No target is provided as parameter since the target may be a foreign drop target.
45
+ * This is useful to seperate out the logic to move dragged items out of their previous parents.
46
+ * Use `onDrop` to handle drop-related logic.
47
+ *
48
+ * This ignores the `canDrop` handler, since the drop target is unknown in this handler.
49
+ */
50
+ onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
38
51
  };
39
52
  treeInstance: {
40
53
  getDropTarget: () => DropTarget<T> | null;
@@ -3,4 +3,4 @@ import { DropTarget } from "./types";
3
3
  export declare const getDragCode: ({ item, childIndex }: DropTarget<any>) => string;
4
4
  export declare const getDropOffset: (e: any, item: ItemInstance<any>) => number;
5
5
  export declare const canDrop: (dataTransfer: DataTransfer | null, target: DropTarget<any>, tree: TreeInstance<any>) => boolean;
6
- export declare const getDropTarget: (e: any, item: ItemInstance<any>, tree: TreeInstance<any>) => DropTarget<any>;
6
+ export declare const getDropTarget: (e: any, item: ItemInstance<any>, tree: TreeInstance<any>, canDropInbetween?: boolean | undefined) => DropTarget<any>;