react-spectrum
2851cbd1 - Adding utility handlers to DnD hooks to simplify implementation experience (#3266)

Commit
3 years ago
Adding utility handlers to DnD hooks to simplify implementation experience (#3266) * initial brain storming * adding assumptions, updating stories, fixing bugs * add useDraggable and useDroppable, document other bugs * compiling feedback and tentative implementation some meeting feedback * switching to single hook strategy * cleaning up some testing code * adding dropOperation to onInsert,onRootDrop, etc * experiementation with tracking draggedCollection and droppedCollection * debugging and musings * porting onReorder and other helper functions to the aria dnd hooks * fixing circular dep and adding another story with onDrop/getDropOperation override * debug tests, fixes, and some additional musings * storing dom node as drop target if dropping on non-collection drop target * fixing lint * cleanup * fixing case where getDropOperation is provided but onDrop isnt * fix case where onDrop is defined but getDropOperation isnt * updating ListView getDropTargetFromPoint so it uses dropState.getDropOperation * tentative defaultGetDropTargetFromPoint outline * Revert "tentative defaultGetDropTargetFromPoint outline" This reverts commit faae38bf3487f887edbd723c71f8ae6af7c5a4c6. * Revert "updating ListView getDropTargetFromPoint so it uses dropState.getDropOperation" This reverts commit 0f8c96be1bbdec497fef989a8007ddf780271b2f. * passing items directly to handlers * tracking currently dragged keys in global state allows us to simplify onReorder and prevent folders from being dragged into themselves automatically * making util handlers more consistent with other drop handlers * tracking dragging/dropping collection refs instead of collections collections could potentially change during a drag operation, breaking isInternalDrop collection comparison checks. Switch to using the drag/drop collection refs for isInternalDrop checks. Add tracker for currentDropCollectionRef so for getDropOperation logic * adding isInternalDrop info to onItemDrop for users who will handle updating both drag source and drop collection in the onItemDrop handler (aka onDrop) * adding onRemove util function * handle onInsert copy operation if the user performs a internal drop but it is a copy operation then we need to not perform a reorder but instead perform a onInsert. * restoring delayed onDrop behavior in useDrop retools the global dnd state tracking logic to conform with the following event flow: dragstart -> drop (onDrop not yet called) -> dragend (including onDragEnd) -> onDrop (delayed via setTimeout in useDrop. Alternative to these changes is to add a setTimeout to the option.onDragEnd call in onDrag * fixing tests to match delayed onDrop * removing useDragHooks and useDropHooks * fixing lint * clean up types and provide more info to isValidDropTarget removed some props that werent being used in various hooks to avoid confusion for the end user. Provided types and target to isValidDropTarget so the user can choose to omit folders from being valid drop targets if the dragged items include invalid file types or stuff * delaying onDragEnd handler so it always happens after onDrop iOS Safari was firing the setTimeout onDrop before onDragEnd unlike every other browser so I am delaying onDragEnd handler to enforce consistency. Global DnD state now is cleared after onDragEnd and in drag start (in case a drop is done via a non RSP draggable item where there wont be a onDragEnd). Global DnD state isnt cleared in onDrop because we need the drop target + drop collection info for drag end onRemove handling * add workaround for Chrome Android bug Chrome android always returns "none" for its drop effect in dragend so we track the drop effect in the global DnD state as a fallback * progress on tests and fixing endDrag fixed a bug where endDrag didnt properly call onRemove if onDragEnd wasnt defined * adding tests for the global DnD state tracker * allowing user to perform onInsert in the same list if it is a copy operation if the user doesnt have onReorder provided, this will allow the user to hold Option to change the drop operation to copy and thus get access to the drop indicators between the rows. Without holding Option, the drop operation will be move and thus the inbetween row drop targets will no longer be valid because onReorder isnt provided * fixing some review comments and bugs * adjusting defaultDrop's dep array so it works with handler updates during drag if a handler changes during a drag session it can break the experience so we grab our handlers via the localState ref instead of from props directly * fix getDropTargetFromPoint so that it accounts for root drop cases previously getDropTargetFromPoint would only consider drops on, before, or after a item. However, this meant that a collection that allowed before/after drops along with root drops would never return a root drop target since getDropTargetFromPoint would always return the before/after drop target * clearing global DnD state in onDrop if drag item isnt a RSP dnd item e.g. drag a file from finder/file explorer into a droppable RSP collection. In that case ondragend isnt handled by us so we can go ahead and clear the global DnD state in onDrop * revert getDropTargetFromPoint changes * fixing tests and adjusting type isValidDropTarget as a part of the util handlers is only for onItemDrop filtering since I figure the user wont really have cause to filter out an insert drop or a root drop since they can just omit the handlers for those cases * adding filed bug * making internal copy drop insert operations a no op previously we had internal copy drop insert operations handled by onInsert. From feedback, this was deemed too complicated since onInsert now handles external and internal drop operations so now onInsert only handles external drops * move global dnd state to aria/dnd and update getDropOperation we didnt want to export the global dnd state from stately and expose it externally, so moved it to aria/dnd instead. Changes were made to getDropOperations and onDragEnd in the dnd collection state hooks so that we provide isInternalDrop and dragging keys via args instead of state instead. getDropOperations now has an object as an arg since we hit 5 different arguments. dropTarget is tentatively dropped from being returned by onDragEnd since it was used mainly to check if it is an internal drop for item removal purposes, but removal should happen in onItemDrop instead since that has isInternalDrop already * removing droppedTarget tracking from global dnd state was previously only used to call onRemove when isInternalDrop was true and the drop target was a folder. Decided that a user would instead handle removing the original items via onItemDrop in cases like those * unifying dropCollectionRef tracker in global DnD state now that we have a single dropCollectionRef tracker, we also only set it when entering a valid drop target. We do that instead of setting it when entering any drop target because we clear this tracker in onDropExit which only fires when leaving a valid drop target, thus making onDragEnd return a invalid isInternalDrop=true when we drop somewhere off the last dragged over collection * clearing dropCollectionRef when drag is canceled via Escape and tests * allowing drops that have invalid and valid drag types this is for a case where a folder only accepts certain file types but the user drops a bunch of valid and invlid files types on it. It should still accept the drop but the invalid drag items should be filtered out by the user (for now, up for discussion). Currently there is a bug where onRemove doesnt know which of the dragged keys were valid drops * removing timeout from onDrop We decided to make the drag and drop event handlers consistent with the order in which they are fired in the browser. To work around the original bug https://bugzilla.mozilla.org/show_bug.cgi?id=460801, we manually call the onDragEnd handler if the dragged element is removed. * adding useDraggableCollection removes need to have parentRef in useDraggableItem. Necessary to track draggingCollectionRef for getDropOperation and onDragEnd * adding more storybook actions and fixing when they are fired a bunch of the other listview stories had the ondrop action after the async stuff in onDrop, giving the false impression that onDrop was fired after onDragEnd * making useDnDHooks return a merged list of hooks makes it easier on the user, now they dont need to juggle dropHooks and dragHooks * forgot to include the story updates * first stab at adding automatic item filtering onDrop * use acceptedDragTypes in default onDrop filtering if provided as per feedback here:https://github.com/adobe/react-spectrum/pull/3266#discussion_r962055900. This means we no longer default acceptedDragTypes to "all" * fixing tests from merge * update prop names to shouldAcceptItemDrop and onItemRemove * fix non draggable ListView * fixing tests in 16 and 17 * fixing merge and tests * allowing internal copy operation via onReorder, revert to old getDropOperations includes other review comments like getting rid of global DnD state clear on dragstart in favor of already existing clears on drag end and onDrop * fixing tests and adding useDraggableCollection to draggable listbox * refactor global dnd state moved dropeffect tracking out of the global dnd state object since it isnt collection specific. Also moved as many instances of the global drag state setters/clears out of useDrag and useDrop into the draggable/droppable specific hooks. Some renaming for consistency * fixing drag between list story * adding tests for default onDrop filtering and directory/file dropping * adding more stories * use shouldAcceptItemDrop to further filter what items are provided to drop handlers * adding tests for shouldAcceptItemDrop drop filtering * fix skipped test * removing onItemRemove from util handlers it is problematic for cases where onDrop has additional filtering on the items it will actually take action on since the items that werent processed shouldnt be removed by onItemRemove but we dont have a good way to communicate that. For now, users can recreate onItemRemove in onDragEnd if they have a simple case * quick fix to detect android talkback click when setting modality isVirtualClick relies on detail=0 as a check for virtual clicks, but click events for Android Talkback have detail=0. Added a quick fix with a buttons=1 check that only works for click events since mousedown event will have buttons=1 for android taps as well. This fixes an issue where DragManagers beginDragging wasnt setting a drag targetfor android talkback, resulting in droppableCollection not being set via onDropEnter in useDroppableCollection, breaking valid drop target filtering for defaultGetDropOperation in useDroppableCollectionState * clean up * fixing test for 17 * improving isVirtualClick detection of Android talkback clicks * fixing lint * removing pointer listener case from android isVirtualClick detection isVirtualClick should only be used for click and mouse event listeners
Author
Parents
Loading