@headless-tree/core 0.0.0-20250611223358 → 0.0.0-20250611231952
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.
- package/CHANGELOG.md +3 -1
- package/lib/cjs/core/create-tree.js +13 -1
- package/lib/cjs/features/renaming/feature.js +8 -0
- package/lib/esm/core/create-tree.js +13 -1
- package/lib/esm/features/renaming/feature.js +8 -0
- package/package.json +1 -1
- package/src/core/create-tree.ts +20 -1
- package/src/features/renaming/feature.ts +13 -0
- package/src/features/renaming/renaming.spec.ts +31 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @headless-tree/core
|
|
2
2
|
|
|
3
|
-
## 0.0.0-
|
|
3
|
+
## 0.0.0-20250611231952
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
- 727c982: export makeStateUpdater from core package
|
|
18
18
|
- c041a3f: expose `isOrderedDragTarget` as utility method to differentiate between ordered and unordered drag targets (#108)
|
|
19
19
|
- 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.
|
|
20
|
+
- 4e79bc7: Fixed a bug where `feature.overwrites` is not always respected when features are sorted during tree initialization
|
|
21
|
+
- 0669580: Fixed a bug where items that call `item.getProps` while being renamed, can be dragged while being renamed (#110)
|
|
20
22
|
|
|
21
23
|
## 1.1.0
|
|
22
24
|
|
|
@@ -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
|
|
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;
|
|
@@ -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: {
|
|
@@ -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
|
|
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;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { makeStateUpdater } from "../../utils";
|
|
2
2
|
export const renamingFeature = {
|
|
3
3
|
key: "renaming",
|
|
4
|
+
overwrites: ["drag-and-drop"],
|
|
4
5
|
getDefaultConfig: (defaultConfig, tree) => (Object.assign({ setRenamingItem: makeStateUpdater("renamingItem", tree), setRenamingValue: makeStateUpdater("renamingValue", tree), canRename: () => true }, defaultConfig)),
|
|
5
6
|
stateHandlerNames: {
|
|
6
7
|
renamingItem: "setRenamingItem",
|
|
@@ -47,6 +48,13 @@ export const renamingFeature = {
|
|
|
47
48
|
}),
|
|
48
49
|
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; },
|
|
49
50
|
isRenaming: ({ tree, item }) => item.getId() === tree.getState().renamingItem,
|
|
51
|
+
getProps: ({ prev, item }) => {
|
|
52
|
+
var _a;
|
|
53
|
+
const isRenaming = item.isRenaming();
|
|
54
|
+
const prevProps = (_a = prev === null || prev === void 0 ? void 0 : prev()) !== null && _a !== void 0 ? _a : {};
|
|
55
|
+
return isRenaming
|
|
56
|
+
? Object.assign(Object.assign({}, prevProps), { draggable: false, onDragStart: () => { } }) : prevProps;
|
|
57
|
+
},
|
|
50
58
|
},
|
|
51
59
|
hotkeys: {
|
|
52
60
|
renameItem: {
|
package/package.json
CHANGED
package/src/core/create-tree.ts
CHANGED
|
@@ -24,6 +24,24 @@ const verifyFeatures = (features: FeatureImplementation[] | undefined) => {
|
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
// Check all possible pairs and sort the array
|
|
28
|
+
const exhaustiveSort = <T>(
|
|
29
|
+
arr: T[],
|
|
30
|
+
compareFn: (param1: T, param2: T) => number,
|
|
31
|
+
) => {
|
|
32
|
+
const n = arr.length;
|
|
33
|
+
|
|
34
|
+
for (let i = 0; i < n; i++) {
|
|
35
|
+
for (let j = i + 1; j < n; j++) {
|
|
36
|
+
if (compareFn(arr[j], arr[i]) < 0) {
|
|
37
|
+
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return arr;
|
|
43
|
+
};
|
|
44
|
+
|
|
27
45
|
const compareFeatures =
|
|
28
46
|
(originalOrder: FeatureImplementation[]) =>
|
|
29
47
|
(feature1: FeatureImplementation, feature2: FeatureImplementation) => {
|
|
@@ -33,11 +51,12 @@ const compareFeatures =
|
|
|
33
51
|
if (feature1.key && feature2.overwrites?.includes(feature1.key)) {
|
|
34
52
|
return -1;
|
|
35
53
|
}
|
|
54
|
+
|
|
36
55
|
return originalOrder.indexOf(feature1) - originalOrder.indexOf(feature2);
|
|
37
56
|
};
|
|
38
57
|
|
|
39
58
|
const sortFeatures = (features: FeatureImplementation[] = []) =>
|
|
40
|
-
features
|
|
59
|
+
exhaustiveSort(features, compareFeatures(features));
|
|
41
60
|
|
|
42
61
|
export const createTree = <T>(
|
|
43
62
|
initialConfig: TreeConfig<T>,
|
|
@@ -9,6 +9,7 @@ type InputEvent = {
|
|
|
9
9
|
|
|
10
10
|
export const renamingFeature: FeatureImplementation = {
|
|
11
11
|
key: "renaming",
|
|
12
|
+
overwrites: ["drag-and-drop"],
|
|
12
13
|
|
|
13
14
|
getDefaultConfig: (defaultConfig, tree) => ({
|
|
14
15
|
setRenamingItem: makeStateUpdater("renamingItem", tree),
|
|
@@ -72,6 +73,18 @@ export const renamingFeature: FeatureImplementation = {
|
|
|
72
73
|
|
|
73
74
|
isRenaming: ({ tree, item }) =>
|
|
74
75
|
item.getId() === tree.getState().renamingItem,
|
|
76
|
+
|
|
77
|
+
getProps: ({ prev, item }) => {
|
|
78
|
+
const isRenaming = item.isRenaming();
|
|
79
|
+
const prevProps = prev?.() ?? {};
|
|
80
|
+
return isRenaming
|
|
81
|
+
? {
|
|
82
|
+
...prevProps,
|
|
83
|
+
draggable: false,
|
|
84
|
+
onDragStart: () => {},
|
|
85
|
+
}
|
|
86
|
+
: prevProps;
|
|
87
|
+
},
|
|
75
88
|
},
|
|
76
89
|
|
|
77
90
|
hotkeys: {
|
|
@@ -93,6 +93,37 @@ describe("core-feature/renaming", () => {
|
|
|
93
93
|
expect(setRenamingItem).toHaveBeenCalledWith(null);
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
+
describe("dragging", async () => {
|
|
97
|
+
const suiteTree = await tree
|
|
98
|
+
.withFeatures({
|
|
99
|
+
key: "drag-and-drop",
|
|
100
|
+
itemInstance: {
|
|
101
|
+
getProps: ({ prev }: any) => ({
|
|
102
|
+
...prev?.(),
|
|
103
|
+
draggable: true,
|
|
104
|
+
onDragStart: "initialOnDragStart",
|
|
105
|
+
}),
|
|
106
|
+
},
|
|
107
|
+
})
|
|
108
|
+
.createTestCaseTree();
|
|
109
|
+
suiteTree.resetBeforeEach();
|
|
110
|
+
|
|
111
|
+
it("sets draggable to undefined for items being renamed", () => {
|
|
112
|
+
const item = suiteTree.item("x1");
|
|
113
|
+
item.startRenaming();
|
|
114
|
+
const props = item.getProps();
|
|
115
|
+
expect(props.draggable).toBe(false);
|
|
116
|
+
expect(props.onDragStart).toStrictEqual(expect.any(Function));
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("retains draggable for items not being renamed", () => {
|
|
120
|
+
const item = suiteTree.item("x1");
|
|
121
|
+
const props = item.getProps();
|
|
122
|
+
expect(props.draggable).toBe(true);
|
|
123
|
+
expect(props.onDragStart).toBe("initialOnDragStart");
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
96
127
|
describe("hotkeys", () => {
|
|
97
128
|
it("starts renaming", () => {
|
|
98
129
|
const setRenamingItem = tree.mockedHandler("setRenamingItem");
|