@headless-tree/core 0.0.0-20250726131941 → 0.0.0-20250730213235
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 +2 -1
- package/dist/index.d.mts +1 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +34 -16
- package/dist/index.mjs +34 -16
- package/package.json +1 -1
- package/src/core/create-tree.ts +26 -15
- package/src/features/async-data-loader/feature.ts +5 -0
- package/src/features/async-data-loader/types.ts +2 -0
- package/src/features/checkboxes/feature.ts +1 -1
- package/src/features/main/types.ts +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# @headless-tree/core
|
|
2
2
|
|
|
3
|
-
## 0.0.0-
|
|
3
|
+
## 0.0.0-20250730213235
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
+
- e8ddbb0: Added `item.updateCachedData(data)` in async tree feature, that works similar to the existing `item.updateCachedChildrenIds(childrenIds)` feature
|
|
7
8
|
- 662e2a8: Added stories and documentation on how to use nested DOM rendering for tree structures instead of flat lists,
|
|
8
9
|
which can be used for animating expand/collapse behavior
|
|
9
10
|
- b41e1d2: fixed a bug where ending drag without successful drop doesn't properly reset drag line (#132)
|
package/dist/index.d.mts
CHANGED
|
@@ -150,8 +150,6 @@ type MainFeatureDef<T = any> = {
|
|
|
150
150
|
treeInstance: {
|
|
151
151
|
/** @internal */
|
|
152
152
|
applySubStateUpdate: <K extends keyof TreeState<any>>(stateName: K, updater: Updater<TreeState<T>[K]>) => void;
|
|
153
|
-
/** @internal */
|
|
154
|
-
buildItemInstance: (itemId: string) => ItemInstance<T>;
|
|
155
153
|
setState: SetStateFn<TreeState<T>>;
|
|
156
154
|
getState: () => TreeState<T>;
|
|
157
155
|
setConfig: SetStateFn<TreeConfig<T>>;
|
|
@@ -296,6 +294,7 @@ type AsyncDataLoaderFeatureDef<T> = {
|
|
|
296
294
|
* @param optimistic If true, the item will not trigger a state update on `loadingItemChildrens`, and
|
|
297
295
|
* the tree will continue to display the old data until the new data has loaded. */
|
|
298
296
|
invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
|
|
297
|
+
updateCachedData: (data: T) => void;
|
|
299
298
|
updateCachedChildrenIds: (childrenIds: string[]) => void;
|
|
300
299
|
isLoading: () => boolean;
|
|
301
300
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -150,8 +150,6 @@ type MainFeatureDef<T = any> = {
|
|
|
150
150
|
treeInstance: {
|
|
151
151
|
/** @internal */
|
|
152
152
|
applySubStateUpdate: <K extends keyof TreeState<any>>(stateName: K, updater: Updater<TreeState<T>[K]>) => void;
|
|
153
|
-
/** @internal */
|
|
154
|
-
buildItemInstance: (itemId: string) => ItemInstance<T>;
|
|
155
153
|
setState: SetStateFn<TreeState<T>>;
|
|
156
154
|
getState: () => TreeState<T>;
|
|
157
155
|
setConfig: SetStateFn<TreeConfig<T>>;
|
|
@@ -296,6 +294,7 @@ type AsyncDataLoaderFeatureDef<T> = {
|
|
|
296
294
|
* @param optimistic If true, the item will not trigger a state update on `loadingItemChildrens`, and
|
|
297
295
|
* the tree will continue to display the old data until the new data has loaded. */
|
|
298
296
|
invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
|
|
297
|
+
updateCachedData: (data: T) => void;
|
|
299
298
|
updateCachedChildrenIds: (childrenIds: string[]) => void;
|
|
300
299
|
isLoading: () => boolean;
|
|
301
300
|
};
|
package/dist/index.js
CHANGED
|
@@ -547,19 +547,6 @@ var createTree = (initialConfig) => {
|
|
|
547
547
|
const externalStateSetter = config[stateHandlerNames[stateName]];
|
|
548
548
|
externalStateSetter == null ? void 0 : externalStateSetter(state[stateName]);
|
|
549
549
|
},
|
|
550
|
-
buildItemInstance: ({}, itemId) => {
|
|
551
|
-
const [instance, finalizeInstance] = buildInstance(
|
|
552
|
-
features,
|
|
553
|
-
"itemInstance",
|
|
554
|
-
(instance2) => ({
|
|
555
|
-
item: instance2,
|
|
556
|
-
tree: treeInstance,
|
|
557
|
-
itemId
|
|
558
|
-
})
|
|
559
|
-
);
|
|
560
|
-
finalizeInstance();
|
|
561
|
-
return instance;
|
|
562
|
-
},
|
|
563
550
|
// TODO rebuildSubTree: (itemId: string) => void;
|
|
564
551
|
rebuildTree: () => {
|
|
565
552
|
var _a2;
|
|
@@ -580,7 +567,23 @@ var createTree = (initialConfig) => {
|
|
|
580
567
|
(_c2 = config.setState) == null ? void 0 : _c2.call(config, state);
|
|
581
568
|
}
|
|
582
569
|
},
|
|
583
|
-
getItemInstance: ({}, itemId) =>
|
|
570
|
+
getItemInstance: ({}, itemId) => {
|
|
571
|
+
const existingInstance = itemInstancesMap[itemId];
|
|
572
|
+
if (!existingInstance) {
|
|
573
|
+
const [instance, finalizeInstance] = buildInstance(
|
|
574
|
+
features,
|
|
575
|
+
"itemInstance",
|
|
576
|
+
(instance2) => ({
|
|
577
|
+
item: instance2,
|
|
578
|
+
tree: treeInstance,
|
|
579
|
+
itemId
|
|
580
|
+
})
|
|
581
|
+
);
|
|
582
|
+
finalizeInstance();
|
|
583
|
+
return instance;
|
|
584
|
+
}
|
|
585
|
+
return existingInstance;
|
|
586
|
+
},
|
|
584
587
|
getItems: () => itemInstances,
|
|
585
588
|
registerElement: ({}, element) => {
|
|
586
589
|
if (treeElement === element) {
|
|
@@ -636,7 +639,17 @@ var createTree = (initialConfig) => {
|
|
|
636
639
|
var _a2;
|
|
637
640
|
return (_a2 = itemDataRefs[itemId]) != null ? _a2 : itemDataRefs[itemId] = { current: {} };
|
|
638
641
|
},
|
|
639
|
-
getItemMeta: ({ itemId }) =>
|
|
642
|
+
getItemMeta: ({ itemId }) => {
|
|
643
|
+
var _a2;
|
|
644
|
+
return (_a2 = itemMetaMap[itemId]) != null ? _a2 : {
|
|
645
|
+
itemId,
|
|
646
|
+
parentId: null,
|
|
647
|
+
level: -1,
|
|
648
|
+
index: -1,
|
|
649
|
+
posInSet: 0,
|
|
650
|
+
setSize: 1
|
|
651
|
+
};
|
|
652
|
+
}
|
|
640
653
|
}
|
|
641
654
|
};
|
|
642
655
|
features.unshift(mainFeature);
|
|
@@ -801,7 +814,7 @@ var selectionFeature = {
|
|
|
801
814
|
|
|
802
815
|
// src/features/checkboxes/feature.ts
|
|
803
816
|
var getAllLoadedDescendants = (tree, itemId, includeFolders = false) => {
|
|
804
|
-
if (!tree.getConfig().isItemFolder(tree.
|
|
817
|
+
if (!tree.getConfig().isItemFolder(tree.getItemInstance(itemId))) {
|
|
805
818
|
return [itemId];
|
|
806
819
|
}
|
|
807
820
|
const descendants = tree.retrieveChildrenIds(itemId).map((child) => getAllLoadedDescendants(tree, child, includeFolders)).flat();
|
|
@@ -1147,6 +1160,11 @@ var asyncDataLoaderFeature = {
|
|
|
1147
1160
|
const dataRef = tree.getDataRef();
|
|
1148
1161
|
dataRef.current.childrenIds[itemId] = childrenIds;
|
|
1149
1162
|
tree.rebuildTree();
|
|
1163
|
+
},
|
|
1164
|
+
updateCachedData: ({ tree, itemId }, data) => {
|
|
1165
|
+
const dataRef = tree.getDataRef();
|
|
1166
|
+
dataRef.current.itemData[itemId] = data;
|
|
1167
|
+
tree.rebuildTree();
|
|
1150
1168
|
}
|
|
1151
1169
|
}
|
|
1152
1170
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -503,19 +503,6 @@ var createTree = (initialConfig) => {
|
|
|
503
503
|
const externalStateSetter = config[stateHandlerNames[stateName]];
|
|
504
504
|
externalStateSetter == null ? void 0 : externalStateSetter(state[stateName]);
|
|
505
505
|
},
|
|
506
|
-
buildItemInstance: ({}, itemId) => {
|
|
507
|
-
const [instance, finalizeInstance] = buildInstance(
|
|
508
|
-
features,
|
|
509
|
-
"itemInstance",
|
|
510
|
-
(instance2) => ({
|
|
511
|
-
item: instance2,
|
|
512
|
-
tree: treeInstance,
|
|
513
|
-
itemId
|
|
514
|
-
})
|
|
515
|
-
);
|
|
516
|
-
finalizeInstance();
|
|
517
|
-
return instance;
|
|
518
|
-
},
|
|
519
506
|
// TODO rebuildSubTree: (itemId: string) => void;
|
|
520
507
|
rebuildTree: () => {
|
|
521
508
|
var _a2;
|
|
@@ -536,7 +523,23 @@ var createTree = (initialConfig) => {
|
|
|
536
523
|
(_c2 = config.setState) == null ? void 0 : _c2.call(config, state);
|
|
537
524
|
}
|
|
538
525
|
},
|
|
539
|
-
getItemInstance: ({}, itemId) =>
|
|
526
|
+
getItemInstance: ({}, itemId) => {
|
|
527
|
+
const existingInstance = itemInstancesMap[itemId];
|
|
528
|
+
if (!existingInstance) {
|
|
529
|
+
const [instance, finalizeInstance] = buildInstance(
|
|
530
|
+
features,
|
|
531
|
+
"itemInstance",
|
|
532
|
+
(instance2) => ({
|
|
533
|
+
item: instance2,
|
|
534
|
+
tree: treeInstance,
|
|
535
|
+
itemId
|
|
536
|
+
})
|
|
537
|
+
);
|
|
538
|
+
finalizeInstance();
|
|
539
|
+
return instance;
|
|
540
|
+
}
|
|
541
|
+
return existingInstance;
|
|
542
|
+
},
|
|
540
543
|
getItems: () => itemInstances,
|
|
541
544
|
registerElement: ({}, element) => {
|
|
542
545
|
if (treeElement === element) {
|
|
@@ -592,7 +595,17 @@ var createTree = (initialConfig) => {
|
|
|
592
595
|
var _a2;
|
|
593
596
|
return (_a2 = itemDataRefs[itemId]) != null ? _a2 : itemDataRefs[itemId] = { current: {} };
|
|
594
597
|
},
|
|
595
|
-
getItemMeta: ({ itemId }) =>
|
|
598
|
+
getItemMeta: ({ itemId }) => {
|
|
599
|
+
var _a2;
|
|
600
|
+
return (_a2 = itemMetaMap[itemId]) != null ? _a2 : {
|
|
601
|
+
itemId,
|
|
602
|
+
parentId: null,
|
|
603
|
+
level: -1,
|
|
604
|
+
index: -1,
|
|
605
|
+
posInSet: 0,
|
|
606
|
+
setSize: 1
|
|
607
|
+
};
|
|
608
|
+
}
|
|
596
609
|
}
|
|
597
610
|
};
|
|
598
611
|
features.unshift(mainFeature);
|
|
@@ -757,7 +770,7 @@ var selectionFeature = {
|
|
|
757
770
|
|
|
758
771
|
// src/features/checkboxes/feature.ts
|
|
759
772
|
var getAllLoadedDescendants = (tree, itemId, includeFolders = false) => {
|
|
760
|
-
if (!tree.getConfig().isItemFolder(tree.
|
|
773
|
+
if (!tree.getConfig().isItemFolder(tree.getItemInstance(itemId))) {
|
|
761
774
|
return [itemId];
|
|
762
775
|
}
|
|
763
776
|
const descendants = tree.retrieveChildrenIds(itemId).map((child) => getAllLoadedDescendants(tree, child, includeFolders)).flat();
|
|
@@ -1103,6 +1116,11 @@ var asyncDataLoaderFeature = {
|
|
|
1103
1116
|
const dataRef = tree.getDataRef();
|
|
1104
1117
|
dataRef.current.childrenIds[itemId] = childrenIds;
|
|
1105
1118
|
tree.rebuildTree();
|
|
1119
|
+
},
|
|
1120
|
+
updateCachedData: ({ tree, itemId }, data) => {
|
|
1121
|
+
const dataRef = tree.getDataRef();
|
|
1122
|
+
dataRef.current.itemData[itemId] = data;
|
|
1123
|
+
tree.rebuildTree();
|
|
1106
1124
|
}
|
|
1107
1125
|
}
|
|
1108
1126
|
};
|
package/package.json
CHANGED
package/src/core/create-tree.ts
CHANGED
|
@@ -170,19 +170,6 @@ export const createTree = <T>(
|
|
|
170
170
|
] as Function;
|
|
171
171
|
externalStateSetter?.(state[stateName]);
|
|
172
172
|
},
|
|
173
|
-
buildItemInstance: ({}, itemId) => {
|
|
174
|
-
const [instance, finalizeInstance] = buildInstance(
|
|
175
|
-
features,
|
|
176
|
-
"itemInstance",
|
|
177
|
-
(instance) => ({
|
|
178
|
-
item: instance,
|
|
179
|
-
tree: treeInstance,
|
|
180
|
-
itemId,
|
|
181
|
-
}),
|
|
182
|
-
);
|
|
183
|
-
finalizeInstance();
|
|
184
|
-
return instance;
|
|
185
|
-
},
|
|
186
173
|
// TODO rebuildSubTree: (itemId: string) => void;
|
|
187
174
|
rebuildTree: () => {
|
|
188
175
|
rebuildItemMeta();
|
|
@@ -206,7 +193,23 @@ export const createTree = <T>(
|
|
|
206
193
|
config.setState?.(state);
|
|
207
194
|
}
|
|
208
195
|
},
|
|
209
|
-
getItemInstance: ({}, itemId) =>
|
|
196
|
+
getItemInstance: ({}, itemId) => {
|
|
197
|
+
const existingInstance = itemInstancesMap[itemId];
|
|
198
|
+
if (!existingInstance) {
|
|
199
|
+
const [instance, finalizeInstance] = buildInstance(
|
|
200
|
+
features,
|
|
201
|
+
"itemInstance",
|
|
202
|
+
(instance) => ({
|
|
203
|
+
item: instance,
|
|
204
|
+
tree: treeInstance,
|
|
205
|
+
itemId,
|
|
206
|
+
}),
|
|
207
|
+
);
|
|
208
|
+
finalizeInstance();
|
|
209
|
+
return instance;
|
|
210
|
+
}
|
|
211
|
+
return existingInstance;
|
|
212
|
+
},
|
|
210
213
|
getItems: () => itemInstances,
|
|
211
214
|
registerElement: ({}, element) => {
|
|
212
215
|
if (treeElement === element) {
|
|
@@ -249,7 +252,15 @@ export const createTree = <T>(
|
|
|
249
252
|
getElement: ({ itemId }) => itemElementsMap[itemId],
|
|
250
253
|
// eslint-disable-next-line no-return-assign
|
|
251
254
|
getDataRef: ({ itemId }) => (itemDataRefs[itemId] ??= { current: {} }),
|
|
252
|
-
getItemMeta: ({ itemId }) =>
|
|
255
|
+
getItemMeta: ({ itemId }) =>
|
|
256
|
+
itemMetaMap[itemId] ?? {
|
|
257
|
+
itemId,
|
|
258
|
+
parentId: null,
|
|
259
|
+
level: -1,
|
|
260
|
+
index: -1,
|
|
261
|
+
posInSet: 0,
|
|
262
|
+
setSize: 1,
|
|
263
|
+
},
|
|
253
264
|
},
|
|
254
265
|
};
|
|
255
266
|
|
|
@@ -165,5 +165,10 @@ export const asyncDataLoaderFeature: FeatureImplementation = {
|
|
|
165
165
|
dataRef.current.childrenIds[itemId] = childrenIds;
|
|
166
166
|
tree.rebuildTree();
|
|
167
167
|
},
|
|
168
|
+
updateCachedData: ({ tree, itemId }, data) => {
|
|
169
|
+
const dataRef = tree.getDataRef<AsyncDataLoaderDataRef>();
|
|
170
|
+
dataRef.current.itemData[itemId] = data;
|
|
171
|
+
tree.rebuildTree();
|
|
172
|
+
},
|
|
168
173
|
},
|
|
169
174
|
};
|
|
@@ -34,6 +34,7 @@ export type AsyncDataLoaderFeatureDef<T> = {
|
|
|
34
34
|
waitForItemChildrenLoaded: (itemId: string) => Promise<void>;
|
|
35
35
|
loadItemData: (itemId: string) => Promise<T>;
|
|
36
36
|
loadChildrenIds: (itemId: string) => Promise<string[]>;
|
|
37
|
+
/* idea: recursiveLoadItems: (itemId: string, cancelToken?: { current: boolean }, onLoad: (itemIds: string[]) => void) => Promise<T[]> */
|
|
37
38
|
};
|
|
38
39
|
itemInstance: SyncDataLoaderFeatureDef<T>["itemInstance"] & {
|
|
39
40
|
/** Invalidate fetched data for item, and triggers a refetch and subsequent rerender if the item is visible
|
|
@@ -46,6 +47,7 @@ export type AsyncDataLoaderFeatureDef<T> = {
|
|
|
46
47
|
* the tree will continue to display the old data until the new data has loaded. */
|
|
47
48
|
invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
|
|
48
49
|
|
|
50
|
+
updateCachedData: (data: T) => void;
|
|
49
51
|
updateCachedChildrenIds: (childrenIds: string[]) => void;
|
|
50
52
|
isLoading: () => boolean;
|
|
51
53
|
};
|
|
@@ -8,7 +8,7 @@ const getAllLoadedDescendants = <T>(
|
|
|
8
8
|
itemId: string,
|
|
9
9
|
includeFolders = false,
|
|
10
10
|
): string[] => {
|
|
11
|
-
if (!tree.getConfig().isItemFolder(tree.
|
|
11
|
+
if (!tree.getConfig().isItemFolder(tree.getItemInstance(itemId))) {
|
|
12
12
|
return [itemId];
|
|
13
13
|
}
|
|
14
14
|
const descendants = tree
|
|
@@ -36,8 +36,6 @@ export type MainFeatureDef<T = any> = {
|
|
|
36
36
|
stateName: K,
|
|
37
37
|
updater: Updater<TreeState<T>[K]>,
|
|
38
38
|
) => void;
|
|
39
|
-
/** @internal */
|
|
40
|
-
buildItemInstance: (itemId: string) => ItemInstance<T>;
|
|
41
39
|
setState: SetStateFn<TreeState<T>>;
|
|
42
40
|
getState: () => TreeState<T>;
|
|
43
41
|
setConfig: SetStateFn<TreeConfig<T>>;
|