Skip to content

Commit 168311e

Browse files
reidbarbersnowystingerLFDanLu
authored
Fix focus behavior after dropping ListView item (#3369)
* Fix focus after dropping item * add tests * add drag utility * fix touch event in drag function * fix test * update mouse drag tests * rename drag utility * test fixes * more test fixes * fix some tests * update dragAndDrop utility * fix more tests * fix more tests * revert dragAndDrop utility add * lint * lint * lint * update todos * fix tests * fix 16 and 17 tests Co-authored-by: Rob Snow <[email protected]> Co-authored-by: Daniel Lu <[email protected]>
1 parent 92294d1 commit 168311e

File tree

3 files changed

+461
-7
lines changed

3 files changed

+461
-7
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import {announce} from '@react-aria/live-announcer';
1414
import {ariaHideOutside} from '@react-aria/overlays';
1515
import {DragEndEvent, DragItem, DropActivateEvent, DropEnterEvent, DropEvent, DropExitEvent, DropItem, DropOperation, DropTarget as DroppableCollectionTarget, FocusableElement} from '@react-types/shared';
16+
import {flushSync} from 'react-dom';
1617
import {getDragModality, getTypes} from './utils';
1718
import {getInteractionModality} from '@react-aria/interactions';
1819
import type {LocalizedStringFormatter} from '@internationalized/string';
@@ -494,7 +495,16 @@ class DragSession {
494495

495496
// Blur and re-focus the drop target so that the focus ring appears.
496497
if (this.currentDropTarget) {
497-
this.currentDropTarget.element.blur();
498+
// Since we cancel all focus events in drag sessions, refire blur to make sure state gets updated so drag target doesn't think it's still focused
499+
// i.e. When you from one list to another during a drag session, we need the blur to fire on the first list after the drag.
500+
if (!this.dragTarget.element.contains(this.currentDropTarget.element)) {
501+
this.dragTarget.element.dispatchEvent(new FocusEvent('blur'));
502+
this.dragTarget.element.dispatchEvent(new FocusEvent('focusout', {bubbles: true}));
503+
}
504+
// Re-focus the focusedKey upon reorder. This requires a React rerender between blurring and focusing.
505+
flushSync(() => {
506+
this.currentDropTarget.element.blur();
507+
});
498508
this.currentDropTarget.element.focus();
499509
}
500510

packages/@react-spectrum/list/stories/ListView.stories.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,10 @@ export function DragIntoItemExample(props) {
852852
}
853853

854854
export function DragBetweenListsExample(props) {
855-
let onDropAction = action('onDrop');
855+
let {onDragStart, onDragEnd, onDrop} = props;
856+
onDrop = chain(action('onDrop'), onDrop);
857+
onDragStart = chain(action('dragStart'), onDragStart);
858+
onDragEnd = chain(action('dragEnd'), onDragEnd);
856859

857860
let list1 = useListData({
858861
initialItems: props.items1 || itemList1
@@ -898,8 +901,8 @@ export function DragBetweenListsExample(props) {
898901
getAllowedDropOperationsAction();
899902
return ['move', 'cancel'];
900903
},
901-
onDragStart: action('dragStart'),
902-
onDragEnd: action('dragEnd')
904+
onDragStart,
905+
onDragEnd
903906
});
904907

905908
// Use a random drag type so the items can only be reordered within the two lists and not dragged elsewhere.
@@ -923,7 +926,7 @@ export function DragBetweenListsExample(props) {
923926
}
924927
}
925928
}
926-
onDropAction(e);
929+
onDrop(e);
927930
onMove(keys, e.target);
928931
}
929932
},

0 commit comments

Comments
 (0)