@headless-tree/core 0.0.4 → 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 (91) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/lib/cjs/core/create-tree.js +11 -10
  3. package/lib/cjs/features/async-data-loader/feature.js +30 -21
  4. package/lib/cjs/features/drag-and-drop/feature.js +34 -22
  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 +4 -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 +6 -4
  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 +41 -24
  18. package/lib/cjs/features/tree/types.d.ts +7 -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 +11 -10
  31. package/lib/esm/features/async-data-loader/feature.js +30 -21
  32. package/lib/esm/features/drag-and-drop/feature.js +34 -22
  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 +4 -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 +6 -4
  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 +41 -24
  46. package/lib/esm/features/tree/types.d.ts +7 -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 +3 -3
  59. package/src/core/create-tree.ts +12 -8
  60. package/src/features/async-data-loader/feature.ts +15 -5
  61. package/src/features/drag-and-drop/feature.ts +42 -20
  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 +7 -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 +8 -3
  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 +43 -23
  74. package/src/features/tree/types.ts +10 -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/tsconfig.json +1 -1
  82. package/lib/cjs/data-adapters/nested-data-adapter.d.ts +0 -9
  83. package/lib/cjs/data-adapters/nested-data-adapter.js +0 -32
  84. package/lib/cjs/data-adapters/types.d.ts +0 -7
  85. package/lib/cjs/data-adapters/types.js +0 -2
  86. package/lib/esm/data-adapters/nested-data-adapter.d.ts +0 -9
  87. package/lib/esm/data-adapters/nested-data-adapter.js +0 -28
  88. package/lib/esm/data-adapters/types.d.ts +0 -7
  89. package/lib/esm/data-adapters/types.js +0 -1
  90. package/src/data-adapters/nested-data-adapter.ts +0 -48
  91. package/src/data-adapters/types.ts +0 -9
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @headless-tree/core
2
2
 
3
+ ## 0.0.6
4
+
5
+ ### Patch Changes
6
+
7
+ - bc9c446: dev release
8
+
9
+ ## 0.0.5
10
+
11
+ ### Patch Changes
12
+
13
+ - 751682a: dev release
14
+
3
15
  ## 0.0.4
4
16
 
5
17
  ### Patch Changes
@@ -11,11 +11,12 @@ const buildItemInstance = (features, tree, itemId) => {
11
11
  return itemInstance;
12
12
  };
13
13
  const createTree = (initialConfig) => {
14
- var _a, _b, _c, _d, _e;
14
+ var _a, _b, _c, _d, _e, _f;
15
15
  const treeInstance = {};
16
16
  const additionalFeatures = [feature_1.treeFeature, ...((_a = initialConfig.features) !== null && _a !== void 0 ? _a : [])];
17
- 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; }, (_b = initialConfig.state) !== null && _b !== void 0 ? _b : {});
17
+ 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 : {});
18
18
  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);
19
+ const stateHandlerNames = additionalFeatures.reduce((acc, feature) => (Object.assign(Object.assign({}, acc), feature.stateHandlerNames)), {});
19
20
  let treeElement;
20
21
  const treeDataRef = { current: {} };
21
22
  const itemInstancesMap = {};
@@ -60,10 +61,13 @@ const createTree = (initialConfig) => {
60
61
  key: "main",
61
62
  createTreeInstance: (prev) => (Object.assign(Object.assign({}, prev), { getState: () => state, setState: (updater) => {
62
63
  var _a;
63
- state = typeof updater === "function" ? updater(state) : updater;
64
+ // Not necessary, since I think the subupdate below keeps the state fresh anyways?
65
+ // state = typeof updater === "function" ? updater(state) : updater;
64
66
  (_a = config.setState) === null || _a === void 0 ? void 0 : _a.call(config, state);
65
- eachFeature((feature) => { var _a; return (_a = feature.setState) === null || _a === void 0 ? void 0 : _a.call(feature, treeInstance); });
66
- eachFeature((feature) => { var _a; return (_a = feature.onStateOrConfigChange) === null || _a === void 0 ? void 0 : _a.call(feature, treeInstance); });
67
+ }, applySubStateUpdate: (stateName, updater) => {
68
+ state[stateName] =
69
+ typeof updater === "function" ? updater(state[stateName]) : updater;
70
+ config[stateHandlerNames[stateName]](state[stateName]);
67
71
  }, rebuildTree: () => {
68
72
  var _a;
69
73
  rebuildItemMeta(mainFeature);
@@ -72,10 +76,7 @@ const createTree = (initialConfig) => {
72
76
  config = typeof updater === "function" ? updater(config) : updater;
73
77
  if (config.state) {
74
78
  state = Object.assign(Object.assign({}, state), config.state);
75
- eachFeature((feature) => { var _a; return (_a = feature.setState) === null || _a === void 0 ? void 0 : _a.call(feature, treeInstance); });
76
79
  }
77
- eachFeature((feature) => { var _a; return (_a = feature.onConfigChange) === null || _a === void 0 ? void 0 : _a.call(feature, treeInstance); });
78
- eachFeature((feature) => { var _a; return (_a = feature.onStateOrConfigChange) === null || _a === void 0 ? void 0 : _a.call(feature, treeInstance); });
79
80
  }, getItemInstance: (itemId) => itemInstancesMap[itemId], getItems: () => itemInstances, registerElement: (element) => {
80
81
  if (treeElement === element) {
81
82
  return;
@@ -107,8 +108,8 @@ const createTree = (initialConfig) => {
107
108
  // todo sort features
108
109
  const features = [mainFeature, ...additionalFeatures];
109
110
  for (const feature of features) {
110
- Object.assign(treeInstance, (_d = (_c = feature.createTreeInstance) === null || _c === void 0 ? void 0 : _c.call(feature, Object.assign({}, treeInstance), treeInstance)) !== null && _d !== void 0 ? _d : {});
111
- Object.assign(hotkeyPresets, (_e = feature.hotkeys) !== null && _e !== void 0 ? _e : {});
111
+ Object.assign(treeInstance, (_e = (_d = feature.createTreeInstance) === null || _d === void 0 ? void 0 : _d.call(feature, Object.assign({}, treeInstance), treeInstance)) !== null && _e !== void 0 ? _e : {});
112
+ Object.assign(hotkeyPresets, (_f = feature.hotkeys) !== null && _f !== void 0 ? _f : {});
112
113
  }
113
114
  rebuildItemMeta(mainFeature);
114
115
  return treeInstance;
@@ -7,43 +7,52 @@ exports.asyncDataLoaderFeature = {
7
7
  dependingFeatures: ["main"],
8
8
  getInitialState: (initialState) => (Object.assign({ loadingItems: [] }, initialState)),
9
9
  getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setLoadingItems: (0, utils_1.makeStateUpdater)("loadingItems", tree) }, defaultConfig)),
10
+ stateHandlerNames: {
11
+ loadingItems: "setLoadingItems",
12
+ },
10
13
  createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { retrieveItemData: (itemId) => {
11
- var _a, _b, _c, _d, _e, _f;
12
- var _g, _h;
14
+ var _a, _b, _c, _d, _e;
15
+ var _f, _g;
13
16
  const config = instance.getConfig();
14
17
  const dataRef = instance.getDataRef();
15
- (_a = (_g = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_g.itemData = {});
16
- (_b = (_h = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_h.childrenIds = {});
18
+ (_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_f.itemData = {});
19
+ (_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_g.childrenIds = {});
17
20
  if (dataRef.current.itemData[itemId]) {
18
21
  return dataRef.current.itemData[itemId];
19
22
  }
20
23
  if (!instance.getState().loadingItems.includes(itemId)) {
21
- (_c = config.setLoadingItems) === null || _c === void 0 ? void 0 : _c.call(config, (loadingItems) => [...loadingItems, itemId]);
22
- (_d = config.asyncDataLoader) === null || _d === void 0 ? void 0 : _d.getItem(itemId).then((item) => {
23
- var _a, _b;
24
+ instance.applySubStateUpdate("loadingItems", (loadingItems) => [
25
+ ...loadingItems,
26
+ itemId,
27
+ ]);
28
+ (_c = config.asyncDataLoader) === null || _c === void 0 ? void 0 : _c.getItem(itemId).then((item) => {
29
+ var _a;
24
30
  dataRef.current.itemData[itemId] = item;
25
31
  (_a = config.onLoadedItem) === null || _a === void 0 ? void 0 : _a.call(config, itemId, item);
26
- (_b = config.setLoadingItems) === null || _b === void 0 ? void 0 : _b.call(config, (loadingItems) => loadingItems.filter((id) => id !== itemId));
32
+ instance.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
27
33
  });
28
34
  }
29
- return (_f = (_e = config.createLoadingItemData) === null || _e === void 0 ? void 0 : _e.call(config)) !== null && _f !== void 0 ? _f : null;
35
+ return (_e = (_d = config.createLoadingItemData) === null || _d === void 0 ? void 0 : _d.call(config)) !== null && _e !== void 0 ? _e : null;
30
36
  }, retrieveChildrenIds: (itemId) => {
31
- var _a, _b, _c, _d, _e, _f;
32
- var _g, _h;
37
+ var _a, _b, _c, _d, _e;
38
+ var _f, _g;
33
39
  const config = instance.getConfig();
34
40
  const dataRef = instance.getDataRef();
35
- (_a = (_g = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_g.itemData = {});
36
- (_b = (_h = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_h.childrenIds = {});
41
+ (_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_f.itemData = {});
42
+ (_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_g.childrenIds = {});
37
43
  if (dataRef.current.childrenIds[itemId]) {
38
44
  return dataRef.current.childrenIds[itemId];
39
45
  }
40
46
  if (instance.getState().loadingItems.includes(itemId)) {
41
47
  return [];
42
48
  }
43
- (_c = config.setLoadingItems) === null || _c === void 0 ? void 0 : _c.call(config, (loadingItems) => [...loadingItems, itemId]);
44
- if ((_d = config.asyncDataLoader) === null || _d === void 0 ? void 0 : _d.getChildrenWithData) {
45
- (_e = config.asyncDataLoader) === null || _e === void 0 ? void 0 : _e.getChildrenWithData(itemId).then((children) => {
46
- var _a, _b, _c;
49
+ instance.applySubStateUpdate("loadingItems", (loadingItems) => [
50
+ ...loadingItems,
51
+ itemId,
52
+ ]);
53
+ if ((_c = config.asyncDataLoader) === null || _c === void 0 ? void 0 : _c.getChildrenWithData) {
54
+ (_d = config.asyncDataLoader) === null || _d === void 0 ? void 0 : _d.getChildrenWithData(itemId).then((children) => {
55
+ var _a, _b;
47
56
  for (const { id, data } of children) {
48
57
  dataRef.current.itemData[id] = data;
49
58
  (_a = config.onLoadedItem) === null || _a === void 0 ? void 0 : _a.call(config, id, data);
@@ -51,16 +60,16 @@ exports.asyncDataLoaderFeature = {
51
60
  const childrenIds = children.map(({ id }) => id);
52
61
  dataRef.current.childrenIds[itemId] = childrenIds;
53
62
  (_b = config.onLoadedChildren) === null || _b === void 0 ? void 0 : _b.call(config, itemId, childrenIds);
54
- (_c = config.setLoadingItems) === null || _c === void 0 ? void 0 : _c.call(config, (loadingItems) => loadingItems.filter((id) => id !== itemId));
63
+ instance.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
55
64
  instance.rebuildTree();
56
65
  });
57
66
  }
58
67
  else {
59
- (_f = config.asyncDataLoader) === null || _f === void 0 ? void 0 : _f.getChildren(itemId).then((childrenIds) => {
60
- var _a, _b;
68
+ (_e = config.asyncDataLoader) === null || _e === void 0 ? void 0 : _e.getChildren(itemId).then((childrenIds) => {
69
+ var _a;
61
70
  dataRef.current.childrenIds[itemId] = childrenIds;
62
71
  (_a = config.onLoadedChildren) === null || _a === void 0 ? void 0 : _a.call(config, itemId, childrenIds);
63
- (_b = config.setLoadingItems) === null || _b === void 0 ? void 0 : _b.call(config, (loadingItems) => loadingItems.filter((id) => id !== itemId));
72
+ instance.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
64
73
  instance.rebuildTree();
65
74
  });
66
75
  }
@@ -6,15 +6,18 @@ const utils_2 = require("../../utils");
6
6
  exports.dragAndDropFeature = {
7
7
  key: "dragAndDrop",
8
8
  dependingFeatures: ["main", "tree", "selection"],
9
- getDefaultConfig: (defaultConfig, tree) => (Object.assign({ canDrop: (_, target) => target.item.isFolder(), setDndState: (0, utils_2.makeStateUpdater)("dnd", tree) }, defaultConfig)),
9
+ getDefaultConfig: (defaultConfig, tree) => (Object.assign({ canDrop: (_, target) => target.item.isFolder(), canDropForeignDragObject: () => false, setDndState: (0, utils_2.makeStateUpdater)("dnd", tree) }, defaultConfig)),
10
+ stateHandlerNames: {
11
+ dnd: "setDndState",
12
+ },
10
13
  createTreeInstance: (prev, tree) => (Object.assign(Object.assign({}, prev), { getDropTarget: () => {
11
14
  var _a, _b;
12
15
  return (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.dragTarget) !== null && _b !== void 0 ? _b : null;
13
16
  } })),
14
17
  createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { getProps: () => {
15
18
  var _a, _b, _c;
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: (e) => {
17
- var _a, _b, _c, _d, _e;
19
+ 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) => {
20
+ var _a, _b, _c;
18
21
  const selectedItems = tree.getSelectedItems();
19
22
  const items = selectedItems.includes(item) ? selectedItems : [item];
20
23
  const config = tree.getConfig();
@@ -29,12 +32,12 @@ exports.dragAndDropFeature = {
29
32
  const { format, data } = config.createForeignDragObject(items);
30
33
  (_c = e.dataTransfer) === null || _c === void 0 ? void 0 : _c.setData(format, data);
31
34
  }
32
- (_e = (_d = tree.getConfig()).setDndState) === null || _e === void 0 ? void 0 : _e.call(_d, {
35
+ tree.applySubStateUpdate("dnd", {
33
36
  draggedItems: items,
34
37
  draggingOverItem: tree.getFocusedItem(),
35
38
  });
36
- }, onDragOver: (e) => {
37
- var _a, _b, _c, _d, _e;
39
+ }), onDragOver: item.getMemoizedProp("dnd/onDragOver", () => (e) => {
40
+ var _a, _b, _c;
38
41
  const target = (0, utils_1.getDropTarget)(e, item, tree);
39
42
  const dataRef = tree.getDataRef();
40
43
  if (!((_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) &&
@@ -50,14 +53,21 @@ exports.dragAndDropFeature = {
50
53
  return;
51
54
  }
52
55
  dataRef.current.lastDragCode = nextDragCode;
53
- (_e = (_d = tree.getConfig()).setDndState) === null || _e === void 0 ? void 0 : _e.call(_d, (state) => (Object.assign(Object.assign({}, state), { dragTarget: target, draggingOverItem: item })));
54
- }, onDragLeave: () => {
55
- var _a, _b;
56
+ tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { dragTarget: target, draggingOverItem: item })));
57
+ }), onDragLeave: item.getMemoizedProp("dnd/onDragLeave", () => () => {
56
58
  const dataRef = tree.getDataRef();
57
59
  dataRef.current.lastDragCode = "no-drag";
58
- (_b = (_a = tree.getConfig()).setDndState) === null || _b === void 0 ? void 0 : _b.call(_a, (state) => (Object.assign(Object.assign({}, state), { draggingOverItem: undefined, dragTarget: undefined })));
59
- }, onDrop: (e) => {
60
- var _a, _b, _c, _d, _e;
60
+ tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { draggingOverItem: undefined, dragTarget: undefined })));
61
+ }), onDragEnd: item.getMemoizedProp("dnd/onDragEnd", () => (e) => {
62
+ var _a, _b, _c;
63
+ const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
64
+ tree.applySubStateUpdate("dnd", null);
65
+ if (e.dataTransfer.dropEffect === "none" || !draggedItems) {
66
+ return;
67
+ }
68
+ (_c = (_b = tree.getConfig()).onCompleteForeignDrop) === null || _c === void 0 ? void 0 : _c.call(_b, draggedItems);
69
+ }), onDrop: item.getMemoizedProp("dnd/onDrop", () => (e) => {
70
+ var _a, _b, _c;
61
71
  const dataRef = tree.getDataRef();
62
72
  const target = (0, utils_1.getDropTarget)(e, item, tree);
63
73
  if (!(0, utils_1.canDrop)(e.dataTransfer, target, tree)) {
@@ -67,30 +77,32 @@ exports.dragAndDropFeature = {
67
77
  const config = tree.getConfig();
68
78
  const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
69
79
  dataRef.current.lastDragCode = undefined;
70
- (_c = (_b = tree.getConfig()).setDndState) === null || _c === void 0 ? void 0 : _c.call(_b, null);
80
+ tree.applySubStateUpdate("dnd", null);
71
81
  if (draggedItems) {
72
- (_d = config.onDrop) === null || _d === void 0 ? void 0 : _d.call(config, draggedItems, target);
82
+ (_b = config.onDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target);
73
83
  }
74
84
  else {
75
- (_e = config.onDropForeignDragObject) === null || _e === void 0 ? void 0 : _e.call(config, e.dataTransfer, target);
85
+ (_c = config.onDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(config, e.dataTransfer, target);
76
86
  }
77
87
  // TODO rebuild tree?
78
- } }));
88
+ }) }));
79
89
  }, isDropTarget: () => {
80
90
  const target = tree.getDropTarget();
81
91
  return target ? target.item.getId() === item.getId() : false;
82
92
  }, isDropTargetAbove: () => {
83
93
  const target = tree.getDropTarget();
84
- if (!target || target.childIndex === null)
94
+ if (!target ||
95
+ target.childIndex === null ||
96
+ target.item !== item.getParent())
85
97
  return false;
86
- const targetIndex = target.item.getItemMeta().index;
87
- return targetIndex + target.childIndex + 1 === item.getItemMeta().index;
98
+ return target.childIndex === item.getItemMeta().posInSet;
88
99
  }, isDropTargetBelow: () => {
89
100
  const target = tree.getDropTarget();
90
- if (!target || target.childIndex === null)
101
+ if (!target ||
102
+ target.childIndex === null ||
103
+ target.item !== item.getParent())
91
104
  return false;
92
- const targetIndex = target.item.getItemMeta().index;
93
- return targetIndex + target.childIndex === item.getItemMeta().index;
105
+ return target.childIndex - 1 === item.getItemMeta().posInSet;
94
106
  }, isDraggingOver: () => {
95
107
  var _a, _b;
96
108
  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>;
@@ -34,29 +34,46 @@ const getDropTargetPosition = (offset, topLinePercentage, bottomLinePercentage)
34
34
  }
35
35
  return types_1.DropTargetPosition.Item;
36
36
  };
37
- const getDropTarget = (e, item, tree) => {
38
- var _a, _b;
37
+ const getDropTarget = (e, item, tree, canDropInbetween = tree.getConfig().canDropInbetween) => {
38
+ var _a, _b, _c, _d;
39
39
  const config = tree.getConfig();
40
- const offset = (0, exports.getDropOffset)(e, item);
41
- const dropOnItemTarget = { item, childIndex: null };
42
- const pos = getDropTargetPosition(offset, (_a = config.topLinePercentage) !== null && _a !== void 0 ? _a : 0.3, (_b = config.bottomLinePercentage) !== null && _b !== void 0 ? _b : 0.7);
43
- const inbetweenPos = getDropTargetPosition(offset, 0.5, 0.5);
44
- if (!config.canDropInbetween) {
45
- return dropOnItemTarget;
46
- }
47
- if (!(0, exports.canDrop)(e.dataTransfer, dropOnItemTarget, tree)) {
48
- return {
49
- item: item.getParent(),
50
- childIndex: item.getIndexInParent() +
51
- (inbetweenPos === types_1.DropTargetPosition.Top ? 0 : 1),
52
- };
40
+ const draggedItems = (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) !== null && _b !== void 0 ? _b : [];
41
+ const itemTarget = { item, childIndex: null, insertionIndex: null };
42
+ const parentTarget = {
43
+ item: item.getParent(),
44
+ childIndex: null,
45
+ insertionIndex: null,
46
+ };
47
+ if (!canDropInbetween) {
48
+ if (!(0, exports.canDrop)(e.dataTransfer, parentTarget, tree)) {
49
+ return (0, exports.getDropTarget)(e, item.getParent(), tree, false);
50
+ }
51
+ return itemTarget;
53
52
  }
53
+ const canDropInside = (0, exports.canDrop)(e.dataTransfer, itemTarget, tree);
54
+ const offset = (0, exports.getDropOffset)(e, item);
55
+ const pos = canDropInside
56
+ ? getDropTargetPosition(offset, (_c = config.topLinePercentage) !== null && _c !== void 0 ? _c : 0.3, (_d = config.bottomLinePercentage) !== null && _d !== void 0 ? _d : 0.7)
57
+ : getDropTargetPosition(offset, 0.5, 0.5);
54
58
  if (pos === types_1.DropTargetPosition.Item) {
55
- return dropOnItemTarget;
59
+ return itemTarget;
60
+ }
61
+ if (!(0, exports.canDrop)(e.dataTransfer, parentTarget, tree)) {
62
+ return (0, exports.getDropTarget)(e, item.getParent(), tree, false);
56
63
  }
64
+ const childIndex = item.getIndexInParent() + (pos === types_1.DropTargetPosition.Top ? 0 : 1);
65
+ const numberOfDragItemsBeforeTarget = item
66
+ .getParent()
67
+ .getChildren()
68
+ .slice(0, childIndex)
69
+ .reduce((counter, child) => child && (draggedItems === null || draggedItems === void 0 ? void 0 : draggedItems.some((i) => i.getId() === child.getId()))
70
+ ? ++counter
71
+ : counter, 0);
57
72
  return {
58
73
  item: item.getParent(),
59
- childIndex: item.getIndexInParent() + (pos === types_1.DropTargetPosition.Top ? 0 : 1),
74
+ childIndex,
75
+ // TODO performance could be improved by computing this only when dragcode changed
76
+ insertionIndex: childIndex - numberOfDragItemsBeforeTarget,
60
77
  };
61
78
  };
62
79
  exports.getDropTarget = getDropTarget;
@@ -16,24 +16,27 @@ exports.expandAllFeature = {
16
16
  dependingFeatures: ["main", "tree"],
17
17
  createTreeInstance: (prev, tree) => (Object.assign(Object.assign({}, prev), { expandAll: (cancelToken) => __awaiter(void 0, void 0, void 0, function* () {
18
18
  yield Promise.all(tree.getItems().map((item) => item.expandAll(cancelToken)));
19
- }), collapseAll: () => __awaiter(void 0, void 0, void 0, function* () {
20
- var _a, _b;
21
- (_b = (_a = tree.getConfig()).setExpandedItems) === null || _b === void 0 ? void 0 : _b.call(_a, []);
22
- }) })),
19
+ }), collapseAll: () => {
20
+ tree.applySubStateUpdate("expandedItems", []);
21
+ tree.rebuildTree();
22
+ } })),
23
23
  createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { expandAll: (cancelToken) => __awaiter(void 0, void 0, void 0, function* () {
24
24
  if (cancelToken === null || cancelToken === void 0 ? void 0 : cancelToken.current) {
25
25
  return;
26
26
  }
27
+ if (!item.isFolder()) {
28
+ return;
29
+ }
27
30
  item.expand();
28
31
  yield (0, utils_1.poll)(() => !tree.getState().loadingItems.includes(item.getId()));
29
32
  yield Promise.all(item.getChildren().map((child) => __awaiter(void 0, void 0, void 0, function* () {
30
33
  yield (0, utils_1.poll)(() => !tree.getState().loadingItems.includes(child.getId()));
31
34
  yield (child === null || child === void 0 ? void 0 : child.expandAll(cancelToken));
32
35
  })));
33
- }), collapseAll: () => __awaiter(void 0, void 0, void 0, function* () {
34
- yield Promise.all(item.getChildren().map((child) => __awaiter(void 0, void 0, void 0, function* () {
35
- yield (child === null || child === void 0 ? void 0 : child.collapseAll());
36
- })));
36
+ }), collapseAll: () => {
37
+ for (const child of item.getChildren()) {
38
+ child === null || child === void 0 ? void 0 : child.collapseAll();
39
+ }
37
40
  item.collapse();
38
- }) })),
41
+ } })),
39
42
  };
@@ -5,13 +5,13 @@ export type ExpandAllFeatureDef = {
5
5
  expandAll: (cancelToken?: {
6
6
  current: boolean;
7
7
  }) => Promise<void>;
8
- collapseAll: () => Promise<void>;
8
+ collapseAll: () => void;
9
9
  };
10
10
  itemInstance: {
11
11
  expandAll: (cancelToken?: {
12
12
  current: boolean;
13
13
  }) => Promise<void>;
14
- collapseAll: () => Promise<void>;
14
+ collapseAll: () => void;
15
15
  };
16
16
  hotkeys: never;
17
17
  };
@@ -1,13 +1,16 @@
1
- import { FeatureImplementation, HotkeysConfig, ItemInstance, SetStateFn, TreeConfig, TreeState } from "../../types/core";
1
+ import { FeatureImplementation, HotkeysConfig, ItemInstance, SetStateFn, TreeConfig, TreeState, Updater } from "../../types/core";
2
2
  import { ItemMeta } from "../tree/types";
3
3
  export type MainFeatureDef<T = any> = {
4
4
  state: {};
5
5
  config: {
6
6
  features?: FeatureImplementation<any>[];
7
+ initialState?: Partial<TreeState<T>>;
7
8
  state?: Partial<TreeState<T>>;
8
9
  setState?: SetStateFn<TreeState<T>>;
9
10
  };
10
11
  treeInstance: {
12
+ /** @internal */
13
+ applySubStateUpdate: <K extends keyof TreeState<any>>(stateName: K, updater: Updater<TreeState<T>[K]>) => void;
11
14
  setState: SetStateFn<TreeState<T>>;
12
15
  getState: () => TreeState<T>;
13
16
  setConfig: SetStateFn<TreeConfig<T>>;
@@ -6,36 +6,37 @@ exports.renamingFeature = {
6
6
  key: "renaming",
7
7
  dependingFeatures: ["main", "tree"],
8
8
  getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setRenamingItem: (0, utils_1.makeStateUpdater)("renamingItem", tree), setRenamingValue: (0, utils_1.makeStateUpdater)("renamingValue", tree), canRename: () => true }, defaultConfig)),
9
+ stateHandlerNames: {
10
+ renamingItem: "setRenamingItem",
11
+ renamingValue: "setRenamingValue",
12
+ },
9
13
  createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { startRenamingItem: (itemId) => {
10
- var _a, _b;
11
14
  const config = instance.getConfig();
12
15
  const item = instance.getItemInstance(itemId);
13
16
  if (!item.canRename()) {
14
17
  return;
15
18
  }
16
- (_a = config.setRenamingItem) === null || _a === void 0 ? void 0 : _a.call(config, itemId);
17
- (_b = config.setRenamingValue) === null || _b === void 0 ? void 0 : _b.call(config, item.getItemName());
19
+ instance.applySubStateUpdate("renamingItem", itemId);
20
+ instance.applySubStateUpdate("renamingValue", item.getItemName());
18
21
  }, getRenamingItem: () => {
19
22
  const itemId = instance.getState().renamingItem;
20
23
  return itemId ? instance.getItemInstance(itemId) : null;
21
24
  }, getRenamingValue: () => instance.getState().renamingValue || "", abortRenaming: () => {
22
- var _a, _b;
23
- (_b = (_a = instance.getConfig()).setRenamingItem) === null || _b === void 0 ? void 0 : _b.call(_a, null);
25
+ instance.applySubStateUpdate("renamingItem", null);
24
26
  }, completeRenaming: () => {
25
- var _a, _b, _c;
27
+ var _a;
26
28
  const config = instance.getConfig();
27
29
  const item = instance.getRenamingItem();
28
30
  if (item) {
29
31
  (_a = config.onRename) === null || _a === void 0 ? void 0 : _a.call(config, item, instance.getState().renamingValue || "");
30
32
  }
31
- (_c = (_b = instance.getConfig()).setRenamingItem) === null || _c === void 0 ? void 0 : _c.call(_b, null);
33
+ instance.applySubStateUpdate("renamingItem", null);
32
34
  }, isRenamingItem: () => !!instance.getState().renamingItem })),
33
35
  createItemInstance: (prev, instance, tree) => (Object.assign(Object.assign({}, prev), { getRenameInputProps: () => ({
34
36
  onBlur: () => tree.abortRenaming(),
35
37
  value: tree.getRenamingValue(),
36
38
  onChange: (e) => {
37
- var _a, _b;
38
- (_b = (_a = tree.getConfig()).setRenamingValue) === null || _b === void 0 ? void 0 : _b.call(_a, e.target.value);
39
+ tree.applySubStateUpdate("renamingValue", e.target.value);
39
40
  },
40
41
  }), canRename: () => { var _a, _b, _c; return (_c = (_b = (_a = tree.getConfig()).canRename) === null || _b === void 0 ? void 0 : _b.call(_a, instance)) !== null && _c !== void 0 ? _c : true; }, isRenaming: () => instance.getId() === tree.getState().renamingItem })),
41
42
  hotkeys: {
@@ -8,16 +8,19 @@ exports.searchFeature = {
8
8
  getInitialState: (initialState) => (Object.assign({ search: null }, initialState)),
9
9
  getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setSearch: (0, utils_1.makeStateUpdater)("search", tree), isSearchMatchingItem: (search, item) => search.length > 0 &&
10
10
  item.getItemName().toLowerCase().includes(search.toLowerCase()) }, defaultConfig)),
11
+ stateHandlerNames: {
12
+ search: "setSearch",
13
+ },
11
14
  createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { setSearch: (search) => {
12
- var _a, _b, _c;
13
- (_b = (_a = instance.getConfig()).setSearch) === null || _b === void 0 ? void 0 : _b.call(_a, search);
14
- (_c = instance
15
+ var _a;
16
+ instance.applySubStateUpdate("search", search);
17
+ (_a = instance
15
18
  .getItems()
16
19
  .find((item) => {
17
20
  var _a, _b;
18
21
  return (_b = (_a = instance
19
22
  .getConfig()).isSearchMatchingItem) === null || _b === void 0 ? void 0 : _b.call(_a, instance.getSearchValue(), item);
20
- })) === null || _c === void 0 ? void 0 : _c.setFocused();
23
+ })) === null || _a === void 0 ? void 0 : _a.setFocused();
21
24
  }, openSearch: (initialValue = "") => {
22
25
  instance.setSearch(initialValue);
23
26
  setTimeout(() => {
@@ -39,7 +42,7 @@ exports.searchFeature = {
39
42
  value: instance.getSearchValue(),
40
43
  onChange: (e) => instance.setSearch(e.target.value),
41
44
  onBlur: () => instance.closeSearch(),
42
- }), getSearchMatchingItems: (0, utils_1.memo)((search, items) => items.filter((item) => { var _a, _b; return (_b = (_a = instance.getConfig()).isSearchMatchingItem) === null || _b === void 0 ? void 0 : _b.call(_a, search, item); }), () => [instance.getSearchValue(), instance.getItems()]) })),
45
+ }), getSearchMatchingItems: (0, utils_1.memo)((search, items) => items.filter((item) => { var _a, _b; return search && ((_b = (_a = instance.getConfig()).isSearchMatchingItem) === null || _b === void 0 ? void 0 : _b.call(_a, search, item)); }), () => [instance.getSearchValue(), instance.getItems()]) })),
43
46
  createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { isMatchingSearch: () => tree.getSearchMatchingItems().some((i) => i.getId() === item.getId()) })),
44
47
  hotkeys: {
45
48
  openSearch: {
@@ -60,30 +63,41 @@ exports.searchFeature = {
60
63
  tree.closeSearch();
61
64
  },
62
65
  },
66
+ submitSearch: {
67
+ hotkey: "Enter",
68
+ allowWhenInputFocused: true,
69
+ isEnabled: (tree) => tree.isSearchOpen(),
70
+ handler: (e, tree) => {
71
+ tree.closeSearch();
72
+ tree.setSelectedItems([tree.getFocusedItem().getId()]);
73
+ },
74
+ },
63
75
  nextSearchItem: {
64
76
  hotkey: "ArrowDown",
65
77
  allowWhenInputFocused: true,
78
+ canRepeat: true,
66
79
  isEnabled: (tree) => tree.isSearchOpen(),
67
80
  handler: (e, tree) => {
68
- // TODO scroll into view
69
81
  const focusItem = tree
70
82
  .getSearchMatchingItems()
71
83
  .find((item) => item.getItemMeta().index >
72
84
  tree.getFocusedItem().getItemMeta().index);
73
85
  focusItem === null || focusItem === void 0 ? void 0 : focusItem.setFocused();
86
+ focusItem === null || focusItem === void 0 ? void 0 : focusItem.scrollTo({ block: "nearest", inline: "nearest" });
74
87
  },
75
88
  },
76
89
  previousSearchItem: {
77
90
  hotkey: "ArrowUp",
78
91
  allowWhenInputFocused: true,
92
+ canRepeat: true,
79
93
  isEnabled: (tree) => tree.isSearchOpen(),
80
94
  handler: (e, tree) => {
81
- // TODO scroll into view
82
95
  const focusItem = [...tree.getSearchMatchingItems()]
83
96
  .reverse()
84
97
  .find((item) => item.getItemMeta().index <
85
98
  tree.getFocusedItem().getItemMeta().index);
86
99
  focusItem === null || focusItem === void 0 ? void 0 : focusItem.setFocused();
100
+ focusItem === null || focusItem === void 0 ? void 0 : focusItem.scrollTo({ block: "nearest", inline: "nearest" });
87
101
  },
88
102
  },
89
103
  },
@@ -29,5 +29,5 @@ export type SearchFeatureDef<T> = {
29
29
  itemInstance: {
30
30
  isMatchingSearch: () => boolean;
31
31
  };
32
- hotkeys: "openSearch" | "closeSearch" | "nextSearchItem" | "previousSearchItem";
32
+ hotkeys: "openSearch" | "closeSearch" | "submitSearch" | "nextSearchItem" | "previousSearchItem";
33
33
  };
@@ -7,9 +7,11 @@ exports.selectionFeature = {
7
7
  dependingFeatures: ["main", "tree"],
8
8
  getInitialState: (initialState) => (Object.assign({ selectedItems: [] }, initialState)),
9
9
  getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setSelectedItems: (0, utils_1.makeStateUpdater)("selectedItems", tree) }, defaultConfig)),
10
+ stateHandlerNames: {
11
+ selectedItems: "setSelectedItems",
12
+ },
10
13
  createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { setSelectedItems: (selectedItems) => {
11
- var _a, _b;
12
- (_b = (_a = instance.getConfig()).setSelectedItems) === null || _b === void 0 ? void 0 : _b.call(_a, selectedItems);
14
+ instance.applySubStateUpdate("selectedItems", selectedItems);
13
15
  },
14
16
  // TODO memo
15
17
  getSelectedItems: () => {
@@ -51,7 +53,7 @@ exports.selectionFeature = {
51
53
  else {
52
54
  item.select();
53
55
  }
54
- }, getProps: () => (Object.assign(Object.assign({}, prev.getProps()), { onClick: (e) => {
56
+ }, getProps: () => (Object.assign(Object.assign({}, prev.getProps()), { "aria-selected": item.isSelected() ? "true" : "false", onClick: item.getMemoizedProp("selection/onClick", () => (e) => {
55
57
  var _a, _b;
56
58
  if (e.shiftKey) {
57
59
  item.selectUpTo(e.ctrlKey || e.metaKey);
@@ -63,7 +65,7 @@ exports.selectionFeature = {
63
65
  tree.setSelectedItems([item.getItemMeta().itemId]);
64
66
  }
65
67
  (_b = (_a = prev.getProps()).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
66
- } })) })),
68
+ }) })) })),
67
69
  hotkeys: {
68
70
  // setSelectedItem: {
69
71
  // hotkey: "space",