Skip to content

Commit 473c611

Browse files
reidbarberdevongovettLFDanLu
authored
fix(RAC): Tree DnD followup + docs (#8302)
* storybook: fix drop indicator style outside of iframe * storybook: fix children not moving in drag * storybook: allow dragging in second tree * update getDropTargetFromPoint to handle ambiguous drop position: 'after last child' or 'after parent' * fix serializeItem to handle empty children * add `position: relative` to the drop indicator row to fix scrolling it into view * add aria-expanded to TreeDropIndicator row * fix drop indicator missing level style * add docs * fix types * remove aria-expanded from insertion indicator * docs types fixes * If dropping "after" an expanded item with children, change target to be "before" its first actual child item. * init TreeDropTargetDelegate * lint * add comment * handle currentItem?.nextKey != null * add TreeDropTargetDelegate to exports and DropHooks * fixes and cleanup * cleanup * fix indention in docs examples * fix duplicate key dropping * fix directory example * up X_SWITCH_THRESHOLD to 10 * add recursive rendering to docs examples * fix dup keys in DroppableTree * Add indentation to drop indicator * Improve docs examples * Fix insertion indicator indentation when checkboxes and drag buttons are not present * shorten duplicate item data in examples * docs types * fix dropping before first expanded parent * add isValidDropTarget checks * handle reorder 'after' expanded parent should not be a target * Allow dropping after dragged key, but not after one of its children * Reorder examples * feat: Ensure that getKeys filters out selected child keys if parent key is selected (#8337) * Fix tree docs example by accounting for child keys that are included in a selected parent * update getKeys to automatically filter out child keys if parent key is also selected * fix infinite loop and add test * add serializeItem to other examples so children get unique ids * docs: increase indention between levels * default to root drop target if there are no potential targets * allowsDragging should be false if dragging disabled * add unit tests * Update packages/react-aria-components/docs/Tree.mdx Co-authored-by: Devon Govett <[email protected]> * optimize getKeys to be linear --------- Co-authored-by: Devon Govett <[email protected]> Co-authored-by: Daniel Lu <[email protected]>
1 parent 21d1950 commit 473c611

File tree

9 files changed

+1741
-65
lines changed

9 files changed

+1741
-65
lines changed

packages/@react-aria/dnd/src/ListDropTargetDelegate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class ListDropTargetDelegate implements DropTargetDelegate {
3333
private ref: RefObject<HTMLElement | null>;
3434
private layout: 'stack' | 'grid';
3535
private orientation: Orientation;
36-
private direction: Direction;
36+
protected direction: Direction;
3737

3838
constructor(collection: Iterable<Node<unknown>>, ref: RefObject<HTMLElement | null>, options?: ListDropTargetDelegateOptions) {
3939
this.collection = collection;

packages/@react-stately/dnd/src/useDraggableCollectionState.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,35 @@ export function useDraggableCollectionState(props: DraggableCollectionStateOptio
7272
let draggedKey = useRef<Key | null>(null);
7373
let getKeys = (key: Key) => {
7474
// The clicked item is always added to the drag. If it is selected, then all of the
75-
// other selected items are also dragged. If it is not selected, the only the clicked
75+
// other selected items are also dragged. If it is not selected, then only the clicked
7676
// item is dragged. This matches native macOS behavior.
77-
let keys = new Set(
78-
selectionManager.isSelected(key)
79-
? new Set([...selectionManager.selectedKeys].filter(key => !!collection.getItem(key)))
80-
: []
81-
);
77+
// Additionally, we filter out any keys that are children of any of the other selected keys
78+
let keys = new Set<Key>();
79+
if (selectionManager.isSelected(key)) {
80+
for (let currentKey of selectionManager.selectedKeys) {
81+
let node = collection.getItem(currentKey);
82+
if (node) {
83+
let isChild = false;
84+
let parentKey = node.parentKey;
85+
while (parentKey != null) {
86+
// eslint-disable-next-line max-depth
87+
if (selectionManager.selectedKeys.has(parentKey)) {
88+
isChild = true;
89+
break;
90+
}
91+
let parentNode = collection.getItem(parentKey);
92+
parentKey = parentNode ? parentNode.parentKey : null;
93+
}
94+
95+
if (!isChild) {
96+
keys.add(currentKey);
97+
}
98+
}
99+
}
100+
} else {
101+
keys.add(key);
102+
}
82103

83-
keys.add(key);
84104
return keys;
85105
};
86106

packages/@react-stately/dnd/src/useDroppableCollectionState.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,14 @@ export function useDroppableCollectionState(props: DroppableCollectionStateOptio
7272

7373
let getOppositeTarget = (target: ItemDropTarget): ItemDropTarget | null => {
7474
if (target.dropPosition === 'before') {
75-
let key = collection.getKeyBefore(target.key);
76-
return key != null && collection.getItem(key)?.level === collection.getItem(target.key)?.level
77-
? {type: 'item', key, dropPosition: 'after'}
75+
let node = collection.getItem(target.key);
76+
return node && node.prevKey != null
77+
? {type: 'item', key: node.prevKey, dropPosition: 'after'}
7878
: null;
7979
} else if (target.dropPosition === 'after') {
80-
let key = collection.getKeyAfter(target.key);
81-
return key != null && collection.getItem(key)?.level === collection.getItem(target.key)?.level
82-
? {type: 'item', key, dropPosition: 'before'}
80+
let node = collection.getItem(target.key);
81+
return node && node.nextKey != null
82+
? {type: 'item', key: node.nextKey, dropPosition: 'before'}
8383
: null;
8484
}
8585
return null;

0 commit comments

Comments
 (0)