@headless-tree/core 1.1.0 → 1.2.1

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 (50) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/lib/cjs/core/create-tree.js +22 -2
  3. package/lib/cjs/features/async-data-loader/feature.js +4 -4
  4. package/lib/cjs/features/checkboxes/feature.d.ts +2 -0
  5. package/lib/cjs/features/checkboxes/feature.js +94 -0
  6. package/lib/cjs/features/checkboxes/types.d.ts +26 -0
  7. package/lib/cjs/features/checkboxes/types.js +9 -0
  8. package/lib/cjs/features/drag-and-drop/feature.js +31 -5
  9. package/lib/cjs/features/drag-and-drop/types.d.ts +5 -0
  10. package/lib/cjs/features/main/types.d.ts +2 -0
  11. package/lib/cjs/features/renaming/feature.js +8 -0
  12. package/lib/cjs/features/tree/feature.js +5 -0
  13. package/lib/cjs/features/tree/types.d.ts +3 -1
  14. package/lib/cjs/index.d.ts +4 -0
  15. package/lib/cjs/index.js +7 -0
  16. package/lib/cjs/test-utils/test-tree.js +1 -0
  17. package/lib/cjs/types/core.d.ts +2 -1
  18. package/lib/esm/core/create-tree.js +22 -2
  19. package/lib/esm/features/async-data-loader/feature.js +4 -4
  20. package/lib/esm/features/checkboxes/feature.d.ts +2 -0
  21. package/lib/esm/features/checkboxes/feature.js +91 -0
  22. package/lib/esm/features/checkboxes/types.d.ts +26 -0
  23. package/lib/esm/features/checkboxes/types.js +6 -0
  24. package/lib/esm/features/drag-and-drop/feature.js +31 -5
  25. package/lib/esm/features/drag-and-drop/types.d.ts +5 -0
  26. package/lib/esm/features/main/types.d.ts +2 -0
  27. package/lib/esm/features/renaming/feature.js +8 -0
  28. package/lib/esm/features/tree/feature.js +5 -0
  29. package/lib/esm/features/tree/types.d.ts +3 -1
  30. package/lib/esm/index.d.ts +4 -0
  31. package/lib/esm/index.js +4 -0
  32. package/lib/esm/test-utils/test-tree.js +1 -0
  33. package/lib/esm/types/core.d.ts +2 -1
  34. package/package.json +7 -2
  35. package/readme.md +157 -0
  36. package/src/core/create-tree.ts +33 -2
  37. package/src/features/async-data-loader/feature.ts +4 -4
  38. package/src/features/checkboxes/checkboxes.spec.ts +134 -0
  39. package/src/features/checkboxes/feature.ts +119 -0
  40. package/src/features/checkboxes/types.ts +28 -0
  41. package/src/features/drag-and-drop/feature.ts +38 -2
  42. package/src/features/drag-and-drop/types.ts +5 -0
  43. package/src/features/main/types.ts +2 -0
  44. package/src/features/renaming/feature.ts +13 -0
  45. package/src/features/renaming/renaming.spec.ts +31 -0
  46. package/src/features/tree/feature.ts +6 -0
  47. package/src/features/tree/types.ts +4 -2
  48. package/src/index.ts +5 -0
  49. package/src/test-utils/test-tree.ts +1 -0
  50. package/src/types/core.ts +2 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @headless-tree/core
2
2
 
3
+ ## 1.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 344011a: fixed an issue where dropping items on an empty tree didn't trigger any events
8
+ - 9f418f8: support setting the drag preview with the `setDragImage` option (#115)
9
+ - 309feba: fixed an issue where the drag-forbidden cursor is shown briefly between changing drag targets (#114)
10
+
11
+ ## 1.2.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 647a072: Fixed incorrect package.json exports configurations to proper ESM and CJS exports (#104)
16
+ - 349d36e: change package.json["module"] to commonjs to fix inconsistent package definitiuons (#104)
17
+ - e2faf37: Fixed an issue async data loaders that resolve data before the tree is mounted can cause the tree to not render at all
18
+
19
+ Note: When using the `createTree()` API directly instead of going through the React `useTree` API, an additional call
20
+ to `tree.rebuildItems()` afterwards will be necessary. This change is marked as minor release regardless, since `createTree` is
21
+ currently not a publically documented feature.
22
+
23
+ ### Patch Changes
24
+
25
+ - 727c982: export makeStateUpdater from core package
26
+ - c041a3f: expose `isOrderedDragTarget` as utility method to differentiate between ordered and unordered drag targets (#108)
27
+ - 2887b0c: Added a `item.getKey()` utility method to use for generating React keys. For now, this just returns the item id, so no migration is needed from using `item.getId()` as React keys.
28
+ - 4e79bc7: Fixed a bug where `feature.overwrites` is not always respected when features are sorted during tree initialization
29
+ - 0669580: Fixed a bug where items that call `item.getProps` while being renamed, can be dragged while being renamed (#110)
30
+
3
31
  ## 1.1.0
4
32
 
5
33
  ### Minor Changes
@@ -14,6 +14,18 @@ const verifyFeatures = (features) => {
14
14
  }
15
15
  }
16
16
  };
17
+ // Check all possible pairs and sort the array
18
+ const exhaustiveSort = (arr, compareFn) => {
19
+ const n = arr.length;
20
+ for (let i = 0; i < n; i++) {
21
+ for (let j = i + 1; j < n; j++) {
22
+ if (compareFn(arr[j], arr[i]) < 0) {
23
+ [arr[i], arr[j]] = [arr[j], arr[i]];
24
+ }
25
+ }
26
+ }
27
+ return arr;
28
+ };
17
29
  const compareFeatures = (originalOrder) => (feature1, feature2) => {
18
30
  var _a, _b;
19
31
  if (feature2.key && ((_a = feature1.overwrites) === null || _a === void 0 ? void 0 : _a.includes(feature2.key))) {
@@ -24,7 +36,7 @@ const compareFeatures = (originalOrder) => (feature1, feature2) => {
24
36
  }
25
37
  return originalOrder.indexOf(feature1) - originalOrder.indexOf(feature2);
26
38
  };
27
- const sortFeatures = (features = []) => features.sort(compareFeatures(features));
39
+ const sortFeatures = (features = []) => exhaustiveSort(features, compareFeatures(features));
28
40
  const createTree = (initialConfig) => {
29
41
  var _a, _b, _c, _d;
30
42
  const buildInstance = (_a = initialConfig.instanceBuilder) !== null && _a !== void 0 ? _a : build_static_instance_1.buildStaticInstance;
@@ -100,6 +112,15 @@ const createTree = (initialConfig) => {
100
112
  const externalStateSetter = config[stateHandlerNames[stateName]];
101
113
  externalStateSetter === null || externalStateSetter === void 0 ? void 0 : externalStateSetter(state[stateName]);
102
114
  },
115
+ buildItemInstance: ({}, itemId) => {
116
+ const [instance, finalizeInstance] = buildInstance(features, "itemInstance", (instance) => ({
117
+ item: instance,
118
+ tree: treeInstance,
119
+ itemId,
120
+ }));
121
+ finalizeInstance();
122
+ return instance;
123
+ },
103
124
  // TODO rebuildSubTree: (itemId: string) => void;
104
125
  rebuildTree: () => {
105
126
  var _a;
@@ -165,7 +186,6 @@ const createTree = (initialConfig) => {
165
186
  Object.assign(hotkeyPresets, (_d = feature.hotkeys) !== null && _d !== void 0 ? _d : {});
166
187
  }
167
188
  finalizeTree();
168
- rebuildItemMeta();
169
189
  return treeInstance;
170
190
  };
171
191
  exports.createTree = createTree;
@@ -75,14 +75,14 @@ exports.asyncDataLoaderFeature = {
75
75
  var _b;
76
76
  return ((_b = getDataRef(tree).current.childrenIds[itemId]) !== null && _b !== void 0 ? _b : (yield loadChildrenIds(tree, itemId)));
77
77
  }),
78
- retrieveItemData: ({ tree }, itemId) => {
78
+ retrieveItemData: ({ tree }, itemId, skipFetch = false) => {
79
79
  var _a, _b;
80
80
  const config = tree.getConfig();
81
81
  const dataRef = getDataRef(tree);
82
82
  if (dataRef.current.itemData[itemId]) {
83
83
  return dataRef.current.itemData[itemId];
84
84
  }
85
- if (!tree.getState().loadingItemData.includes(itemId)) {
85
+ if (!tree.getState().loadingItemData.includes(itemId) && !skipFetch) {
86
86
  tree.applySubStateUpdate("loadingItemData", (loadingItemData) => [
87
87
  ...loadingItemData,
88
88
  itemId,
@@ -91,12 +91,12 @@ exports.asyncDataLoaderFeature = {
91
91
  }
92
92
  return (_b = (_a = config.createLoadingItemData) === null || _a === void 0 ? void 0 : _a.call(config)) !== null && _b !== void 0 ? _b : null;
93
93
  },
94
- retrieveChildrenIds: ({ tree }, itemId) => {
94
+ retrieveChildrenIds: ({ tree }, itemId, skipFetch = false) => {
95
95
  const dataRef = getDataRef(tree);
96
96
  if (dataRef.current.childrenIds[itemId]) {
97
97
  return dataRef.current.childrenIds[itemId];
98
98
  }
99
- if (tree.getState().loadingItemChildrens.includes(itemId)) {
99
+ if (tree.getState().loadingItemChildrens.includes(itemId) || skipFetch) {
100
100
  return [];
101
101
  }
102
102
  tree.applySubStateUpdate("loadingItemChildrens", (loadingItemChildrens) => [...loadingItemChildrens, itemId]);
@@ -0,0 +1,2 @@
1
+ import { FeatureImplementation } from "../../types/core";
2
+ export declare const checkboxesFeature: FeatureImplementation;
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkboxesFeature = void 0;
4
+ const utils_1 = require("../../utils");
5
+ const types_1 = require("./types");
6
+ const errors_1 = require("../../utilities/errors");
7
+ const getAllLoadedDescendants = (tree, itemId) => {
8
+ if (!tree.getConfig().isItemFolder(tree.buildItemInstance(itemId))) {
9
+ return [itemId];
10
+ }
11
+ return tree
12
+ .retrieveChildrenIds(itemId)
13
+ .map((child) => getAllLoadedDescendants(tree, child))
14
+ .flat();
15
+ };
16
+ exports.checkboxesFeature = {
17
+ key: "checkboxes",
18
+ overwrites: ["selection"],
19
+ getInitialState: (initialState) => (Object.assign({ checkedItems: [] }, initialState)),
20
+ getDefaultConfig: (defaultConfig, tree) => {
21
+ var _a;
22
+ const hasAsyncLoader = (_a = defaultConfig.features) === null || _a === void 0 ? void 0 : _a.some((f) => f.key === "async-data-loader");
23
+ if (hasAsyncLoader && !defaultConfig.canCheckFolders) {
24
+ (0, errors_1.throwError)(`!canCheckFolders not supported with async trees`);
25
+ }
26
+ return Object.assign({ setCheckedItems: (0, utils_1.makeStateUpdater)("checkedItems", tree), canCheckFolders: hasAsyncLoader !== null && hasAsyncLoader !== void 0 ? hasAsyncLoader : false }, defaultConfig);
27
+ },
28
+ stateHandlerNames: {
29
+ checkedItems: "setCheckedItems",
30
+ },
31
+ treeInstance: {
32
+ setCheckedItems: ({ tree }, checkedItems) => {
33
+ tree.applySubStateUpdate("checkedItems", checkedItems);
34
+ },
35
+ },
36
+ itemInstance: {
37
+ getCheckboxProps: ({ item }) => {
38
+ const checkedState = item.getCheckedState();
39
+ return {
40
+ onChange: item.toggleCheckedState,
41
+ checked: checkedState === types_1.CheckedState.Checked,
42
+ ref: (r) => {
43
+ if (r) {
44
+ r.indeterminate = checkedState === types_1.CheckedState.Indeterminate;
45
+ }
46
+ },
47
+ };
48
+ },
49
+ toggleCheckedState: ({ item }) => {
50
+ if (item.getCheckedState() === types_1.CheckedState.Checked) {
51
+ item.setUnchecked();
52
+ }
53
+ else {
54
+ item.setChecked();
55
+ }
56
+ },
57
+ getCheckedState: ({ item, tree, itemId }) => {
58
+ const { checkedItems } = tree.getState();
59
+ if (checkedItems.includes(itemId)) {
60
+ return types_1.CheckedState.Checked;
61
+ }
62
+ if (item.isFolder() && !tree.getConfig().canCheckFolders) {
63
+ const descendants = getAllLoadedDescendants(tree, itemId);
64
+ if (descendants.every((d) => checkedItems.includes(d))) {
65
+ return types_1.CheckedState.Checked;
66
+ }
67
+ if (descendants.some((d) => checkedItems.includes(d))) {
68
+ return types_1.CheckedState.Indeterminate;
69
+ }
70
+ }
71
+ return types_1.CheckedState.Unchecked;
72
+ },
73
+ setChecked: ({ item, tree, itemId }) => {
74
+ if (!item.isFolder() || tree.getConfig().canCheckFolders) {
75
+ tree.applySubStateUpdate("checkedItems", (items) => [...items, itemId]);
76
+ }
77
+ else {
78
+ tree.applySubStateUpdate("checkedItems", (items) => [
79
+ ...items,
80
+ ...getAllLoadedDescendants(tree, itemId),
81
+ ]);
82
+ }
83
+ },
84
+ setUnchecked: ({ item, tree, itemId }) => {
85
+ if (!item.isFolder() || tree.getConfig().canCheckFolders) {
86
+ tree.applySubStateUpdate("checkedItems", (items) => items.filter((id) => id !== itemId));
87
+ }
88
+ else {
89
+ const descendants = getAllLoadedDescendants(tree, itemId);
90
+ tree.applySubStateUpdate("checkedItems", (items) => items.filter((id) => !descendants.includes(id)));
91
+ }
92
+ },
93
+ },
94
+ };
@@ -0,0 +1,26 @@
1
+ import { SetStateFn } from "../../types/core";
2
+ export declare enum CheckedState {
3
+ Checked = "checked",
4
+ Unchecked = "unchecked",
5
+ Indeterminate = "indeterminate"
6
+ }
7
+ export type CheckboxesFeatureDef<T> = {
8
+ state: {
9
+ checkedItems: string[];
10
+ };
11
+ config: {
12
+ setCheckedItems?: SetStateFn<string[]>;
13
+ canCheckFolders?: boolean;
14
+ };
15
+ treeInstance: {
16
+ setCheckedItems: (checkedItems: string[]) => void;
17
+ };
18
+ itemInstance: {
19
+ setChecked: () => void;
20
+ setUnchecked: () => void;
21
+ toggleCheckedState: () => void;
22
+ getCheckedState: () => CheckedState;
23
+ getCheckboxProps: () => Record<string, any>;
24
+ };
25
+ hotkeys: never;
26
+ };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CheckedState = void 0;
4
+ var CheckedState;
5
+ (function (CheckedState) {
6
+ CheckedState["Checked"] = "checked";
7
+ CheckedState["Unchecked"] = "unchecked";
8
+ CheckedState["Indeterminate"] = "indeterminate";
9
+ })(CheckedState || (exports.CheckedState = CheckedState = {}));
@@ -68,14 +68,35 @@ exports.dragAndDropFeature = {
68
68
  }
69
69
  : { display: "none" };
70
70
  },
71
- getContainerProps: ({ prev }, treeLabel) => {
71
+ getContainerProps: ({ prev, tree }, treeLabel) => {
72
72
  const prevProps = prev === null || prev === void 0 ? void 0 : prev(treeLabel);
73
- return Object.assign(Object.assign({}, prevProps), { style: Object.assign(Object.assign({}, prevProps === null || prevProps === void 0 ? void 0 : prevProps.style), { position: "relative" }) });
73
+ return Object.assign(Object.assign({}, prevProps), { onDragOver: (e) => {
74
+ e.preventDefault();
75
+ }, onDrop: (e) => __awaiter(void 0, void 0, void 0, function* () {
76
+ var _a, _b, _c;
77
+ // TODO merge implementation with itemInstance.onDrop
78
+ const dataRef = tree.getDataRef();
79
+ const target = { item: tree.getRootItem() };
80
+ if (!(0, utils_1.canDrop)(e.dataTransfer, target, tree)) {
81
+ return;
82
+ }
83
+ e.preventDefault();
84
+ const config = tree.getConfig();
85
+ const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
86
+ dataRef.current.lastDragCode = undefined;
87
+ tree.applySubStateUpdate("dnd", null);
88
+ if (draggedItems) {
89
+ yield ((_b = config.onDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target));
90
+ }
91
+ else if (e.dataTransfer) {
92
+ yield ((_c = config.onDropForeignDragObject) === null || _c === void 0 ? void 0 : _c.call(config, e.dataTransfer, target));
93
+ }
94
+ }), style: Object.assign(Object.assign({}, prevProps === null || prevProps === void 0 ? void 0 : prevProps.style), { position: "relative" }) });
74
95
  },
75
96
  },
76
97
  itemInstance: {
77
- getProps: ({ tree, item, prev }) => (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { draggable: true, onDragStart: (e) => {
78
- var _a, _b, _c;
98
+ getProps: ({ tree, item, prev }) => (Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { draggable: true, onDragEnter: (e) => e.preventDefault(), onDragStart: (e) => {
99
+ var _a, _b, _c, _d;
79
100
  const selectedItems = tree.getSelectedItems();
80
101
  const items = selectedItems.includes(item) ? selectedItems : [item];
81
102
  const config = tree.getConfig();
@@ -86,9 +107,13 @@ exports.dragAndDropFeature = {
86
107
  e.preventDefault();
87
108
  return;
88
109
  }
110
+ if (config.setDragImage) {
111
+ const { imgElement, xOffset, yOffset } = config.setDragImage(items);
112
+ (_c = e.dataTransfer) === null || _c === void 0 ? void 0 : _c.setDragImage(imgElement, xOffset !== null && xOffset !== void 0 ? xOffset : 0, yOffset !== null && yOffset !== void 0 ? yOffset : 0);
113
+ }
89
114
  if (config.createForeignDragObject) {
90
115
  const { format, data } = config.createForeignDragObject(items);
91
- (_c = e.dataTransfer) === null || _c === void 0 ? void 0 : _c.setData(format, data);
116
+ (_d = e.dataTransfer) === null || _d === void 0 ? void 0 : _d.setData(format, data);
92
117
  }
93
118
  tree.applySubStateUpdate("dnd", {
94
119
  draggedItems: items,
@@ -134,6 +159,7 @@ exports.dragAndDropFeature = {
134
159
  (_d = (_c = tree.getConfig()).onCompleteForeignDrop) === null || _d === void 0 ? void 0 : _d.call(_c, draggedItems);
135
160
  }, onDrop: (e) => __awaiter(void 0, void 0, void 0, function* () {
136
161
  var _a, _b, _c;
162
+ e.stopPropagation();
137
163
  const dataRef = tree.getDataRef();
138
164
  const target = (0, utils_1.getDragTarget)(e, item, tree);
139
165
  if (!(0, utils_1.canDrop)(e.dataTransfer, target, tree)) {
@@ -46,6 +46,11 @@ export type DragAndDropFeatureDef<T> = {
46
46
  format: string;
47
47
  data: any;
48
48
  };
49
+ setDragImage?: (items: ItemInstance<T>[]) => {
50
+ imgElement: Element;
51
+ xOffset?: number;
52
+ yOffset?: number;
53
+ };
49
54
  canDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => boolean;
50
55
  onDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => void | Promise<void>;
51
56
  onDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => void | Promise<void>;
@@ -17,6 +17,8 @@ export type MainFeatureDef<T = any> = {
17
17
  treeInstance: {
18
18
  /** @internal */
19
19
  applySubStateUpdate: <K extends keyof TreeState<any>>(stateName: K, updater: Updater<TreeState<T>[K]>) => void;
20
+ /** @internal */
21
+ buildItemInstance: (itemId: string) => ItemInstance<T>;
20
22
  setState: SetStateFn<TreeState<T>>;
21
23
  getState: () => TreeState<T>;
22
24
  setConfig: SetStateFn<TreeConfig<T>>;
@@ -4,6 +4,7 @@ exports.renamingFeature = void 0;
4
4
  const utils_1 = require("../../utils");
5
5
  exports.renamingFeature = {
6
6
  key: "renaming",
7
+ overwrites: ["drag-and-drop"],
7
8
  getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setRenamingItem: (0, utils_1.makeStateUpdater)("renamingItem", tree), setRenamingValue: (0, utils_1.makeStateUpdater)("renamingValue", tree), canRename: () => true }, defaultConfig)),
8
9
  stateHandlerNames: {
9
10
  renamingItem: "setRenamingItem",
@@ -50,6 +51,13 @@ exports.renamingFeature = {
50
51
  }),
51
52
  canRename: ({ tree, item }) => { var _a, _b, _c; return (_c = (_b = (_a = tree.getConfig()).canRename) === null || _b === void 0 ? void 0 : _b.call(_a, item)) !== null && _c !== void 0 ? _c : true; },
52
53
  isRenaming: ({ tree, item }) => item.getId() === tree.getState().renamingItem,
54
+ getProps: ({ prev, item }) => {
55
+ var _a;
56
+ const isRenaming = item.isRenaming();
57
+ const prevProps = (_a = prev === null || prev === void 0 ? void 0 : prev()) !== null && _a !== void 0 ? _a : {};
58
+ return isRenaming
59
+ ? Object.assign(Object.assign({}, prevProps), { draggable: false, onDragStart: () => { } }) : prevProps;
60
+ },
53
61
  },
54
62
  hotkeys: {
55
63
  renameItem: {
@@ -59,6 +59,10 @@ exports.treeFeature = {
59
59
  var _a, _b;
60
60
  return ((_b = tree.getItemInstance((_a = tree.getState().focusedItem) !== null && _a !== void 0 ? _a : "")) !== null && _b !== void 0 ? _b : tree.getItems()[0]);
61
61
  },
62
+ getRootItem: ({ tree }) => {
63
+ const { rootItemId } = tree.getConfig();
64
+ return tree.getItemInstance(rootItemId);
65
+ },
62
66
  focusNextItem: ({ tree }) => {
63
67
  var _a;
64
68
  const focused = tree.getFocusedItem().getItemMeta();
@@ -100,6 +104,7 @@ exports.treeFeature = {
100
104
  (_d = item.getElement()) === null || _d === void 0 ? void 0 : _d.scrollIntoView(scrollIntoViewArg);
101
105
  }),
102
106
  getId: ({ itemId }) => itemId,
107
+ getKey: ({ itemId }) => itemId, // TODO apply to all stories to use
103
108
  getProps: ({ item, prev }) => {
104
109
  const itemMeta = item.getItemMeta();
105
110
  return Object.assign(Object.assign({}, prev === null || prev === void 0 ? void 0 : prev()), { ref: item.registerElement, 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: (e) => {
@@ -27,7 +27,8 @@ export type TreeFeatureDef<T> = {
27
27
  treeInstance: {
28
28
  /** @internal */
29
29
  getItemsMeta: () => ItemMeta[];
30
- getFocusedItem: () => ItemInstance<any>;
30
+ getFocusedItem: () => ItemInstance<T>;
31
+ getRootItem: () => ItemInstance<T>;
31
32
  focusNextItem: () => void;
32
33
  focusPreviousItem: () => void;
33
34
  updateDomFocus: () => void;
@@ -37,6 +38,7 @@ export type TreeFeatureDef<T> = {
37
38
  };
38
39
  itemInstance: {
39
40
  getId: () => string;
41
+ getKey: () => string;
40
42
  getProps: () => Record<string, any>;
41
43
  getItemName: () => string;
42
44
  getItemData: () => T;
@@ -5,6 +5,7 @@ export { MainFeatureDef, InstanceBuilder } from "./features/main/types";
5
5
  export * from "./features/drag-and-drop/types";
6
6
  export * from "./features/keyboard-drag-and-drop/types";
7
7
  export * from "./features/selection/types";
8
+ export * from "./features/checkboxes/types";
8
9
  export * from "./features/async-data-loader/types";
9
10
  export * from "./features/sync-data-loader/types";
10
11
  export * from "./features/hotkeys-core/types";
@@ -13,6 +14,7 @@ export * from "./features/renaming/types";
13
14
  export * from "./features/expand-all/types";
14
15
  export * from "./features/prop-memoization/types";
15
16
  export * from "./features/selection/feature";
17
+ export * from "./features/checkboxes/feature";
16
18
  export * from "./features/hotkeys-core/feature";
17
19
  export * from "./features/async-data-loader/feature";
18
20
  export * from "./features/sync-data-loader/feature";
@@ -27,3 +29,5 @@ export * from "./utilities/insert-items-at-target";
27
29
  export * from "./utilities/remove-items-from-parents";
28
30
  export * from "./core/build-proxified-instance";
29
31
  export * from "./core/build-static-instance";
32
+ export { makeStateUpdater } from "./utils";
33
+ export { isOrderedDragTarget } from "./features/drag-and-drop/utils";
package/lib/cjs/index.js CHANGED
@@ -14,12 +14,14 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.isOrderedDragTarget = exports.makeStateUpdater = void 0;
17
18
  __exportStar(require("./types/core"), exports);
18
19
  __exportStar(require("./core/create-tree"), exports);
19
20
  __exportStar(require("./features/tree/types"), exports);
20
21
  __exportStar(require("./features/drag-and-drop/types"), exports);
21
22
  __exportStar(require("./features/keyboard-drag-and-drop/types"), exports);
22
23
  __exportStar(require("./features/selection/types"), exports);
24
+ __exportStar(require("./features/checkboxes/types"), exports);
23
25
  __exportStar(require("./features/async-data-loader/types"), exports);
24
26
  __exportStar(require("./features/sync-data-loader/types"), exports);
25
27
  __exportStar(require("./features/hotkeys-core/types"), exports);
@@ -28,6 +30,7 @@ __exportStar(require("./features/renaming/types"), exports);
28
30
  __exportStar(require("./features/expand-all/types"), exports);
29
31
  __exportStar(require("./features/prop-memoization/types"), exports);
30
32
  __exportStar(require("./features/selection/feature"), exports);
33
+ __exportStar(require("./features/checkboxes/feature"), exports);
31
34
  __exportStar(require("./features/hotkeys-core/feature"), exports);
32
35
  __exportStar(require("./features/async-data-loader/feature"), exports);
33
36
  __exportStar(require("./features/sync-data-loader/feature"), exports);
@@ -42,3 +45,7 @@ __exportStar(require("./utilities/insert-items-at-target"), exports);
42
45
  __exportStar(require("./utilities/remove-items-from-parents"), exports);
43
46
  __exportStar(require("./core/build-proxified-instance"), exports);
44
47
  __exportStar(require("./core/build-static-instance"), exports);
48
+ var utils_1 = require("./utils");
49
+ Object.defineProperty(exports, "makeStateUpdater", { enumerable: true, get: function () { return utils_1.makeStateUpdater; } });
50
+ var utils_2 = require("./features/drag-and-drop/utils");
51
+ Object.defineProperty(exports, "isOrderedDragTarget", { enumerable: true, get: function () { return utils_2.isOrderedDragTarget; } });
@@ -34,6 +34,7 @@ class TestTree {
34
34
  get instance() {
35
35
  if (!this.treeInstance) {
36
36
  this.treeInstance = (0, create_tree_1.createTree)(this.config);
37
+ this.treeInstance.rebuildTree();
37
38
  }
38
39
  return this.treeInstance;
39
40
  }
@@ -10,6 +10,7 @@ import { RenamingFeatureDef } from "../features/renaming/types";
10
10
  import { ExpandAllFeatureDef } from "../features/expand-all/types";
11
11
  import { PropMemoizationFeatureDef } from "../features/prop-memoization/types";
12
12
  import { KeyboardDragAndDropFeatureDef } from "../features/keyboard-drag-and-drop/types";
13
+ import { CheckboxesFeatureDef } from "../features/checkboxes/types";
13
14
  export type Updater<T> = T | ((old: T) => T);
14
15
  export type SetStateFn<T> = (updaterOrValue: Updater<T>) => void;
15
16
  export type FeatureDef = {
@@ -34,7 +35,7 @@ type MergedFeatures<F extends FeatureDef> = {
34
35
  itemInstance: UnionToIntersection<F["itemInstance"]>;
35
36
  hotkeys: F["hotkeys"];
36
37
  };
37
- export type RegisteredFeatures<T> = MainFeatureDef<T> | TreeFeatureDef<T> | SelectionFeatureDef<T> | DragAndDropFeatureDef<T> | KeyboardDragAndDropFeatureDef<T> | HotkeysCoreFeatureDef<T> | SyncDataLoaderFeatureDef<T> | AsyncDataLoaderFeatureDef<T> | SearchFeatureDef<T> | RenamingFeatureDef<T> | ExpandAllFeatureDef | PropMemoizationFeatureDef;
38
+ export type RegisteredFeatures<T> = MainFeatureDef<T> | TreeFeatureDef<T> | SelectionFeatureDef<T> | CheckboxesFeatureDef<T> | DragAndDropFeatureDef<T> | KeyboardDragAndDropFeatureDef<T> | HotkeysCoreFeatureDef<T> | SyncDataLoaderFeatureDef<T> | AsyncDataLoaderFeatureDef<T> | SearchFeatureDef<T> | RenamingFeatureDef<T> | ExpandAllFeatureDef | PropMemoizationFeatureDef;
38
39
  type TreeStateType<T> = MergedFeatures<RegisteredFeatures<T>>["state"];
39
40
  export interface TreeState<T> extends TreeStateType<T> {
40
41
  }
@@ -11,6 +11,18 @@ const verifyFeatures = (features) => {
11
11
  }
12
12
  }
13
13
  };
14
+ // Check all possible pairs and sort the array
15
+ const exhaustiveSort = (arr, compareFn) => {
16
+ const n = arr.length;
17
+ for (let i = 0; i < n; i++) {
18
+ for (let j = i + 1; j < n; j++) {
19
+ if (compareFn(arr[j], arr[i]) < 0) {
20
+ [arr[i], arr[j]] = [arr[j], arr[i]];
21
+ }
22
+ }
23
+ }
24
+ return arr;
25
+ };
14
26
  const compareFeatures = (originalOrder) => (feature1, feature2) => {
15
27
  var _a, _b;
16
28
  if (feature2.key && ((_a = feature1.overwrites) === null || _a === void 0 ? void 0 : _a.includes(feature2.key))) {
@@ -21,7 +33,7 @@ const compareFeatures = (originalOrder) => (feature1, feature2) => {
21
33
  }
22
34
  return originalOrder.indexOf(feature1) - originalOrder.indexOf(feature2);
23
35
  };
24
- const sortFeatures = (features = []) => features.sort(compareFeatures(features));
36
+ const sortFeatures = (features = []) => exhaustiveSort(features, compareFeatures(features));
25
37
  export const createTree = (initialConfig) => {
26
38
  var _a, _b, _c, _d;
27
39
  const buildInstance = (_a = initialConfig.instanceBuilder) !== null && _a !== void 0 ? _a : buildStaticInstance;
@@ -97,6 +109,15 @@ export const createTree = (initialConfig) => {
97
109
  const externalStateSetter = config[stateHandlerNames[stateName]];
98
110
  externalStateSetter === null || externalStateSetter === void 0 ? void 0 : externalStateSetter(state[stateName]);
99
111
  },
112
+ buildItemInstance: ({}, itemId) => {
113
+ const [instance, finalizeInstance] = buildInstance(features, "itemInstance", (instance) => ({
114
+ item: instance,
115
+ tree: treeInstance,
116
+ itemId,
117
+ }));
118
+ finalizeInstance();
119
+ return instance;
120
+ },
100
121
  // TODO rebuildSubTree: (itemId: string) => void;
101
122
  rebuildTree: () => {
102
123
  var _a;
@@ -162,6 +183,5 @@ export const createTree = (initialConfig) => {
162
183
  Object.assign(hotkeyPresets, (_d = feature.hotkeys) !== null && _d !== void 0 ? _d : {});
163
184
  }
164
185
  finalizeTree();
165
- rebuildItemMeta();
166
186
  return treeInstance;
167
187
  };
@@ -72,14 +72,14 @@ export const asyncDataLoaderFeature = {
72
72
  var _b;
73
73
  return ((_b = getDataRef(tree).current.childrenIds[itemId]) !== null && _b !== void 0 ? _b : (yield loadChildrenIds(tree, itemId)));
74
74
  }),
75
- retrieveItemData: ({ tree }, itemId) => {
75
+ retrieveItemData: ({ tree }, itemId, skipFetch = false) => {
76
76
  var _a, _b;
77
77
  const config = tree.getConfig();
78
78
  const dataRef = getDataRef(tree);
79
79
  if (dataRef.current.itemData[itemId]) {
80
80
  return dataRef.current.itemData[itemId];
81
81
  }
82
- if (!tree.getState().loadingItemData.includes(itemId)) {
82
+ if (!tree.getState().loadingItemData.includes(itemId) && !skipFetch) {
83
83
  tree.applySubStateUpdate("loadingItemData", (loadingItemData) => [
84
84
  ...loadingItemData,
85
85
  itemId,
@@ -88,12 +88,12 @@ export const asyncDataLoaderFeature = {
88
88
  }
89
89
  return (_b = (_a = config.createLoadingItemData) === null || _a === void 0 ? void 0 : _a.call(config)) !== null && _b !== void 0 ? _b : null;
90
90
  },
91
- retrieveChildrenIds: ({ tree }, itemId) => {
91
+ retrieveChildrenIds: ({ tree }, itemId, skipFetch = false) => {
92
92
  const dataRef = getDataRef(tree);
93
93
  if (dataRef.current.childrenIds[itemId]) {
94
94
  return dataRef.current.childrenIds[itemId];
95
95
  }
96
- if (tree.getState().loadingItemChildrens.includes(itemId)) {
96
+ if (tree.getState().loadingItemChildrens.includes(itemId) || skipFetch) {
97
97
  return [];
98
98
  }
99
99
  tree.applySubStateUpdate("loadingItemChildrens", (loadingItemChildrens) => [...loadingItemChildrens, itemId]);
@@ -0,0 +1,2 @@
1
+ import { FeatureImplementation } from "../../types/core";
2
+ export declare const checkboxesFeature: FeatureImplementation;