UNPKG

react-beautiful-dnd

Version:

Beautiful, accessible drag and drop for lists with React.js

536 lines (429 loc) 14.4 kB
'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; };