@headless-tree/core 0.0.10 → 0.0.12

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 (148) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/lib/cjs/core/build-proxified-instance.d.ts +2 -0
  3. package/lib/cjs/core/build-proxified-instance.js +58 -0
  4. package/lib/cjs/core/build-static-instance.d.ts +2 -0
  5. package/lib/cjs/core/build-static-instance.js +26 -0
  6. package/lib/cjs/core/create-tree.js +62 -40
  7. package/lib/cjs/features/async-data-loader/feature.d.ts +1 -4
  8. package/lib/cjs/features/async-data-loader/feature.js +35 -23
  9. package/lib/cjs/features/async-data-loader/types.d.ts +4 -6
  10. package/lib/cjs/features/drag-and-drop/feature.d.ts +2 -3
  11. package/lib/cjs/features/drag-and-drop/feature.js +79 -44
  12. package/lib/cjs/features/drag-and-drop/types.d.ts +15 -6
  13. package/lib/cjs/features/drag-and-drop/utils.d.ts +2 -3
  14. package/lib/cjs/features/drag-and-drop/utils.js +140 -37
  15. package/lib/cjs/features/expand-all/feature.d.ts +1 -5
  16. package/lib/cjs/features/expand-all/feature.js +12 -6
  17. package/lib/cjs/features/hotkeys-core/feature.d.ts +1 -3
  18. package/lib/cjs/features/main/types.d.ts +8 -2
  19. package/lib/cjs/features/prop-memoization/feature.d.ts +2 -0
  20. package/lib/cjs/features/prop-memoization/feature.js +48 -0
  21. package/lib/cjs/features/prop-memoization/types.d.ts +10 -0
  22. package/lib/cjs/features/prop-memoization/types.js +2 -0
  23. package/lib/cjs/features/renaming/feature.d.ts +1 -4
  24. package/lib/cjs/features/renaming/feature.js +36 -22
  25. package/lib/cjs/features/renaming/types.d.ts +2 -2
  26. package/lib/cjs/features/search/feature.d.ts +1 -4
  27. package/lib/cjs/features/search/feature.js +38 -24
  28. package/lib/cjs/features/search/types.d.ts +0 -1
  29. package/lib/cjs/features/selection/feature.d.ts +1 -4
  30. package/lib/cjs/features/selection/feature.js +54 -35
  31. package/lib/cjs/features/selection/types.d.ts +1 -1
  32. package/lib/cjs/features/sync-data-loader/feature.d.ts +1 -3
  33. package/lib/cjs/features/sync-data-loader/feature.js +7 -2
  34. package/lib/cjs/features/tree/feature.d.ts +1 -5
  35. package/lib/cjs/features/tree/feature.js +97 -92
  36. package/lib/cjs/features/tree/types.d.ts +5 -8
  37. package/lib/cjs/index.d.ts +5 -1
  38. package/lib/cjs/index.js +4 -1
  39. package/lib/cjs/mddocs-entry.d.ts +10 -0
  40. package/lib/cjs/test-utils/test-tree-do.d.ts +23 -0
  41. package/lib/cjs/test-utils/test-tree-do.js +99 -0
  42. package/lib/cjs/test-utils/test-tree-expect.d.ts +15 -0
  43. package/lib/cjs/test-utils/test-tree-expect.js +62 -0
  44. package/lib/cjs/test-utils/test-tree.d.ts +47 -0
  45. package/lib/cjs/test-utils/test-tree.js +203 -0
  46. package/lib/cjs/types/core.d.ts +39 -24
  47. package/lib/cjs/utilities/errors.d.ts +1 -0
  48. package/lib/cjs/utilities/errors.js +5 -0
  49. package/lib/cjs/utilities/insert-items-at-target.js +10 -3
  50. package/lib/cjs/utilities/remove-items-from-parents.js +14 -8
  51. package/lib/cjs/utils.d.ts +3 -3
  52. package/lib/cjs/utils.js +6 -6
  53. package/lib/esm/core/build-proxified-instance.d.ts +2 -0
  54. package/lib/esm/core/build-proxified-instance.js +54 -0
  55. package/lib/esm/core/build-static-instance.d.ts +2 -0
  56. package/lib/esm/core/build-static-instance.js +22 -0
  57. package/lib/esm/core/create-tree.js +62 -40
  58. package/lib/esm/features/async-data-loader/feature.d.ts +1 -4
  59. package/lib/esm/features/async-data-loader/feature.js +35 -23
  60. package/lib/esm/features/async-data-loader/types.d.ts +4 -6
  61. package/lib/esm/features/drag-and-drop/feature.d.ts +2 -3
  62. package/lib/esm/features/drag-and-drop/feature.js +79 -44
  63. package/lib/esm/features/drag-and-drop/types.d.ts +15 -6
  64. package/lib/esm/features/drag-and-drop/utils.d.ts +2 -3
  65. package/lib/esm/features/drag-and-drop/utils.js +138 -34
  66. package/lib/esm/features/expand-all/feature.d.ts +1 -5
  67. package/lib/esm/features/expand-all/feature.js +12 -6
  68. package/lib/esm/features/hotkeys-core/feature.d.ts +1 -3
  69. package/lib/esm/features/main/types.d.ts +8 -2
  70. package/lib/esm/features/prop-memoization/feature.d.ts +2 -0
  71. package/lib/esm/features/prop-memoization/feature.js +45 -0
  72. package/lib/esm/features/prop-memoization/types.d.ts +10 -0
  73. package/lib/esm/features/prop-memoization/types.js +1 -0
  74. package/lib/esm/features/renaming/feature.d.ts +1 -4
  75. package/lib/esm/features/renaming/feature.js +36 -22
  76. package/lib/esm/features/renaming/types.d.ts +2 -2
  77. package/lib/esm/features/search/feature.d.ts +1 -4
  78. package/lib/esm/features/search/feature.js +38 -24
  79. package/lib/esm/features/search/types.d.ts +0 -1
  80. package/lib/esm/features/selection/feature.d.ts +1 -4
  81. package/lib/esm/features/selection/feature.js +54 -35
  82. package/lib/esm/features/selection/types.d.ts +1 -1
  83. package/lib/esm/features/sync-data-loader/feature.d.ts +1 -3
  84. package/lib/esm/features/sync-data-loader/feature.js +7 -2
  85. package/lib/esm/features/tree/feature.d.ts +1 -5
  86. package/lib/esm/features/tree/feature.js +98 -93
  87. package/lib/esm/features/tree/types.d.ts +5 -8
  88. package/lib/esm/index.d.ts +5 -1
  89. package/lib/esm/index.js +4 -1
  90. package/lib/esm/mddocs-entry.d.ts +10 -0
  91. package/lib/esm/test-utils/test-tree-do.d.ts +23 -0
  92. package/lib/esm/test-utils/test-tree-do.js +95 -0
  93. package/lib/esm/test-utils/test-tree-expect.d.ts +15 -0
  94. package/lib/esm/test-utils/test-tree-expect.js +58 -0
  95. package/lib/esm/test-utils/test-tree.d.ts +47 -0
  96. package/lib/esm/test-utils/test-tree.js +199 -0
  97. package/lib/esm/types/core.d.ts +39 -24
  98. package/lib/esm/utilities/errors.d.ts +1 -0
  99. package/lib/esm/utilities/errors.js +1 -0
  100. package/lib/esm/utilities/insert-items-at-target.js +10 -3
  101. package/lib/esm/utilities/remove-items-from-parents.js +14 -8
  102. package/lib/esm/utils.d.ts +3 -3
  103. package/lib/esm/utils.js +3 -3
  104. package/package.json +7 -3
  105. package/src/core/build-proxified-instance.ts +117 -0
  106. package/src/core/build-static-instance.ts +27 -0
  107. package/src/core/core.spec.ts +210 -0
  108. package/src/core/create-tree.ts +73 -78
  109. package/src/features/async-data-loader/async-data-loader.spec.ts +124 -0
  110. package/src/features/async-data-loader/feature.ts +34 -44
  111. package/src/features/async-data-loader/types.ts +4 -6
  112. package/src/features/drag-and-drop/drag-and-drop.spec.ts +717 -0
  113. package/src/features/drag-and-drop/feature.ts +88 -63
  114. package/src/features/drag-and-drop/types.ts +24 -10
  115. package/src/features/drag-and-drop/utils.ts +197 -56
  116. package/src/features/expand-all/expand-all.spec.ts +56 -0
  117. package/src/features/expand-all/feature.ts +9 -24
  118. package/src/features/hotkeys-core/feature.ts +5 -14
  119. package/src/features/main/types.ts +14 -1
  120. package/src/features/prop-memoization/feature.ts +51 -0
  121. package/src/features/prop-memoization/prop-memoization.spec.ts +68 -0
  122. package/src/features/prop-memoization/types.ts +11 -0
  123. package/src/features/renaming/feature.ts +37 -45
  124. package/src/features/renaming/renaming.spec.ts +127 -0
  125. package/src/features/renaming/types.ts +2 -2
  126. package/src/features/search/feature.ts +36 -46
  127. package/src/features/search/search.spec.ts +117 -0
  128. package/src/features/search/types.ts +0 -1
  129. package/src/features/selection/feature.ts +50 -53
  130. package/src/features/selection/selection.spec.ts +219 -0
  131. package/src/features/selection/types.ts +0 -2
  132. package/src/features/sync-data-loader/feature.ts +9 -18
  133. package/src/features/tree/feature.ts +101 -144
  134. package/src/features/tree/tree.spec.ts +475 -0
  135. package/src/features/tree/types.ts +5 -9
  136. package/src/index.ts +6 -1
  137. package/src/mddocs-entry.ts +13 -0
  138. package/src/test-utils/test-tree-do.ts +136 -0
  139. package/src/test-utils/test-tree-expect.ts +86 -0
  140. package/src/test-utils/test-tree.ts +227 -0
  141. package/src/types/core.ts +76 -108
  142. package/src/utilities/errors.ts +2 -0
  143. package/src/utilities/insert-items-at-target.ts +10 -3
  144. package/src/utilities/remove-items-from-parents.ts +15 -10
  145. package/src/utils.spec.ts +89 -0
  146. package/src/utils.ts +6 -6
  147. package/tsconfig.json +1 -0
  148. package/vitest.config.ts +6 -0
@@ -0,0 +1,54 @@
1
+ import { throwError } from "../utilities/errors";
2
+ const noop = () => { };
3
+ const findPrevInstanceMethod = (features, instanceType, methodKey, featureSearchIndex) => {
4
+ var _a;
5
+ for (let i = featureSearchIndex; i >= 0; i--) {
6
+ const feature = features[i];
7
+ const itemInstanceMethod = (_a = feature[instanceType]) === null || _a === void 0 ? void 0 : _a[methodKey];
8
+ if (itemInstanceMethod) {
9
+ return i;
10
+ }
11
+ }
12
+ return null;
13
+ };
14
+ const invokeInstanceMethod = (features, instanceType, opts, methodKey, featureIndex, args) => {
15
+ var _a;
16
+ const prevIndex = findPrevInstanceMethod(features, instanceType, methodKey, featureIndex - 1);
17
+ const itemInstanceMethod = (_a = features[featureIndex][instanceType]) === null || _a === void 0 ? void 0 : _a[methodKey];
18
+ return itemInstanceMethod(Object.assign(Object.assign({}, opts), { prev: prevIndex !== null
19
+ ? (...newArgs) => invokeInstanceMethod(features, instanceType, opts, methodKey, prevIndex, newArgs)
20
+ : null }), ...args);
21
+ };
22
+ export const buildProxiedInstance = (features, instanceType, buildOpts) => {
23
+ // demo with prototypes: https://jsfiddle.net/bgenc58r/
24
+ const opts = {};
25
+ const item = new Proxy({}, {
26
+ has(target, key) {
27
+ if (typeof key === "symbol") {
28
+ return false;
29
+ }
30
+ if (key === "toJSON") {
31
+ return false;
32
+ }
33
+ const hasInstanceMethod = findPrevInstanceMethod(features, instanceType, key, features.length - 1);
34
+ return Boolean(hasInstanceMethod);
35
+ },
36
+ get(target, key) {
37
+ if (typeof key === "symbol") {
38
+ return undefined;
39
+ }
40
+ if (key === "toJSON") {
41
+ return {};
42
+ }
43
+ return (...args) => {
44
+ const featureIndex = findPrevInstanceMethod(features, instanceType, key, features.length - 1);
45
+ if (featureIndex === null) {
46
+ throw throwError(`feature missing for method ${key}`);
47
+ }
48
+ return invokeInstanceMethod(features, instanceType, opts, key, featureIndex, args);
49
+ };
50
+ },
51
+ });
52
+ Object.assign(opts, buildOpts(item));
53
+ return [item, noop];
54
+ };
@@ -0,0 +1,2 @@
1
+ import { InstanceBuilder } from "../features/main/types";
2
+ export declare const buildStaticInstance: InstanceBuilder;
@@ -0,0 +1,22 @@
1
+ /* eslint-disable no-continue,no-labels,no-extra-label */
2
+ export const buildStaticInstance = (features, instanceType, buildOpts) => {
3
+ const instance = {};
4
+ const finalize = () => {
5
+ const opts = buildOpts(instance);
6
+ featureLoop: for (let i = 0; i < features.length; i++) {
7
+ // Loop goes in forward order, each features overwrite previous ones and wraps those in a prev() fn
8
+ const definition = features[i][instanceType];
9
+ if (!definition)
10
+ continue featureLoop;
11
+ methodLoop: for (const [key, method] of Object.entries(definition)) {
12
+ if (!method)
13
+ continue methodLoop;
14
+ const prev = instance[key];
15
+ instance[key] = (...args) => {
16
+ return method(Object.assign(Object.assign({}, opts), { prev }), ...args);
17
+ };
18
+ }
19
+ }
20
+ };
21
+ return [instance, finalize];
22
+ };
@@ -1,42 +1,38 @@
1
1
  import { treeFeature } from "../features/tree/feature";
2
- const buildItemInstance = (features, tree, itemId) => {
3
- var _a, _b;
4
- const itemInstance = {};
5
- for (const feature of features) {
6
- Object.assign(
7
- // TODO dont run createItemInstance, but assign prototype objects instead?
8
- // https://jsfiddle.net/bgenc58r/
9
- itemInstance, (_b = (_a = feature.createItemInstance) === null || _a === void 0 ? void 0 : _a.call(feature, Object.assign({}, itemInstance), itemInstance, tree, itemId)) !== null && _b !== void 0 ? _b : {});
10
- }
11
- return itemInstance;
12
- };
2
+ import { buildStaticInstance } from "./build-static-instance";
3
+ import { throwError } from "../utilities/errors";
13
4
  const verifyFeatures = (features) => {
14
5
  var _a;
15
6
  const loadedFeatures = features === null || features === void 0 ? void 0 : features.map((feature) => feature.key);
16
7
  for (const feature of features !== null && features !== void 0 ? features : []) {
17
8
  const missingDependency = (_a = feature.deps) === null || _a === void 0 ? void 0 : _a.find((dep) => !(loadedFeatures === null || loadedFeatures === void 0 ? void 0 : loadedFeatures.includes(dep)));
18
9
  if (missingDependency) {
19
- throw new Error(`${feature.key} needs ${missingDependency}`);
10
+ throw throwError(`${feature.key} needs ${missingDependency}`);
20
11
  }
21
12
  }
22
13
  };
23
- const compareFeatures = (feature1, feature2) => {
24
- var _a;
14
+ const compareFeatures = (originalOrder) => (feature1, feature2) => {
15
+ var _a, _b;
25
16
  if (feature2.key && ((_a = feature1.overwrites) === null || _a === void 0 ? void 0 : _a.includes(feature2.key))) {
26
17
  return 1;
27
18
  }
28
- return -1;
19
+ if (feature1.key && ((_b = feature2.overwrites) === null || _b === void 0 ? void 0 : _b.includes(feature1.key))) {
20
+ return -1;
21
+ }
22
+ return originalOrder.indexOf(feature1) - originalOrder.indexOf(feature2);
29
23
  };
30
- const sortFeatures = (features = []) => features.sort(compareFeatures);
24
+ const sortFeatures = (features = []) => features.sort(compareFeatures(features));
31
25
  export const createTree = (initialConfig) => {
32
- var _a, _b, _c, _d, _e;
33
- const treeInstance = {};
26
+ var _a, _b, _c, _d;
27
+ const buildInstance = (_a = initialConfig.instanceBuilder) !== null && _a !== void 0 ? _a : buildStaticInstance;
34
28
  const additionalFeatures = [
35
29
  treeFeature,
36
30
  ...sortFeatures(initialConfig.features),
37
31
  ];
38
32
  verifyFeatures(additionalFeatures);
39
- 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 = (_a = initialConfig.initialState) !== null && _a !== void 0 ? _a : initialConfig.state) !== null && _b !== void 0 ? _b : {});
33
+ const features = [...additionalFeatures];
34
+ const [treeInstance, finalizeTree] = buildInstance(features, "treeInstance", (tree) => ({ tree }));
35
+ 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 : {});
40
36
  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);
41
37
  const stateHandlerNames = additionalFeatures.reduce((acc, feature) => (Object.assign(Object.assign({}, acc), feature.stateHandlerNames)), {});
42
38
  let treeElement;
@@ -47,11 +43,12 @@ export const createTree = (initialConfig) => {
47
43
  const itemDataRefs = {};
48
44
  let itemMetaMap = {};
49
45
  const hotkeyPresets = {};
50
- const rebuildItemMeta = (main) => {
46
+ const rebuildItemMeta = () => {
51
47
  // TODO can we find a way to only run this for the changed substructure?
52
48
  itemInstances = [];
53
49
  itemMetaMap = {};
54
- const rootInstance = buildItemInstance([main, ...additionalFeatures], treeInstance, config.rootItemId);
50
+ const [rootInstance, finalizeRootInstance] = buildInstance(features, "itemInstance", (item) => ({ item, tree: treeInstance, itemId: config.rootItemId }));
51
+ finalizeRootInstance();
55
52
  itemInstancesMap[config.rootItemId] = rootInstance;
56
53
  itemMetaMap[config.rootItemId] = {
57
54
  itemId: config.rootItemId,
@@ -64,7 +61,12 @@ export const createTree = (initialConfig) => {
64
61
  for (const item of treeInstance.getItemsMeta()) {
65
62
  itemMetaMap[item.itemId] = item;
66
63
  if (!itemInstancesMap[item.itemId]) {
67
- const instance = buildItemInstance([main, ...additionalFeatures], treeInstance, item.itemId);
64
+ const [instance, finalizeInstance] = buildInstance(features, "itemInstance", (instance) => ({
65
+ item: instance,
66
+ tree: treeInstance,
67
+ itemId: item.itemId,
68
+ }));
69
+ finalizeInstance();
68
70
  itemInstancesMap[item.itemId] = instance;
69
71
  itemInstances.push(instance);
70
72
  }
@@ -80,25 +82,36 @@ export const createTree = (initialConfig) => {
80
82
  };
81
83
  const mainFeature = {
82
84
  key: "main",
83
- createTreeInstance: (prev) => (Object.assign(Object.assign({}, prev), { getState: () => state, setState: (updater) => {
85
+ treeInstance: {
86
+ getState: () => state,
87
+ setState: ({}, updater) => {
84
88
  var _a;
85
89
  // Not necessary, since I think the subupdate below keeps the state fresh anyways?
86
90
  // state = typeof updater === "function" ? updater(state) : updater;
87
- (_a = config.setState) === null || _a === void 0 ? void 0 : _a.call(config, state);
88
- }, applySubStateUpdate: (stateName, updater) => {
91
+ (_a = config.setState) === null || _a === void 0 ? void 0 : _a.call(config, state); // TODO this cant be right... This doesnt allow external state updates
92
+ },
93
+ applySubStateUpdate: ({}, stateName, updater) => {
89
94
  state[stateName] =
90
95
  typeof updater === "function" ? updater(state[stateName]) : updater;
91
- config[stateHandlerNames[stateName]](state[stateName]);
92
- }, rebuildTree: () => {
96
+ const externalStateSetter = config[stateHandlerNames[stateName]];
97
+ externalStateSetter === null || externalStateSetter === void 0 ? void 0 : externalStateSetter(state[stateName]);
98
+ },
99
+ // TODO rebuildSubTree: (itemId: string) => void;
100
+ rebuildTree: () => {
93
101
  var _a;
94
- rebuildItemMeta(mainFeature);
102
+ rebuildItemMeta();
95
103
  (_a = config.setState) === null || _a === void 0 ? void 0 : _a.call(config, state);
96
- }, getConfig: () => config, setConfig: (updater) => {
104
+ },
105
+ getConfig: () => config,
106
+ setConfig: (_, updater) => {
97
107
  config = typeof updater === "function" ? updater(config) : updater;
98
108
  if (config.state) {
99
109
  state = Object.assign(Object.assign({}, state), config.state);
100
110
  }
101
- }, getItemInstance: (itemId) => itemInstancesMap[itemId], getItems: () => itemInstances, registerElement: (element) => {
111
+ },
112
+ getItemInstance: ({}, itemId) => itemInstancesMap[itemId],
113
+ getItems: () => itemInstances,
114
+ registerElement: ({}, element) => {
102
115
  if (treeElement === element) {
103
116
  return;
104
117
  }
@@ -109,28 +122,37 @@ export const createTree = (initialConfig) => {
109
122
  eachFeature((feature) => { var _a; return (_a = feature.onTreeMount) === null || _a === void 0 ? void 0 : _a.call(feature, treeInstance, element); });
110
123
  }
111
124
  treeElement = element;
112
- }, getElement: () => treeElement, getDataRef: () => treeDataRef, getHotkeyPresets: () => hotkeyPresets })),
113
- createItemInstance: (prev, instance, _, itemId) => (Object.assign(Object.assign({}, prev), { registerElement: (element) => {
125
+ },
126
+ getElement: () => treeElement,
127
+ getDataRef: () => treeDataRef,
128
+ getHotkeyPresets: () => hotkeyPresets,
129
+ },
130
+ itemInstance: {
131
+ // TODO just change to a getRef method that memoizes, maybe as part of getProps
132
+ registerElement: ({ itemId, item }, element) => {
114
133
  if (itemElementsMap[itemId] === element) {
115
134
  return;
116
135
  }
117
136
  const oldElement = itemElementsMap[itemId];
118
137
  if (oldElement && !element) {
119
- eachFeature((feature) => { var _a; return (_a = feature.onItemUnmount) === null || _a === void 0 ? void 0 : _a.call(feature, instance, oldElement, treeInstance); });
138
+ eachFeature((feature) => { var _a; return (_a = feature.onItemUnmount) === null || _a === void 0 ? void 0 : _a.call(feature, item, oldElement, treeInstance); });
120
139
  }
121
140
  else if (!oldElement && element) {
122
- eachFeature((feature) => { var _a; return (_a = feature.onItemMount) === null || _a === void 0 ? void 0 : _a.call(feature, instance, element, treeInstance); });
141
+ eachFeature((feature) => { var _a; return (_a = feature.onItemMount) === null || _a === void 0 ? void 0 : _a.call(feature, item, element, treeInstance); });
123
142
  }
124
143
  itemElementsMap[itemId] = element;
125
- }, getElement: () => itemElementsMap[itemId],
144
+ },
145
+ getElement: ({ itemId }) => itemElementsMap[itemId],
126
146
  // eslint-disable-next-line no-return-assign
127
- getDataRef: () => { var _a; return ((_a = itemDataRefs[itemId]) !== null && _a !== void 0 ? _a : (itemDataRefs[itemId] = { current: {} })); }, getItemMeta: () => itemMetaMap[itemId] })),
147
+ getDataRef: ({ itemId }) => { var _a; return ((_a = itemDataRefs[itemId]) !== null && _a !== void 0 ? _a : (itemDataRefs[itemId] = { current: {} })); },
148
+ getItemMeta: ({ itemId }) => itemMetaMap[itemId],
149
+ },
128
150
  };
129
- const features = [mainFeature, ...additionalFeatures];
151
+ features.unshift(mainFeature);
130
152
  for (const feature of features) {
131
- 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 : {});
132
- Object.assign(hotkeyPresets, (_e = feature.hotkeys) !== null && _e !== void 0 ? _e : {});
153
+ Object.assign(hotkeyPresets, (_d = feature.hotkeys) !== null && _d !== void 0 ? _d : {});
133
154
  }
134
- rebuildItemMeta(mainFeature);
155
+ finalizeTree();
156
+ rebuildItemMeta();
135
157
  return treeInstance;
136
158
  };
@@ -1,5 +1,2 @@
1
1
  import { FeatureImplementation } from "../../types/core";
2
- import { AsyncDataLoaderFeatureDef } from "./types";
3
- import { MainFeatureDef } from "../main/types";
4
- import { TreeFeatureDef } from "../tree/types";
5
- export declare const asyncDataLoaderFeature: FeatureImplementation<any, AsyncDataLoaderFeatureDef<any>, MainFeatureDef | TreeFeatureDef<any> | AsyncDataLoaderFeatureDef<any>>;
2
+ export declare const asyncDataLoaderFeature: FeatureImplementation;
@@ -6,18 +6,19 @@ export const asyncDataLoaderFeature = {
6
6
  stateHandlerNames: {
7
7
  loadingItems: "setLoadingItems",
8
8
  },
9
- createTreeInstance: (prev, instance) => (Object.assign(Object.assign({}, prev), { retrieveItemData: (itemId) => {
9
+ treeInstance: {
10
+ retrieveItemData: ({ tree }, itemId) => {
10
11
  var _a, _b, _c, _d, _e;
11
12
  var _f, _g;
12
- const config = instance.getConfig();
13
- const dataRef = instance.getDataRef();
13
+ const config = tree.getConfig();
14
+ const dataRef = tree.getDataRef();
14
15
  (_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_f.itemData = {});
15
16
  (_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_g.childrenIds = {});
16
17
  if (dataRef.current.itemData[itemId]) {
17
18
  return dataRef.current.itemData[itemId];
18
19
  }
19
- if (!instance.getState().loadingItems.includes(itemId)) {
20
- instance.applySubStateUpdate("loadingItems", (loadingItems) => [
20
+ if (!tree.getState().loadingItems.includes(itemId)) {
21
+ tree.applySubStateUpdate("loadingItems", (loadingItems) => [
21
22
  ...loadingItems,
22
23
  itemId,
23
24
  ]);
@@ -25,24 +26,25 @@ export const asyncDataLoaderFeature = {
25
26
  var _a;
26
27
  dataRef.current.itemData[itemId] = item;
27
28
  (_a = config.onLoadedItem) === null || _a === void 0 ? void 0 : _a.call(config, itemId, item);
28
- instance.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
29
+ tree.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
29
30
  });
30
31
  }
31
32
  return (_e = (_d = config.createLoadingItemData) === null || _d === void 0 ? void 0 : _d.call(config)) !== null && _e !== void 0 ? _e : null;
32
- }, retrieveChildrenIds: (itemId) => {
33
+ },
34
+ retrieveChildrenIds: ({ tree }, itemId) => {
33
35
  var _a, _b, _c, _d, _e;
34
36
  var _f, _g;
35
- const config = instance.getConfig();
36
- const dataRef = instance.getDataRef();
37
+ const config = tree.getConfig();
38
+ const dataRef = tree.getDataRef();
37
39
  (_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : (_f.itemData = {});
38
40
  (_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : (_g.childrenIds = {});
39
41
  if (dataRef.current.childrenIds[itemId]) {
40
42
  return dataRef.current.childrenIds[itemId];
41
43
  }
42
- if (instance.getState().loadingItems.includes(itemId)) {
44
+ if (tree.getState().loadingItems.includes(itemId)) {
43
45
  return [];
44
46
  }
45
- instance.applySubStateUpdate("loadingItems", (loadingItems) => [
47
+ tree.applySubStateUpdate("loadingItems", (loadingItems) => [
46
48
  ...loadingItems,
47
49
  itemId,
48
50
  ]);
@@ -56,8 +58,8 @@ export const asyncDataLoaderFeature = {
56
58
  const childrenIds = children.map(({ id }) => id);
57
59
  dataRef.current.childrenIds[itemId] = childrenIds;
58
60
  (_b = config.onLoadedChildren) === null || _b === void 0 ? void 0 : _b.call(config, itemId, childrenIds);
59
- instance.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
60
- instance.rebuildTree();
61
+ tree.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
62
+ tree.rebuildTree();
61
63
  });
62
64
  }
63
65
  else {
@@ -65,21 +67,31 @@ export const asyncDataLoaderFeature = {
65
67
  var _a;
66
68
  dataRef.current.childrenIds[itemId] = childrenIds;
67
69
  (_a = config.onLoadedChildren) === null || _a === void 0 ? void 0 : _a.call(config, itemId, childrenIds);
68
- instance.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
69
- instance.rebuildTree();
70
+ tree.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
71
+ tree.rebuildTree();
70
72
  });
71
73
  }
72
74
  return [];
73
- }, invalidateItemData: (itemId) => {
75
+ },
76
+ },
77
+ itemInstance: {
78
+ isLoading: ({ tree, item }) => tree.getState().loadingItems.includes(item.getItemMeta().itemId),
79
+ invalidateItemData: ({ tree, itemId }) => {
74
80
  var _a;
75
- const dataRef = instance.getDataRef();
81
+ const dataRef = tree.getDataRef();
76
82
  (_a = dataRef.current.itemData) === null || _a === void 0 ? true : delete _a[itemId];
77
- instance.retrieveItemData(itemId);
78
- }, invalidateChildrenIds: (itemId) => {
83
+ tree.retrieveItemData(itemId);
84
+ },
85
+ invalidateChildrenIds: ({ tree, itemId }) => {
79
86
  var _a;
80
- const dataRef = instance.getDataRef();
87
+ const dataRef = tree.getDataRef();
81
88
  (_a = dataRef.current.childrenIds) === null || _a === void 0 ? true : delete _a[itemId];
82
- instance.retrieveChildrenIds(itemId);
83
- } })),
84
- createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { isLoading: () => tree.getState().loadingItems.includes(item.getItemMeta().itemId), invalidateItemData: () => tree.invalidateItemData(item.getItemMeta().itemId), invalidateChildrenIds: () => tree.invalidateChildrenIds(item.getItemMeta().itemId) })),
89
+ tree.retrieveChildrenIds(itemId);
90
+ },
91
+ updateCachedChildrenIds: ({ tree, itemId }, childrenIds) => {
92
+ const dataRef = tree.getDataRef();
93
+ dataRef.current.childrenIds[itemId] = childrenIds;
94
+ tree.rebuildTree();
95
+ },
96
+ },
85
97
  };
@@ -27,15 +27,13 @@ export type AsyncDataLoaderFeatureDef<T> = {
27
27
  onLoadedChildren?: (itemId: string, childrenIds: string[]) => void;
28
28
  asyncDataLoader?: AsyncTreeDataLoader<T>;
29
29
  };
30
- treeInstance: SyncDataLoaderFeatureDef<T>["treeInstance"] & {
31
- /** Invalidate fetched data for item, and triggers a refetch and subsequent rerender if the item is visible */
32
- invalidateItemData: (itemId: string) => void;
33
- invalidateChildrenIds: (itemId: string) => void;
34
- };
30
+ treeInstance: SyncDataLoaderFeatureDef<T>["treeInstance"];
35
31
  itemInstance: SyncDataLoaderFeatureDef<T>["itemInstance"] & {
32
+ /** Invalidate fetched data for item, and triggers a refetch and subsequent rerender if the item is visible */
36
33
  invalidateItemData: () => void;
37
34
  invalidateChildrenIds: () => void;
38
- isLoading: () => void;
35
+ updateCachedChildrenIds: (childrenIds: string[]) => void;
36
+ isLoading: () => boolean;
39
37
  };
40
38
  hotkeys: SyncDataLoaderFeatureDef<T>["hotkeys"];
41
39
  };
@@ -1,3 +1,2 @@
1
- import { FeatureDefs, FeatureImplementation } from "../../types/core";
2
- import { DragAndDropFeatureDef } from "./types";
3
- export declare const dragAndDropFeature: FeatureImplementation<any, DragAndDropFeatureDef<any>, FeatureDefs<any>>;
1
+ import { FeatureImplementation } from "../../types/core";
2
+ export declare const dragAndDropFeature: FeatureImplementation;
@@ -1,47 +1,69 @@
1
1
  import { canDrop, getDragCode, getDropTarget } from "./utils";
2
2
  import { makeStateUpdater } from "../../utils";
3
3
  export const dragAndDropFeature = {
4
- key: "dragAndDrop",
4
+ key: "drag-and-drop",
5
5
  deps: ["selection"],
6
- getDefaultConfig: (defaultConfig, tree) => (Object.assign({ canDrop: (_, target) => target.item.isFolder(), canDropForeignDragObject: () => false, setDndState: makeStateUpdater("dnd", tree) }, defaultConfig)),
6
+ getDefaultConfig: (defaultConfig, tree) => (Object.assign({ canDrop: (_, target) => target.item.isFolder(), canDropForeignDragObject: () => false, setDndState: makeStateUpdater("dnd", tree), canReorder: true }, defaultConfig)),
7
7
  stateHandlerNames: {
8
8
  dnd: "setDndState",
9
9
  },
10
- createTreeInstance: (prev, tree) => (Object.assign(Object.assign({}, prev), { getDropTarget: () => {
10
+ treeInstance: {
11
+ getDropTarget: ({ tree }) => {
11
12
  var _a, _b;
12
13
  return (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.dragTarget) !== null && _b !== void 0 ? _b : null;
13
- }, getDragLineData: () => {
14
- var _a, _b, _c, _d, _e;
14
+ },
15
+ getDragLineData: ({ tree }) => {
16
+ var _a, _b, _c, _d, _e, _f;
15
17
  const target = tree.getDropTarget();
16
- const intend = ((_a = target === null || target === void 0 ? void 0 : target.item.getItemMeta().level) !== null && _a !== void 0 ? _a : 0) + 1;
17
- if (!target || target.childIndex === null)
18
+ const indent = ((_a = target === null || target === void 0 ? void 0 : target.item.getItemMeta().level) !== null && _a !== void 0 ? _a : 0) + 1;
19
+ const treeBb = (_b = tree.getElement()) === null || _b === void 0 ? void 0 : _b.getBoundingClientRect();
20
+ if (!target || !treeBb || target.childIndex === null)
18
21
  return null;
19
- const children = target.item.getChildren();
20
- if (target.childIndex === children.length) {
21
- const bb = (_c = (_b = children[target.childIndex - 1]) === null || _b === void 0 ? void 0 : _b.getElement()) === null || _c === void 0 ? void 0 : _c.getBoundingClientRect();
22
+ const leftOffset = target.dragLineLevel * ((_c = tree.getConfig().indent) !== null && _c !== void 0 ? _c : 1);
23
+ const targetItem = tree.getItems()[target.dragLineIndex];
24
+ if (!targetItem) {
25
+ const bb = (_e = (_d = tree
26
+ .getItems()[target.dragLineIndex - 1]) === null || _d === void 0 ? void 0 : _d.getElement()) === null || _e === void 0 ? void 0 : _e.getBoundingClientRect();
22
27
  if (bb) {
23
28
  return {
24
- intend,
25
- top: bb.bottom,
26
- left: bb.left,
27
- right: bb.right,
29
+ indent,
30
+ top: bb.bottom - treeBb.bottom,
31
+ left: bb.left + leftOffset - treeBb.left,
32
+ width: bb.width - leftOffset,
28
33
  };
29
34
  }
30
35
  }
31
- const bb = (_e = (_d = children[target.childIndex]) === null || _d === void 0 ? void 0 : _d.getElement()) === null || _e === void 0 ? void 0 : _e.getBoundingClientRect();
36
+ const bb = (_f = targetItem.getElement()) === null || _f === void 0 ? void 0 : _f.getBoundingClientRect();
32
37
  if (bb) {
33
38
  return {
34
- intend,
35
- top: bb.top,
36
- left: bb.left,
37
- right: bb.right,
39
+ indent,
40
+ top: bb.top - treeBb.top,
41
+ left: bb.left + leftOffset - treeBb.left,
42
+ width: bb.width - leftOffset,
38
43
  };
39
44
  }
40
45
  return null;
41
- } })),
42
- createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { getProps: () => {
46
+ },
47
+ getDragLineStyle: ({ tree }, topOffset = -1, leftOffset = -8) => {
48
+ const dragLine = tree.getDragLineData();
49
+ return dragLine
50
+ ? {
51
+ top: `${dragLine.top + topOffset}px`,
52
+ left: `${dragLine.left + leftOffset}px`,
53
+ width: `${dragLine.width - leftOffset}px`,
54
+ pointerEvents: "none", // important to prevent capturing drag events
55
+ }
56
+ : { display: "none" };
57
+ },
58
+ getContainerProps: ({ prev }) => {
59
+ const prevProps = prev === null || prev === void 0 ? void 0 : prev();
60
+ return Object.assign(Object.assign({}, prevProps), { style: Object.assign(Object.assign({}, prevProps === null || prevProps === void 0 ? void 0 : prevProps.style), { position: "relative" }) });
61
+ },
62
+ },
63
+ itemInstance: {
64
+ getProps: ({ tree, item, prev }) => {
43
65
  var _a, _b, _c;
44
- 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) => {
66
+ return (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { draggable: (_c = (_b = (_a = tree.getConfig()).isItemDraggable) === null || _b === void 0 ? void 0 : _b.call(_a, item)) !== null && _c !== void 0 ? _c : true, onDragStart: (e) => {
45
67
  var _a, _b, _c;
46
68
  const selectedItems = tree.getSelectedItems();
47
69
  const items = selectedItems.includes(item) ? selectedItems : [item];
@@ -61,37 +83,45 @@ export const dragAndDropFeature = {
61
83
  draggedItems: items,
62
84
  draggingOverItem: tree.getFocusedItem(),
63
85
  });
64
- }), onDragOver: item.getMemoizedProp("dnd/onDragOver", () => (e) => {
86
+ }, onDragOver: (e) => {
65
87
  var _a, _b, _c;
66
- const target = getDropTarget(e, item, tree);
67
88
  const dataRef = tree.getDataRef();
68
- if (!((_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) &&
69
- !((_c = (_b = tree.getConfig()).canDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(_b, e.dataTransfer, target))) {
89
+ const nextDragCode = getDragCode(e, item, tree);
90
+ if (nextDragCode === dataRef.current.lastDragCode) {
91
+ if (dataRef.current.lastAllowDrop) {
92
+ e.preventDefault();
93
+ }
70
94
  return;
71
95
  }
72
- if (!canDrop(e.dataTransfer, target, tree)) {
96
+ dataRef.current.lastDragCode = nextDragCode;
97
+ const target = getDropTarget(e, item, tree);
98
+ if (!((_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) &&
99
+ (!e.dataTransfer ||
100
+ !((_c = (_b = tree
101
+ .getConfig()).canDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(_b, e.dataTransfer, target)))) {
102
+ dataRef.current.lastAllowDrop = false;
73
103
  return;
74
104
  }
75
- e.preventDefault();
76
- const nextDragCode = getDragCode(target);
77
- if (nextDragCode === dataRef.current.lastDragCode) {
105
+ if (!canDrop(e.dataTransfer, target, tree)) {
106
+ dataRef.current.lastAllowDrop = false;
78
107
  return;
79
108
  }
80
- dataRef.current.lastDragCode = nextDragCode;
81
109
  tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { dragTarget: target, draggingOverItem: item })));
82
- }), onDragLeave: item.getMemoizedProp("dnd/onDragLeave", () => () => {
110
+ dataRef.current.lastAllowDrop = true;
111
+ e.preventDefault();
112
+ }, onDragLeave: () => {
83
113
  const dataRef = tree.getDataRef();
84
114
  dataRef.current.lastDragCode = "no-drag";
85
115
  tree.applySubStateUpdate("dnd", (state) => (Object.assign(Object.assign({}, state), { draggingOverItem: undefined, dragTarget: undefined })));
86
- }), onDragEnd: item.getMemoizedProp("dnd/onDragEnd", () => (e) => {
87
- var _a, _b, _c;
116
+ }, onDragEnd: (e) => {
117
+ var _a, _b, _c, _d;
88
118
  const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
89
119
  tree.applySubStateUpdate("dnd", null);
90
- if (e.dataTransfer.dropEffect === "none" || !draggedItems) {
120
+ if (((_b = e.dataTransfer) === null || _b === void 0 ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
91
121
  return;
92
122
  }
93
- (_c = (_b = tree.getConfig()).onCompleteForeignDrop) === null || _c === void 0 ? void 0 : _c.call(_b, draggedItems);
94
- }), onDrop: item.getMemoizedProp("dnd/onDrop", () => (e) => {
123
+ (_d = (_c = tree.getConfig()).onCompleteForeignDrop) === null || _d === void 0 ? void 0 : _d.call(_c, draggedItems);
124
+ }, onDrop: (e) => {
95
125
  var _a, _b, _c;
96
126
  const dataRef = tree.getDataRef();
97
127
  const target = getDropTarget(e, item, tree);
@@ -106,30 +136,35 @@ export const dragAndDropFeature = {
106
136
  if (draggedItems) {
107
137
  (_b = config.onDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target);
108
138
  }
109
- else {
139
+ else if (e.dataTransfer) {
110
140
  (_c = config.onDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(config, e.dataTransfer, target);
111
141
  }
112
142
  // TODO rebuild tree?
113
- }) }));
114
- }, isDropTarget: () => {
143
+ } }));
144
+ },
145
+ isDropTarget: ({ tree, item }) => {
115
146
  const target = tree.getDropTarget();
116
147
  return target ? target.item.getId() === item.getId() : false;
117
- }, isDropTargetAbove: () => {
148
+ },
149
+ isDropTargetAbove: ({ tree, item }) => {
118
150
  const target = tree.getDropTarget();
119
151
  if (!target ||
120
152
  target.childIndex === null ||
121
153
  target.item !== item.getParent())
122
154
  return false;
123
155
  return target.childIndex === item.getItemMeta().posInSet;
124
- }, isDropTargetBelow: () => {
156
+ },
157
+ isDropTargetBelow: ({ tree, item }) => {
125
158
  const target = tree.getDropTarget();
126
159
  if (!target ||
127
160
  target.childIndex === null ||
128
161
  target.item !== item.getParent())
129
162
  return false;
130
163
  return target.childIndex - 1 === item.getItemMeta().posInSet;
131
- }, isDraggingOver: () => {
164
+ },
165
+ isDraggingOver: ({ tree, item }) => {
132
166
  var _a, _b;
133
167
  return ((_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggingOverItem) === null || _b === void 0 ? void 0 : _b.getId()) === item.getId();
134
- } })),
168
+ },
169
+ },
135
170
  };