@headless-tree/core 1.4.0 → 1.5.0

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 CHANGED
@@ -1,5 +1,22 @@
1
1
  # @headless-tree/core
2
2
 
3
+ ## 1.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - cbeaba6: all state updates (like setSelectedItems) will not propagate while the component is unmounted. This happened before for `tree.setState()` calls directly, but not individual state atoms like `setSelectedItems`. When calling `createTree()` directly (instead of `useTree()`), `tree.setMounted(true)` needs to be called once after mount. No changes are necessary when using the React-based `useTree()` integration. (#158)
8
+
9
+ ### Patch Changes
10
+
11
+ - 72e714b: all NPM deployments will now publish with provenance
12
+ - 6693986: fixed an issue where async data loaders cause calling `item.getItemData()` outside of the component calling `useTree()` to cause a React warning log (#158)
13
+ - 7a7424f: fixed incorrect exports definition in package.json for require/cjs imports (#161)
14
+ - 215ab4b: add a new symbol that can be used in hotkey configurations "metaorcontrol" that will trigger if either any windows control key or mac meta key is pressed (#141)
15
+ - 51b0dea: Added `isUnorderedDragTarget` as alternative to `isDragTarget` for easier detection of drag type
16
+ - cf845d7: Added new state variable `loadingCheckPropagationItems` to indicate if, in async trees with checkboxes and state propagation enabled, data loading operations are currently loading due to a checkbox propagation taking place
17
+ - 597faad: Checkbox propagation is now supported for trees with async data loaders!
18
+ - b0ee382: triggering a data refetch will now always set the loadingItemData/loadingItemChildrens state variable to the associated items if they where not apart of the cache before
19
+
3
20
  ## 1.4.0
4
21
 
5
22
  ### Minor Changes
package/dist/index.d.mts CHANGED
@@ -75,7 +75,12 @@ type DragAndDropFeatureDef<T> = {
75
75
  getDragLineStyle: (topOffset?: number, leftOffset?: number) => Record<string, any>;
76
76
  };
77
77
  itemInstance: {
78
+ /** Checks if the user is dragging in a way which makes this the new parent of the dragged items, either by dragging on top of
79
+ * this item, or by dragging inbetween children of this item. See @{isUnorderedDragTarget} if the latter is undesirable. */
78
80
  isDragTarget: () => boolean;
81
+ /** As opposed to @{isDragTarget}, this will not be true if the target is inbetween children of this item. This returns only true
82
+ * if the user is dragging directly on top of this item. */
83
+ isUnorderedDragTarget: () => boolean;
79
84
  isDragTargetAbove: () => boolean;
80
85
  isDragTargetBelow: () => boolean;
81
86
  isDraggingOver: () => boolean;
@@ -177,6 +182,10 @@ type MainFeatureDef<T = any> = {
177
182
  };
178
183
  getHotkeyPresets: () => HotkeysConfig<T>;
179
184
  rebuildTree: () => void;
185
+ /** @deprecated Experimental feature, might get removed or changed in the future. */
186
+ scheduleRebuildTree: () => void;
187
+ /** @internal */
188
+ setMounted: (isMounted: boolean) => void;
180
189
  };
181
190
  itemInstance: {
182
191
  registerElement: (element: HTMLElement | null) => void;
@@ -259,7 +268,12 @@ type SyncDataLoaderFeatureDef<T> = {
259
268
  };
260
269
  treeInstance: {
261
270
  retrieveItemData: (itemId: string) => T;
262
- retrieveChildrenIds: (itemId: string) => string[];
271
+ /** Retrieve children Ids. If an async data loader is used, skipFetch is set to true, and children have not been retrieved
272
+ * yet for this item, this will initiate fetching the children, and return an empty array. Once the children have loaded,
273
+ * a rerender will be triggered.
274
+ * @param skipFetch - Defaults to false.
275
+ */
276
+ retrieveChildrenIds: (itemId: string, skipFetch?: boolean) => string[];
263
277
  };
264
278
  itemInstance: {
265
279
  isLoading: () => boolean;
@@ -307,7 +321,8 @@ type AsyncDataLoaderFeatureDef<T> = {
307
321
  * @param optimistic If true, the item will not trigger a state update on `loadingItemChildrens`, and
308
322
  * the tree will continue to display the old data until the new data has loaded. */
309
323
  invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
310
- updateCachedData: (data: T) => void;
324
+ /** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch. */
325
+ updateCachedData: (data: T | undefined) => void;
311
326
  updateCachedChildrenIds: (childrenIds: string[]) => void;
312
327
  isLoading: () => boolean;
313
328
  };
@@ -443,9 +458,11 @@ declare enum CheckedState {
443
458
  type CheckboxesFeatureDef<T> = {
444
459
  state: {
445
460
  checkedItems: string[];
461
+ loadingCheckPropagationItems: string[];
446
462
  };
447
463
  config: {
448
464
  setCheckedItems?: SetStateFn<string[]>;
465
+ setLoadingCheckPropagationItems?: SetStateFn<string[]>;
449
466
  canCheckFolders?: boolean;
450
467
  propagateCheckedState?: boolean;
451
468
  };
@@ -453,11 +470,18 @@ type CheckboxesFeatureDef<T> = {
453
470
  setCheckedItems: (checkedItems: string[]) => void;
454
471
  };
455
472
  itemInstance: {
456
- setChecked: () => void;
457
- setUnchecked: () => void;
458
- toggleCheckedState: () => void;
473
+ /** Will recursively load descendants if propagateCheckedState=true and async data loader is used. If not,
474
+ * this will return immediately. */
475
+ setChecked: () => Promise<void>;
476
+ /** Will recursively load descendants if propagateCheckedState=true and async data loader is used. If not,
477
+ * this will return immediately. */
478
+ setUnchecked: () => Promise<void>;
479
+ /** Will recursively load descendants if propagateCheckedState=true and async data loader is used. If not,
480
+ * this will return immediately. */
481
+ toggleCheckedState: () => Promise<void>;
459
482
  getCheckedState: () => CheckedState;
460
483
  getCheckboxProps: () => Record<string, any>;
484
+ isLoadingCheckPropagation: () => boolean;
461
485
  };
462
486
  hotkeys: never;
463
487
  };
@@ -503,11 +527,11 @@ type HotkeyName = MergedFeatures<RegisteredFeatures<any>>["hotkeys"];
503
527
  type HotkeysConfig<T> = Record<HotkeyName, HotkeyConfig<T>>;
504
528
  type CustomHotkeysConfig<T> = Partial<Record<HotkeyName | `custom${string}`, Partial<HotkeyConfig<T>>>>;
505
529
  type MayReturnNull<T extends (...x: any[]) => any> = (...args: Parameters<T>) => ReturnType<T> | null;
506
- type ItemInstanceOpts<Key extends keyof ItemInstance<any>> = {
507
- item: ItemInstance<any>;
508
- tree: TreeInstance<any>;
530
+ type ItemInstanceOpts<T, Key extends keyof ItemInstance<any>> = {
531
+ item: ItemInstance<T>;
532
+ tree: TreeInstance<T>;
509
533
  itemId: string;
510
- prev?: MayReturnNull<ItemInstance<any>[Key]>;
534
+ prev?: MayReturnNull<ItemInstance<T>[Key]>;
511
535
  };
512
536
  type TreeInstanceOpts<Key extends keyof TreeInstance<any>> = {
513
537
  tree: TreeInstance<any>;
@@ -524,7 +548,7 @@ type FeatureImplementation<T = any> = {
524
548
  [key in keyof TreeInstance<T>]?: (opts: TreeInstanceOpts<key>, ...args: Parameters<TreeInstance<T>[key]>) => void;
525
549
  };
526
550
  itemInstance?: {
527
- [key in keyof ItemInstance<T>]?: (opts: ItemInstanceOpts<key>, ...args: Parameters<ItemInstance<T>[key]>) => void;
551
+ [key in keyof ItemInstance<T>]?: (opts: ItemInstanceOpts<T, key>, ...args: Parameters<ItemInstance<T>[key]>) => void;
528
552
  };
529
553
  onTreeMount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
530
554
  onTreeUnmount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
package/dist/index.d.ts CHANGED
@@ -75,7 +75,12 @@ type DragAndDropFeatureDef<T> = {
75
75
  getDragLineStyle: (topOffset?: number, leftOffset?: number) => Record<string, any>;
76
76
  };
77
77
  itemInstance: {
78
+ /** Checks if the user is dragging in a way which makes this the new parent of the dragged items, either by dragging on top of
79
+ * this item, or by dragging inbetween children of this item. See @{isUnorderedDragTarget} if the latter is undesirable. */
78
80
  isDragTarget: () => boolean;
81
+ /** As opposed to @{isDragTarget}, this will not be true if the target is inbetween children of this item. This returns only true
82
+ * if the user is dragging directly on top of this item. */
83
+ isUnorderedDragTarget: () => boolean;
79
84
  isDragTargetAbove: () => boolean;
80
85
  isDragTargetBelow: () => boolean;
81
86
  isDraggingOver: () => boolean;
@@ -177,6 +182,10 @@ type MainFeatureDef<T = any> = {
177
182
  };
178
183
  getHotkeyPresets: () => HotkeysConfig<T>;
179
184
  rebuildTree: () => void;
185
+ /** @deprecated Experimental feature, might get removed or changed in the future. */
186
+ scheduleRebuildTree: () => void;
187
+ /** @internal */
188
+ setMounted: (isMounted: boolean) => void;
180
189
  };
181
190
  itemInstance: {
182
191
  registerElement: (element: HTMLElement | null) => void;
@@ -259,7 +268,12 @@ type SyncDataLoaderFeatureDef<T> = {
259
268
  };
260
269
  treeInstance: {
261
270
  retrieveItemData: (itemId: string) => T;
262
- retrieveChildrenIds: (itemId: string) => string[];
271
+ /** Retrieve children Ids. If an async data loader is used, skipFetch is set to true, and children have not been retrieved
272
+ * yet for this item, this will initiate fetching the children, and return an empty array. Once the children have loaded,
273
+ * a rerender will be triggered.
274
+ * @param skipFetch - Defaults to false.
275
+ */
276
+ retrieveChildrenIds: (itemId: string, skipFetch?: boolean) => string[];
263
277
  };
264
278
  itemInstance: {
265
279
  isLoading: () => boolean;
@@ -307,7 +321,8 @@ type AsyncDataLoaderFeatureDef<T> = {
307
321
  * @param optimistic If true, the item will not trigger a state update on `loadingItemChildrens`, and
308
322
  * the tree will continue to display the old data until the new data has loaded. */
309
323
  invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
310
- updateCachedData: (data: T) => void;
324
+ /** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch. */
325
+ updateCachedData: (data: T | undefined) => void;
311
326
  updateCachedChildrenIds: (childrenIds: string[]) => void;
312
327
  isLoading: () => boolean;
313
328
  };
@@ -443,9 +458,11 @@ declare enum CheckedState {
443
458
  type CheckboxesFeatureDef<T> = {
444
459
  state: {
445
460
  checkedItems: string[];
461
+ loadingCheckPropagationItems: string[];
446
462
  };
447
463
  config: {
448
464
  setCheckedItems?: SetStateFn<string[]>;
465
+ setLoadingCheckPropagationItems?: SetStateFn<string[]>;
449
466
  canCheckFolders?: boolean;
450
467
  propagateCheckedState?: boolean;
451
468
  };
@@ -453,11 +470,18 @@ type CheckboxesFeatureDef<T> = {
453
470
  setCheckedItems: (checkedItems: string[]) => void;
454
471
  };
455
472
  itemInstance: {
456
- setChecked: () => void;
457
- setUnchecked: () => void;
458
- toggleCheckedState: () => void;
473
+ /** Will recursively load descendants if propagateCheckedState=true and async data loader is used. If not,
474
+ * this will return immediately. */
475
+ setChecked: () => Promise<void>;
476
+ /** Will recursively load descendants if propagateCheckedState=true and async data loader is used. If not,
477
+ * this will return immediately. */
478
+ setUnchecked: () => Promise<void>;
479
+ /** Will recursively load descendants if propagateCheckedState=true and async data loader is used. If not,
480
+ * this will return immediately. */
481
+ toggleCheckedState: () => Promise<void>;
459
482
  getCheckedState: () => CheckedState;
460
483
  getCheckboxProps: () => Record<string, any>;
484
+ isLoadingCheckPropagation: () => boolean;
461
485
  };
462
486
  hotkeys: never;
463
487
  };
@@ -503,11 +527,11 @@ type HotkeyName = MergedFeatures<RegisteredFeatures<any>>["hotkeys"];
503
527
  type HotkeysConfig<T> = Record<HotkeyName, HotkeyConfig<T>>;
504
528
  type CustomHotkeysConfig<T> = Partial<Record<HotkeyName | `custom${string}`, Partial<HotkeyConfig<T>>>>;
505
529
  type MayReturnNull<T extends (...x: any[]) => any> = (...args: Parameters<T>) => ReturnType<T> | null;
506
- type ItemInstanceOpts<Key extends keyof ItemInstance<any>> = {
507
- item: ItemInstance<any>;
508
- tree: TreeInstance<any>;
530
+ type ItemInstanceOpts<T, Key extends keyof ItemInstance<any>> = {
531
+ item: ItemInstance<T>;
532
+ tree: TreeInstance<T>;
509
533
  itemId: string;
510
- prev?: MayReturnNull<ItemInstance<any>[Key]>;
534
+ prev?: MayReturnNull<ItemInstance<T>[Key]>;
511
535
  };
512
536
  type TreeInstanceOpts<Key extends keyof TreeInstance<any>> = {
513
537
  tree: TreeInstance<any>;
@@ -524,7 +548,7 @@ type FeatureImplementation<T = any> = {
524
548
  [key in keyof TreeInstance<T>]?: (opts: TreeInstanceOpts<key>, ...args: Parameters<TreeInstance<T>[key]>) => void;
525
549
  };
526
550
  itemInstance?: {
527
- [key in keyof ItemInstance<T>]?: (opts: ItemInstanceOpts<key>, ...args: Parameters<ItemInstance<T>[key]>) => void;
551
+ [key in keyof ItemInstance<T>]?: (opts: ItemInstanceOpts<T, key>, ...args: Parameters<ItemInstance<T>[key]>) => void;
528
552
  };
529
553
  onTreeMount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
530
554
  onTreeUnmount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
package/dist/index.js CHANGED
@@ -485,6 +485,7 @@ var createTree = (initialConfig) => {
485
485
  );
486
486
  let treeElement;
487
487
  const treeDataRef = { current: {} };
488
+ let rebuildScheduled = false;
488
489
  const itemInstancesMap = {};
489
490
  let itemInstances = [];
490
491
  const itemElementsMap = {};
@@ -528,6 +529,7 @@ var createTree = (initialConfig) => {
528
529
  itemInstances.push(itemInstancesMap[item.itemId]);
529
530
  }
530
531
  }
532
+ rebuildScheduled = false;
531
533
  };
532
534
  const eachFeature = (fn) => {
533
535
  for (const feature of additionalFeatures) {
@@ -542,16 +544,48 @@ var createTree = (initialConfig) => {
542
544
  var _a2;
543
545
  (_a2 = config.setState) == null ? void 0 : _a2.call(config, state);
544
546
  },
547
+ setMounted: ({}, isMounted) => {
548
+ var _a2;
549
+ const ref = treeDataRef.current;
550
+ ref.isMounted = isMounted;
551
+ if (isMounted) {
552
+ (_a2 = ref.waitingForMount) == null ? void 0 : _a2.forEach((cb) => cb());
553
+ ref.waitingForMount = [];
554
+ }
555
+ },
545
556
  applySubStateUpdate: ({}, stateName, updater) => {
546
- state[stateName] = typeof updater === "function" ? updater(state[stateName]) : updater;
547
- const externalStateSetter = config[stateHandlerNames[stateName]];
548
- externalStateSetter == null ? void 0 : externalStateSetter(state[stateName]);
557
+ var _a2;
558
+ const apply = () => {
559
+ state[stateName] = typeof updater === "function" ? updater(state[stateName]) : updater;
560
+ const externalStateSetter = config[stateHandlerNames[stateName]];
561
+ externalStateSetter == null ? void 0 : externalStateSetter(state[stateName]);
562
+ };
563
+ const ref = treeDataRef.current;
564
+ if (ref.isMounted) {
565
+ apply();
566
+ } else {
567
+ (_a2 = ref.waitingForMount) != null ? _a2 : ref.waitingForMount = [];
568
+ ref.waitingForMount.push(apply);
569
+ }
549
570
  },
550
571
  // TODO rebuildSubTree: (itemId: string) => void;
551
572
  rebuildTree: () => {
552
- var _a2;
553
- rebuildItemMeta();
554
- (_a2 = config.setState) == null ? void 0 : _a2.call(config, state);
573
+ var _a2, _b2;
574
+ const ref = treeDataRef.current;
575
+ if (ref.isMounted) {
576
+ rebuildItemMeta();
577
+ (_a2 = config.setState) == null ? void 0 : _a2.call(config, state);
578
+ } else {
579
+ (_b2 = ref.waitingForMount) != null ? _b2 : ref.waitingForMount = [];
580
+ ref.waitingForMount.push(() => {
581
+ var _a3;
582
+ rebuildItemMeta();
583
+ (_a3 = config.setState) == null ? void 0 : _a3.call(config, state);
584
+ });
585
+ }
586
+ },
587
+ scheduleRebuildTree: () => {
588
+ rebuildScheduled = true;
555
589
  },
556
590
  getConfig: () => config,
557
591
  setConfig: (_, updater) => {
@@ -584,7 +618,10 @@ var createTree = (initialConfig) => {
584
618
  }
585
619
  return existingInstance;
586
620
  },
587
- getItems: () => itemInstances,
621
+ getItems: () => {
622
+ if (rebuildScheduled) rebuildItemMeta();
623
+ return itemInstances;
624
+ },
588
625
  registerElement: ({}, element) => {
589
626
  if (treeElement === element) {
590
627
  return;
@@ -817,33 +854,60 @@ var getAllLoadedDescendants = (tree, itemId, includeFolders = false) => {
817
854
  if (!tree.getConfig().isItemFolder(tree.getItemInstance(itemId))) {
818
855
  return [itemId];
819
856
  }
820
- const descendants = tree.retrieveChildrenIds(itemId).map((child) => getAllLoadedDescendants(tree, child, includeFolders)).flat();
857
+ const descendants = tree.retrieveChildrenIds(itemId, true).map((child) => getAllLoadedDescendants(tree, child, includeFolders)).flat();
821
858
  return includeFolders ? [itemId, ...descendants] : descendants;
822
859
  };
860
+ var getAllDescendants = (tree, itemId, includeFolders = false) => __async(null, null, function* () {
861
+ yield tree.loadItemData(itemId);
862
+ if (!tree.getConfig().isItemFolder(tree.getItemInstance(itemId))) {
863
+ return [itemId];
864
+ }
865
+ const childrenIds = yield tree.loadChildrenIds(itemId);
866
+ const descendants = (yield Promise.all(
867
+ childrenIds.map(
868
+ (child) => getAllDescendants(tree, child, includeFolders)
869
+ )
870
+ )).flat();
871
+ return includeFolders ? [itemId, ...descendants] : descendants;
872
+ });
873
+ var withLoadingState = (tree, itemId, callback) => __async(null, null, function* () {
874
+ tree.applySubStateUpdate("loadingCheckPropagationItems", (items) => [
875
+ ...items,
876
+ itemId
877
+ ]);
878
+ try {
879
+ yield callback();
880
+ } finally {
881
+ tree.applySubStateUpdate(
882
+ "loadingCheckPropagationItems",
883
+ (items) => items.filter((id) => id !== itemId)
884
+ );
885
+ }
886
+ });
823
887
  var checkboxesFeature = {
824
888
  key: "checkboxes",
825
889
  overwrites: ["selection"],
826
890
  getInitialState: (initialState) => __spreadValues({
827
- checkedItems: []
891
+ checkedItems: [],
892
+ loadingCheckPropagationItems: []
828
893
  }, initialState),
829
894
  getDefaultConfig: (defaultConfig, tree) => {
830
- var _a, _b, _c;
831
- const hasAsyncLoader = (_a = defaultConfig.features) == null ? void 0 : _a.some(
832
- (f) => f.key === "async-data-loader"
833
- );
834
- if (hasAsyncLoader && defaultConfig.propagateCheckedState) {
835
- throwError(`propagateCheckedState not supported with async trees`);
836
- }
837
- const propagateCheckedState = (_b = defaultConfig.propagateCheckedState) != null ? _b : !hasAsyncLoader;
838
- const canCheckFolders = (_c = defaultConfig.canCheckFolders) != null ? _c : !propagateCheckedState;
895
+ var _a, _b;
896
+ const propagateCheckedState = (_a = defaultConfig.propagateCheckedState) != null ? _a : true;
897
+ const canCheckFolders = (_b = defaultConfig.canCheckFolders) != null ? _b : !propagateCheckedState;
839
898
  return __spreadValues({
840
899
  setCheckedItems: makeStateUpdater("checkedItems", tree),
900
+ setLoadingCheckPropagationItems: makeStateUpdater(
901
+ "loadingCheckPropagationItems",
902
+ tree
903
+ ),
841
904
  propagateCheckedState,
842
905
  canCheckFolders
843
906
  }, defaultConfig);
844
907
  },
845
908
  stateHandlerNames: {
846
- checkedItems: "setCheckedItems"
909
+ checkedItems: "setCheckedItems",
910
+ loadingCheckPropagationItems: "setLoadingCheckPropagationItems"
847
911
  },
848
912
  treeInstance: {
849
913
  setCheckedItems: ({ tree }, checkedItems) => {
@@ -863,13 +927,13 @@ var checkboxesFeature = {
863
927
  }
864
928
  };
865
929
  },
866
- toggleCheckedState: ({ item }) => {
930
+ toggleCheckedState: (_0) => __async(null, [_0], function* ({ item }) {
867
931
  if (item.getCheckedState() === "checked" /* Checked */) {
868
- item.setUnchecked();
932
+ yield item.setUnchecked();
869
933
  } else {
870
- item.setChecked();
934
+ yield item.setChecked();
871
935
  }
872
- },
936
+ }),
873
937
  getCheckedState: ({ item, tree }) => {
874
938
  const { checkedItems } = tree.getState();
875
939
  const { propagateCheckedState } = tree.getConfig();
@@ -879,6 +943,7 @@ var checkboxesFeature = {
879
943
  }
880
944
  if (item.isFolder() && propagateCheckedState) {
881
945
  const descendants = getAllLoadedDescendants(tree, itemId);
946
+ if (descendants.length === 0) return "unchecked" /* Unchecked */;
882
947
  if (descendants.every((d) => checkedItems.includes(d))) {
883
948
  return "checked" /* Checked */;
884
949
  }
@@ -888,36 +953,48 @@ var checkboxesFeature = {
888
953
  }
889
954
  return "unchecked" /* Unchecked */;
890
955
  },
891
- setChecked: ({ item, tree, itemId }) => {
892
- const { propagateCheckedState, canCheckFolders } = tree.getConfig();
893
- if (item.isFolder() && propagateCheckedState) {
894
- tree.applySubStateUpdate("checkedItems", (items) => [
895
- ...items,
896
- ...getAllLoadedDescendants(tree, itemId, canCheckFolders)
897
- ]);
898
- } else if (!item.isFolder() || canCheckFolders) {
899
- tree.applySubStateUpdate("checkedItems", (items) => [...items, itemId]);
900
- }
901
- },
902
- setUnchecked: ({ item, tree, itemId }) => {
903
- const { propagateCheckedState, canCheckFolders } = tree.getConfig();
904
- if (item.isFolder() && propagateCheckedState) {
905
- const descendants = getAllLoadedDescendants(
906
- tree,
907
- itemId,
908
- canCheckFolders
909
- );
910
- tree.applySubStateUpdate(
911
- "checkedItems",
912
- (items) => items.filter((id) => !descendants.includes(id) && id !== itemId)
913
- );
914
- } else {
915
- tree.applySubStateUpdate(
916
- "checkedItems",
917
- (items) => items.filter((id) => id !== itemId)
918
- );
919
- }
920
- }
956
+ setChecked: (_0) => __async(null, [_0], function* ({ item, tree, itemId }) {
957
+ yield withLoadingState(tree, itemId, () => __async(null, null, function* () {
958
+ const { propagateCheckedState, canCheckFolders } = tree.getConfig();
959
+ if (item.isFolder() && propagateCheckedState) {
960
+ const descendants = yield getAllDescendants(
961
+ tree,
962
+ itemId,
963
+ canCheckFolders
964
+ );
965
+ tree.applySubStateUpdate("checkedItems", (items) => [
966
+ ...items,
967
+ ...descendants
968
+ ]);
969
+ } else if (!item.isFolder() || canCheckFolders) {
970
+ tree.applySubStateUpdate("checkedItems", (items) => [
971
+ ...items,
972
+ itemId
973
+ ]);
974
+ }
975
+ }));
976
+ }),
977
+ setUnchecked: (_0) => __async(null, [_0], function* ({ item, tree, itemId }) {
978
+ yield withLoadingState(tree, itemId, () => __async(null, null, function* () {
979
+ const { propagateCheckedState, canCheckFolders } = tree.getConfig();
980
+ if (item.isFolder() && propagateCheckedState) {
981
+ const descendants = yield getAllDescendants(
982
+ tree,
983
+ itemId,
984
+ canCheckFolders
985
+ );
986
+ tree.applySubStateUpdate(
987
+ "checkedItems",
988
+ (items) => items.filter((id) => !descendants.includes(id) && id !== itemId)
989
+ );
990
+ } else {
991
+ tree.applySubStateUpdate(
992
+ "checkedItems",
993
+ (items) => items.filter((id) => id !== itemId)
994
+ );
995
+ }
996
+ }));
997
+ })
921
998
  }
922
999
  };
923
1000
 
@@ -929,7 +1006,8 @@ var specialKeys = {
929
1006
  plus: /^(NumpadAdd|Plus)$/,
930
1007
  minus: /^(NumpadSubtract|Minus)$/,
931
1008
  control: /^(ControlLeft|ControlRight)$/,
932
- shift: /^(ShiftLeft|ShiftRight)$/
1009
+ shift: /^(ShiftLeft|ShiftRight)$/,
1010
+ metaorcontrol: /^(MetaLeft|MetaRight|ControlLeft|ControlRight)$/
933
1011
  };
934
1012
  var testHotkeyMatch = (pressedKeys, tree, hotkey) => {
935
1013
  const supposedKeys = hotkey.hotkey.toLowerCase().split("+");
@@ -1034,6 +1112,12 @@ var loadItemData = (tree, itemId) => __async(null, null, function* () {
1034
1112
  var _a;
1035
1113
  const config = tree.getConfig();
1036
1114
  const dataRef = getDataRef(tree);
1115
+ if (!dataRef.current.itemData[itemId]) {
1116
+ tree.applySubStateUpdate("loadingItemData", (loadingItemData) => [
1117
+ ...loadingItemData,
1118
+ itemId
1119
+ ]);
1120
+ }
1037
1121
  const item = yield config.dataLoader.getItem(itemId);
1038
1122
  dataRef.current.itemData[itemId] = item;
1039
1123
  (_a = config.onLoadedItem) == null ? void 0 : _a.call(config, itemId, item);
@@ -1048,6 +1132,12 @@ var loadChildrenIds = (tree, itemId) => __async(null, null, function* () {
1048
1132
  const config = tree.getConfig();
1049
1133
  const dataRef = getDataRef(tree);
1050
1134
  let childrenIds;
1135
+ if (!dataRef.current.childrenIds[itemId]) {
1136
+ tree.applySubStateUpdate("loadingItemChildrens", (loadingItemChildrens) => [
1137
+ ...loadingItemChildrens,
1138
+ itemId
1139
+ ]);
1140
+ }
1051
1141
  if ("getChildrenWithData" in config.dataLoader) {
1052
1142
  const children = yield config.dataLoader.getChildrenWithData(itemId);
1053
1143
  childrenIds = children.map((c) => c.id);
@@ -1108,11 +1198,7 @@ var asyncDataLoaderFeature = {
1108
1198
  return dataRef.current.itemData[itemId];
1109
1199
  }
1110
1200
  if (!tree.getState().loadingItemData.includes(itemId) && !skipFetch) {
1111
- tree.applySubStateUpdate("loadingItemData", (loadingItemData) => [
1112
- ...loadingItemData,
1113
- itemId
1114
- ]);
1115
- loadItemData(tree, itemId);
1201
+ setTimeout(() => loadItemData(tree, itemId));
1116
1202
  }
1117
1203
  return (_b = (_a = config.createLoadingItemData) == null ? void 0 : _a.call(config)) != null ? _b : null;
1118
1204
  },
@@ -1124,11 +1210,7 @@ var asyncDataLoaderFeature = {
1124
1210
  if (tree.getState().loadingItemChildrens.includes(itemId) || skipFetch) {
1125
1211
  return [];
1126
1212
  }
1127
- tree.applySubStateUpdate(
1128
- "loadingItemChildrens",
1129
- (loadingItemChildrens) => [...loadingItemChildrens, itemId]
1130
- );
1131
- loadChildrenIds(tree, itemId);
1213
+ setTimeout(() => loadChildrenIds(tree, itemId));
1132
1214
  return [];
1133
1215
  }
1134
1216
  },
@@ -1138,10 +1220,6 @@ var asyncDataLoaderFeature = {
1138
1220
  var _a;
1139
1221
  if (!optimistic) {
1140
1222
  (_a = getDataRef(tree).current.itemData) == null ? true : delete _a[itemId];
1141
- tree.applySubStateUpdate("loadingItemData", (loadingItemData) => [
1142
- ...loadingItemData,
1143
- itemId
1144
- ]);
1145
1223
  }
1146
1224
  yield loadItemData(tree, itemId);
1147
1225
  }),
@@ -1149,10 +1227,6 @@ var asyncDataLoaderFeature = {
1149
1227
  var _a;
1150
1228
  if (!optimistic) {
1151
1229
  (_a = getDataRef(tree).current.childrenIds) == null ? true : delete _a[itemId];
1152
- tree.applySubStateUpdate(
1153
- "loadingItemChildrens",
1154
- (loadingItemChildrens) => [...loadingItemChildrens, itemId]
1155
- );
1156
1230
  }
1157
1231
  yield loadChildrenIds(tree, itemId);
1158
1232
  }),
@@ -1604,6 +1678,10 @@ var dragAndDropFeature = {
1604
1678
  const target = tree.getDragTarget();
1605
1679
  return target ? target.item.getId() === item.getId() : false;
1606
1680
  },
1681
+ isUnorderedDragTarget: ({ tree, item }) => {
1682
+ const target = tree.getDragTarget();
1683
+ return target ? !isOrderedDragTarget(target) && target.item.getId() === item.getId() : false;
1684
+ },
1607
1685
  isDragTargetAbove: ({ tree, item }) => {
1608
1686
  const target = tree.getDragTarget();
1609
1687
  if (!target || !isOrderedDragTarget(target) || target.item !== item.getParent())