react-beautiful-dnd
Version:
Beautiful, accessible drag and drop for lists with React.js
536 lines (429 loc) • 14.4 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);
var _defineProperty2 = require('babel-runtime/helpers/defineProperty');
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
var _extends6 = require('babel-runtime/helpers/extends');
var _extends7 = _interopRequireDefault(_extends6);
var _memoizeOne = require('memoize-one');
var _memoizeOne2 = _interopRequireDefault(_memoizeOne);
var _getInitialImpact = require('./get-initial-impact');
var _getInitialImpact2 = _interopRequireDefault(_getInitialImpact);
var _position = require('./position');
var _getDragImpact = require('./get-drag-impact/');
var _getDragImpact2 = _interopRequireDefault(_getDragImpact);
var _moveToNextIndex = require('./move-to-next-index/');
var _moveToNextIndex2 = _interopRequireDefault(_moveToNextIndex);
var _moveCrossAxis = require('./move-cross-axis/');
var _moveCrossAxis2 = _interopRequireDefault(_moveCrossAxis);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var noDimensions = {
request: null,
draggable: {},
droppable: {}
};
var origin = { x: 0, y: 0 };
var clean = (0, _memoizeOne2.default)(function (phase) {
var state = {
phase: phase || 'IDLE',
drag: null,
drop: null,
dimension: noDimensions
};
return state;
});
var move = function move(_ref) {
var state = _ref.state,
clientSelection = _ref.clientSelection,
_ref$shouldAnimate = _ref.shouldAnimate,
shouldAnimate = _ref$shouldAnimate === undefined ? false : _ref$shouldAnimate,
windowScroll = _ref.windowScroll,
impact = _ref.impact;
if (state.phase !== 'DRAGGING') {
console.error('cannot move while not dragging');
return clean();
}
if (state.drag == null) {
console.error('cannot move if there is no drag information');
return clean();
}
var previous = state.drag.current;
var initial = state.drag.initial;
var currentWindowScroll = windowScroll || previous.windowScroll;
var client = function () {
var offset = (0, _position.subtract)(clientSelection, initial.client.selection);
var result = {
offset: offset,
selection: clientSelection,
center: (0, _position.add)(offset, initial.client.center)
};
return result;
}();
var page = {
selection: (0, _position.add)(client.selection, currentWindowScroll),
offset: (0, _position.add)(client.offset, currentWindowScroll),
center: (0, _position.add)(client.center, currentWindowScroll)
};
var current = {
id: previous.id,
type: previous.type,
isScrollAllowed: previous.isScrollAllowed,
client: client,
page: page,
shouldAnimate: shouldAnimate,
windowScroll: currentWindowScroll
};
var previousDroppableOverId = state.drag && state.drag.impact.destination ? state.drag.impact.destination.droppableId : null;
var newImpact = impact || (0, _getDragImpact2.default)({
pageCenter: page.center,
draggable: state.dimension.draggable[current.id],
draggables: state.dimension.draggable,
droppables: state.dimension.droppable,
previousDroppableOverId: previousDroppableOverId
});
var drag = {
initial: initial,
impact: newImpact,
current: current,
previous: {
droppableOverId: previousDroppableOverId
}
};
return (0, _extends7.default)({}, state, {
drag: drag
});
};
exports.default = function () {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : clean('IDLE');
var action = arguments[1];
if (action.type === 'BEGIN_LIFT') {
if (state.phase !== 'IDLE') {
console.error('trying to start a lift while another is occurring');
return state;
}
return clean('COLLECTING_DIMENSIONS');
}
if (action.type === 'REQUEST_DIMENSIONS') {
if (state.phase !== 'COLLECTING_DIMENSIONS') {
console.error('trying to collect dimensions at the wrong time');
return state;
}
var typeId = action.payload;
return {
phase: 'COLLECTING_DIMENSIONS',
drag: null,
drop: null,
dimension: {
request: typeId,
draggable: {},
droppable: {}
}
};
}
if (action.type === 'PUBLISH_DRAGGABLE_DIMENSION') {
var dimension = action.payload;
if (state.phase !== 'COLLECTING_DIMENSIONS') {
console.warn('dimension rejected as no longer requesting dimensions', dimension);
return state;
}
if (state.dimension.draggable[dimension.id]) {
console.error('dimension already exists for ' + dimension.id);
return state;
}
return (0, _extends7.default)({}, state, {
dimension: {
request: state.dimension.request,
droppable: state.dimension.droppable,
draggable: (0, _extends7.default)({}, state.dimension.draggable, (0, _defineProperty3.default)({}, dimension.id, dimension))
}
});
}
if (action.type === 'PUBLISH_DROPPABLE_DIMENSION') {
var _dimension = action.payload;
if (state.phase !== 'COLLECTING_DIMENSIONS') {
console.warn('dimension rejected as no longer requesting dimensions', _dimension);
return state;
}
if (state.dimension.droppable[_dimension.id]) {
console.error('dimension already exists for ' + _dimension.id);
return state;
}
return (0, _extends7.default)({}, state, {
dimension: {
request: state.dimension.request,
draggable: state.dimension.draggable,
droppable: (0, _extends7.default)({}, state.dimension.droppable, (0, _defineProperty3.default)({}, _dimension.id, _dimension))
}
});
}
if (action.type === 'COMPLETE_LIFT') {
if (state.phase !== 'COLLECTING_DIMENSIONS') {
console.error('trying complete lift without collecting dimensions');
return state;
}
var _action$payload = action.payload,
id = _action$payload.id,
type = _action$payload.type,
client = _action$payload.client,
_windowScroll = _action$payload.windowScroll,
isScrollAllowed = _action$payload.isScrollAllowed;
var draggables = state.dimension.draggable;
var draggable = state.dimension.draggable[id];
var droppable = state.dimension.droppable[draggable.droppableId];
var page = {
selection: (0, _position.add)(client.selection, _windowScroll),
center: (0, _position.add)(client.center, _windowScroll)
};
var _impact = (0, _getInitialImpact2.default)({
draggable: draggable,
droppable: droppable,
draggables: draggables
});
if (!_impact || !_impact.destination) {
console.error('invalid lift state');
return clean();
}
var source = _impact.destination;
var initial = {
source: source,
client: client,
page: page,
windowScroll: _windowScroll
};
var current = {
id: id,
type: type,
client: {
selection: client.selection,
center: client.center,
offset: origin
},
page: {
selection: page.selection,
center: page.center,
offset: origin
},
windowScroll: _windowScroll,
isScrollAllowed: isScrollAllowed,
shouldAnimate: false
};
return (0, _extends7.default)({}, state, {
phase: 'DRAGGING',
drag: {
initial: initial,
current: current,
impact: _impact
}
});
}
if (action.type === 'UPDATE_DROPPABLE_DIMENSION_SCROLL') {
if (state.phase !== 'DRAGGING') {
console.error('cannot update a droppable dimensions scroll when not dragging');
return clean();
}
if (state.drag == null) {
console.error('invalid store state');
return clean();
}
if (!state.drag.current.isScrollAllowed) {
return clean();
}
var _action$payload2 = action.payload,
_id = _action$payload2.id,
offset = _action$payload2.offset;
var target = state.dimension.droppable[_id];
if (!target) {
console.error('cannot update a droppable that is not inside of the state', _id);
return clean();
}
var _dimension2 = (0, _extends7.default)({}, target, {
container: (0, _extends7.default)({}, target.container, {
scroll: (0, _extends7.default)({}, target.container.scroll, {
current: offset
})
})
});
var withUpdatedDimension = (0, _extends7.default)({}, state, {
dimension: {
request: state.dimension.request,
draggable: state.dimension.draggable,
droppable: (0, _extends7.default)({}, state.dimension.droppable, (0, _defineProperty3.default)({}, _id, _dimension2))
}
});
return move({
state: withUpdatedDimension,
clientSelection: state.drag.current.client.selection
});
}
if (action.type === 'UPDATE_DROPPABLE_DIMENSION_IS_ENABLED') {
if (!(0, _keys2.default)(state.dimension.droppable).length) {
return state;
}
var _action$payload3 = action.payload,
_id2 = _action$payload3.id,
isEnabled = _action$payload3.isEnabled;
var _target = state.dimension.droppable[_id2];
if (!_target) {
console.error('cannot update enabled flag on droppable that does not have a dimension');
return clean();
}
if (_target.isEnabled === isEnabled) {
console.warn('trying to set droppable isEnabled to ' + isEnabled + ' but it is already ' + isEnabled);
return state;
}
var updatedDroppableDimension = (0, _extends7.default)({}, _target, {
isEnabled: isEnabled
});
return (0, _extends7.default)({}, state, {
dimension: (0, _extends7.default)({}, state.dimension, {
droppable: (0, _extends7.default)({}, state.dimension.droppable, (0, _defineProperty3.default)({}, _id2, updatedDroppableDimension))
})
});
}
if (action.type === 'MOVE') {
var _action$payload4 = action.payload,
_client = _action$payload4.client,
_windowScroll2 = _action$payload4.windowScroll;
return move({
state: state,
clientSelection: _client,
windowScroll: _windowScroll2
});
}
if (action.type === 'MOVE_BY_WINDOW_SCROLL') {
var _windowScroll3 = action.payload.windowScroll;
if (!state.drag) {
console.error('cannot move with window scrolling if no current drag');
return clean();
}
return move({
state: state,
clientSelection: state.drag.current.client.selection,
windowScroll: _windowScroll3
});
}
if (action.type === 'MOVE_FORWARD' || action.type === 'MOVE_BACKWARD') {
if (state.phase !== 'DRAGGING') {
console.error('cannot move while not dragging', action);
return clean();
}
if (!state.drag) {
console.error('cannot move if there is no drag information');
return clean();
}
var existing = state.drag;
var isMovingForward = action.type === 'MOVE_FORWARD';
if (!existing.impact.destination) {
console.error('cannot move if there is no previous destination');
return clean();
}
var _droppable = state.dimension.droppable[existing.impact.destination.droppableId];
var result = (0, _moveToNextIndex2.default)({
isMovingForward: isMovingForward,
draggableId: existing.current.id,
impact: existing.impact,
droppable: _droppable,
draggables: state.dimension.draggable
});
if (!result) {
return state;
}
var _impact2 = result.impact;
var _page = result.pageCenter;
var _client2 = (0, _position.subtract)(_page, existing.current.windowScroll);
return move({
state: state,
impact: _impact2,
clientSelection: _client2,
shouldAnimate: true
});
}
if (action.type === 'CROSS_AXIS_MOVE_FORWARD' || action.type === 'CROSS_AXIS_MOVE_BACKWARD') {
if (state.phase !== 'DRAGGING') {
console.error('cannot move cross axis when not dragging');
return clean();
}
if (!state.drag) {
console.error('cannot move cross axis if there is no drag information');
return clean();
}
if (!state.drag.impact.destination) {
console.error('cannot move cross axis if not in a droppable');
return clean();
}
var _current = state.drag.current;
var draggableId = _current.id;
var center = _current.page.center;
var droppableId = state.drag.impact.destination.droppableId;
var home = state.drag.initial.source;
var _result = (0, _moveCrossAxis2.default)({
isMovingForward: action.type === 'CROSS_AXIS_MOVE_FORWARD',
pageCenter: center,
draggableId: draggableId,
droppableId: droppableId,
home: home,
draggables: state.dimension.draggable,
droppables: state.dimension.droppable
});
if (!_result) {
return state;
}
var _page2 = _result.pageCenter;
var _client3 = (0, _position.subtract)(_page2, _current.windowScroll);
return move({
state: state,
clientSelection: _client3,
impact: _result.impact,
shouldAnimate: true
});
}
if (action.type === 'DROP_ANIMATE') {
var _action$payload5 = action.payload,
trigger = _action$payload5.trigger,
newHomeOffset = _action$payload5.newHomeOffset,
_impact3 = _action$payload5.impact,
_result2 = _action$payload5.result;
if (state.phase !== 'DRAGGING') {
console.error('cannot animate drop while not dragging', action);
return state;
}
if (!state.drag) {
console.error('cannot animate drop - invalid drag state');
return clean();
}
var pending = {
trigger: trigger,
newHomeOffset: newHomeOffset,
result: _result2,
impact: _impact3
};
return {
phase: 'DROP_ANIMATING',
drag: null,
drop: {
pending: pending,
result: null
},
dimension: state.dimension
};
}
if (action.type === 'DROP_COMPLETE') {
var _result3 = action.payload;
return {
phase: 'DROP_COMPLETE',
drag: null,
drop: {
pending: null,
result: _result3
},
dimension: noDimensions
};
}
if (action.type === 'CLEAN') {
return clean();
}
return state;
};