react-beautiful-dnd
Version:
Beautiful, accessible drag and drop for lists with React.js
93 lines (82 loc) • 2.63 kB
JavaScript
// @flow
import invariant from 'tiny-invariant';
import { prepare, completeDrop, initialPublish } from '../action-creators';
import type { DimensionMarshal } from '../dimension-marshal/dimension-marshal-types';
import type { State, ScrollOptions, LiftRequest } from '../../types';
import type { MiddlewareStore, Action, Dispatch } from '../store-types';
export default (getMarshal: () => DimensionMarshal) => {
let timeoutId: ?TimeoutID = null;
const tryAbortCriticalCollection = () => {
if (timeoutId == null) {
return;
}
clearTimeout(timeoutId);
timeoutId = null;
};
return ({ getState, dispatch }: MiddlewareStore) => (next: Dispatch) => (
action: Action,
): any => {
// a lift might be cancelled before we enter phase 2
if (action.type === 'CLEAN') {
tryAbortCriticalCollection();
next(action);
return;
}
if (action.type !== 'LIFT') {
next(action);
return;
}
invariant(
!timeoutId,
'There should not be a pending complete lift phase when a lift action is fired',
);
const marshal: DimensionMarshal = getMarshal();
const { id, client, autoScrollMode, viewport } = action.payload;
const initial: State = getState();
// flush dropping animation if needed
// this can change the descriptor of the dragging item
// Will call the onDragEnd hooks
if (initial.phase === 'DROP_ANIMATING') {
dispatch(completeDrop(initial.pending.result));
}
const postFlushState: State = getState();
invariant(
postFlushState.phase === 'IDLE',
'Incorrect phase to start a drag',
);
// Flush required for react-motion
dispatch(prepare());
timeoutId = setTimeout(() => {
timeoutId = null;
// Phase 2: collect initial dimensions
const state: State = getState();
invariant(
state.phase === 'PREPARING',
'Invalid phase for completing lift',
);
// will communicate with the marshal to start requesting dimensions
const scrollOptions: ScrollOptions = {
shouldPublishImmediately: autoScrollMode === 'JUMP',
};
const request: LiftRequest = {
draggableId: id,
scrollOptions,
};
// Let's get the marshal started!
const { critical, dimensions } = marshal.startPublishing(
request,
viewport.scroll.current,
);
// Okay, we are good to start dragging now
dispatch(
initialPublish({
critical,
dimensions,
client,
autoScrollMode,
viewport,
}),
);
});
};
};