@headless-tree/core 1.3.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,34 @@
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
+
20
+ ## 1.4.0
21
+
22
+ ### Minor Changes
23
+
24
+ - 7ef4864: added feature where closed items are auto-expanded briefly after dragging onto them. set config option `openOnDropDelay` to zero to disable.
25
+
26
+ ### Patch Changes
27
+
28
+ - 8d53b4f: fixed a bug where external changes to focused or selected items don't trigger a rerender (#150)
29
+ - 1cee368: fixed a bug where the drag line is not cleared after drop (#149)
30
+ - 1e833bb: drag-and-drop feature is no longer dependent on selection feature, and fill default to focused item if selection feature is missing (#143)
31
+
3
32
  ## 1.3.0
4
33
 
5
34
  ### Minor Changes
package/dist/index.d.mts CHANGED
@@ -2,6 +2,7 @@ interface DndDataRef {
2
2
  lastDragCode?: string;
3
3
  lastAllowDrop?: boolean;
4
4
  lastDragEnter?: number;
5
+ autoExpandTimeout?: any;
5
6
  windowDragEndListener?: () => void;
6
7
  }
7
8
  interface DndState<T> {
@@ -65,6 +66,8 @@ type DragAndDropFeatureDef<T> = {
65
66
  onDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => void | Promise<void>;
66
67
  onDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => void | Promise<void>;
67
68
  onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
69
+ /** When dragging for this many ms on a closed folder, the folder will automatically open. Set to zero to disable. */
70
+ openOnDropDelay?: number;
68
71
  };
69
72
  treeInstance: {
70
73
  getDragTarget: () => DragTarget<T> | null;
@@ -72,7 +75,12 @@ type DragAndDropFeatureDef<T> = {
72
75
  getDragLineStyle: (topOffset?: number, leftOffset?: number) => Record<string, any>;
73
76
  };
74
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. */
75
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;
76
84
  isDragTargetAbove: () => boolean;
77
85
  isDragTargetBelow: () => boolean;
78
86
  isDraggingOver: () => boolean;
@@ -174,6 +182,10 @@ type MainFeatureDef<T = any> = {
174
182
  };
175
183
  getHotkeyPresets: () => HotkeysConfig<T>;
176
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;
177
189
  };
178
190
  itemInstance: {
179
191
  registerElement: (element: HTMLElement | null) => void;
@@ -256,7 +268,12 @@ type SyncDataLoaderFeatureDef<T> = {
256
268
  };
257
269
  treeInstance: {
258
270
  retrieveItemData: (itemId: string) => T;
259
- 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[];
260
277
  };
261
278
  itemInstance: {
262
279
  isLoading: () => boolean;
@@ -304,7 +321,8 @@ type AsyncDataLoaderFeatureDef<T> = {
304
321
  * @param optimistic If true, the item will not trigger a state update on `loadingItemChildrens`, and
305
322
  * the tree will continue to display the old data until the new data has loaded. */
306
323
  invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
307
- 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;
308
326
  updateCachedChildrenIds: (childrenIds: string[]) => void;
309
327
  isLoading: () => boolean;
310
328
  };
@@ -440,9 +458,11 @@ declare enum CheckedState {
440
458
  type CheckboxesFeatureDef<T> = {
441
459
  state: {
442
460
  checkedItems: string[];
461
+ loadingCheckPropagationItems: string[];
443
462
  };
444
463
  config: {
445
464
  setCheckedItems?: SetStateFn<string[]>;
465
+ setLoadingCheckPropagationItems?: SetStateFn<string[]>;
446
466
  canCheckFolders?: boolean;
447
467
  propagateCheckedState?: boolean;
448
468
  };
@@ -450,11 +470,18 @@ type CheckboxesFeatureDef<T> = {
450
470
  setCheckedItems: (checkedItems: string[]) => void;
451
471
  };
452
472
  itemInstance: {
453
- setChecked: () => void;
454
- setUnchecked: () => void;
455
- 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>;
456
482
  getCheckedState: () => CheckedState;
457
483
  getCheckboxProps: () => Record<string, any>;
484
+ isLoadingCheckPropagation: () => boolean;
458
485
  };
459
486
  hotkeys: never;
460
487
  };
@@ -500,11 +527,11 @@ type HotkeyName = MergedFeatures<RegisteredFeatures<any>>["hotkeys"];
500
527
  type HotkeysConfig<T> = Record<HotkeyName, HotkeyConfig<T>>;
501
528
  type CustomHotkeysConfig<T> = Partial<Record<HotkeyName | `custom${string}`, Partial<HotkeyConfig<T>>>>;
502
529
  type MayReturnNull<T extends (...x: any[]) => any> = (...args: Parameters<T>) => ReturnType<T> | null;
503
- type ItemInstanceOpts<Key extends keyof ItemInstance<any>> = {
504
- item: ItemInstance<any>;
505
- tree: TreeInstance<any>;
530
+ type ItemInstanceOpts<T, Key extends keyof ItemInstance<any>> = {
531
+ item: ItemInstance<T>;
532
+ tree: TreeInstance<T>;
506
533
  itemId: string;
507
- prev?: MayReturnNull<ItemInstance<any>[Key]>;
534
+ prev?: MayReturnNull<ItemInstance<T>[Key]>;
508
535
  };
509
536
  type TreeInstanceOpts<Key extends keyof TreeInstance<any>> = {
510
537
  tree: TreeInstance<any>;
@@ -521,7 +548,7 @@ type FeatureImplementation<T = any> = {
521
548
  [key in keyof TreeInstance<T>]?: (opts: TreeInstanceOpts<key>, ...args: Parameters<TreeInstance<T>[key]>) => void;
522
549
  };
523
550
  itemInstance?: {
524
- [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;
525
552
  };
526
553
  onTreeMount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
527
554
  onTreeUnmount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ interface DndDataRef {
2
2
  lastDragCode?: string;
3
3
  lastAllowDrop?: boolean;
4
4
  lastDragEnter?: number;
5
+ autoExpandTimeout?: any;
5
6
  windowDragEndListener?: () => void;
6
7
  }
7
8
  interface DndState<T> {
@@ -65,6 +66,8 @@ type DragAndDropFeatureDef<T> = {
65
66
  onDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => void | Promise<void>;
66
67
  onDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => void | Promise<void>;
67
68
  onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
69
+ /** When dragging for this many ms on a closed folder, the folder will automatically open. Set to zero to disable. */
70
+ openOnDropDelay?: number;
68
71
  };
69
72
  treeInstance: {
70
73
  getDragTarget: () => DragTarget<T> | null;
@@ -72,7 +75,12 @@ type DragAndDropFeatureDef<T> = {
72
75
  getDragLineStyle: (topOffset?: number, leftOffset?: number) => Record<string, any>;
73
76
  };
74
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. */
75
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;
76
84
  isDragTargetAbove: () => boolean;
77
85
  isDragTargetBelow: () => boolean;
78
86
  isDraggingOver: () => boolean;
@@ -174,6 +182,10 @@ type MainFeatureDef<T = any> = {
174
182
  };
175
183
  getHotkeyPresets: () => HotkeysConfig<T>;
176
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;
177
189
  };
178
190
  itemInstance: {
179
191
  registerElement: (element: HTMLElement | null) => void;
@@ -256,7 +268,12 @@ type SyncDataLoaderFeatureDef<T> = {
256
268
  };
257
269
  treeInstance: {
258
270
  retrieveItemData: (itemId: string) => T;
259
- 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[];
260
277
  };
261
278
  itemInstance: {
262
279
  isLoading: () => boolean;
@@ -304,7 +321,8 @@ type AsyncDataLoaderFeatureDef<T> = {
304
321
  * @param optimistic If true, the item will not trigger a state update on `loadingItemChildrens`, and
305
322
  * the tree will continue to display the old data until the new data has loaded. */
306
323
  invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
307
- 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;
308
326
  updateCachedChildrenIds: (childrenIds: string[]) => void;
309
327
  isLoading: () => boolean;
310
328
  };
@@ -440,9 +458,11 @@ declare enum CheckedState {
440
458
  type CheckboxesFeatureDef<T> = {
441
459
  state: {
442
460
  checkedItems: string[];
461
+ loadingCheckPropagationItems: string[];
443
462
  };
444
463
  config: {
445
464
  setCheckedItems?: SetStateFn<string[]>;
465
+ setLoadingCheckPropagationItems?: SetStateFn<string[]>;
446
466
  canCheckFolders?: boolean;
447
467
  propagateCheckedState?: boolean;
448
468
  };
@@ -450,11 +470,18 @@ type CheckboxesFeatureDef<T> = {
450
470
  setCheckedItems: (checkedItems: string[]) => void;
451
471
  };
452
472
  itemInstance: {
453
- setChecked: () => void;
454
- setUnchecked: () => void;
455
- 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>;
456
482
  getCheckedState: () => CheckedState;
457
483
  getCheckboxProps: () => Record<string, any>;
484
+ isLoadingCheckPropagation: () => boolean;
458
485
  };
459
486
  hotkeys: never;
460
487
  };
@@ -500,11 +527,11 @@ type HotkeyName = MergedFeatures<RegisteredFeatures<any>>["hotkeys"];
500
527
  type HotkeysConfig<T> = Record<HotkeyName, HotkeyConfig<T>>;
501
528
  type CustomHotkeysConfig<T> = Partial<Record<HotkeyName | `custom${string}`, Partial<HotkeyConfig<T>>>>;
502
529
  type MayReturnNull<T extends (...x: any[]) => any> = (...args: Parameters<T>) => ReturnType<T> | null;
503
- type ItemInstanceOpts<Key extends keyof ItemInstance<any>> = {
504
- item: ItemInstance<any>;
505
- tree: TreeInstance<any>;
530
+ type ItemInstanceOpts<T, Key extends keyof ItemInstance<any>> = {
531
+ item: ItemInstance<T>;
532
+ tree: TreeInstance<T>;
506
533
  itemId: string;
507
- prev?: MayReturnNull<ItemInstance<any>[Key]>;
534
+ prev?: MayReturnNull<ItemInstance<T>[Key]>;
508
535
  };
509
536
  type TreeInstanceOpts<Key extends keyof TreeInstance<any>> = {
510
537
  tree: TreeInstance<any>;
@@ -521,7 +548,7 @@ type FeatureImplementation<T = any> = {
521
548
  [key in keyof TreeInstance<T>]?: (opts: TreeInstanceOpts<key>, ...args: Parameters<TreeInstance<T>[key]>) => void;
522
549
  };
523
550
  itemInstance?: {
524
- [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;
525
552
  };
526
553
  onTreeMount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;
527
554
  onTreeUnmount?: (instance: TreeInstance<T>, treeElement: HTMLElement) => void;