UNPKG

react-beautiful-dnd

Version:

A beautiful, accessible drag and drop library for lists with React.js

104 lines (83 loc) 2.88 kB
// @flow import memoizeOne from 'memoize-one'; import type { Action, Store, State, Hooks, DropResult } from '../types'; const getFireHooks = (hooks: Hooks) => memoizeOne((current: State, previous: State): void => { const { onDragStart, onDragEnd } = hooks; const currentPhase = current.phase; const previousPhase = previous.phase; // Drag start if (currentPhase === 'DRAGGING' && previousPhase !== 'DRAGGING') { // onDragStart is optional if (!onDragStart) { return; } if (!current.drag) { console.error('cannot fire onDragStart hook without drag state', { current, previous }); return; } onDragStart(current.drag.current.id, current.drag.initial.source); return; } // Drag end if (currentPhase === 'DROP_COMPLETE' && previousPhase !== 'DROP_COMPLETE') { if (!current.drop || !current.drop.result) { console.error('cannot fire onDragEnd hook without drag state', { current, previous }); return; } const { source, destination, draggableId } = current.drop.result; if (!destination) { onDragEnd(current.drop.result); return; } // Do not publish a result where nothing moved const didMove: boolean = source.droppableId !== destination.droppableId || source.index !== destination.index; if (didMove) { onDragEnd(current.drop.result); return; } const muted: DropResult = { draggableId, source, destination: null, }; onDragEnd(muted); } // Drag cancelled while dragging if (currentPhase === 'IDLE' && previousPhase === 'DRAGGING') { if (!previous.drag) { console.error('cannot fire onDragEnd for cancel because cannot find previous drag'); return; } const result: DropResult = { draggableId: previous.drag.current.id, source: previous.drag.initial.source, destination: null, }; onDragEnd(result); } // Drag cancelled during a drop animation. Not super sure how this can even happen. // This is being really safe if (currentPhase === 'IDLE' && previousPhase === 'DROP_ANIMATING') { if (!previous.drop || !previous.drop.pending) { console.error('cannot fire onDragEnd for cancel because cannot find previous pending drop'); return; } const result: DropResult = { draggableId: previous.drop.pending.result.draggableId, source: previous.drop.pending.result.source, destination: null, }; onDragEnd(result); } }); export default (hooks: Hooks) => { const fireHooks = getFireHooks(hooks); return (store: Store) => (next: (Action) => mixed) => (action: Action): mixed => { const previous: State = store.getState(); const result: mixed = next(action); const current: State = store.getState(); fireHooks(current, previous); return result; }; };