Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-beautiful-dnd

Package Overview
Dependencies
Maintainers
1
Versions
94
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-beautiful-dnd - npm Package Compare versions

Comparing version 2.1.1 to 2.2.0

lib/state/get-client-rect.js

86

lib/state/action-creators.js

@@ -6,3 +6,3 @@ 'use strict';

});
exports.lift = exports.dropAnimationFinished = exports.cancel = exports.drop = exports.completeDrop = exports.clean = exports.moveForward = exports.moveBackward = exports.moveByWindowScroll = exports.move = exports.updateDroppableDimensionScroll = exports.publishDroppableDimension = exports.publishDraggableDimension = exports.requestDimensions = undefined;
exports.lift = exports.dropAnimationFinished = exports.cancel = exports.drop = exports.completeDrop = exports.clean = exports.crossAxisMoveBackward = exports.crossAxisMoveForward = exports.moveForward = exports.moveBackward = exports.moveByWindowScroll = exports.move = exports.updateDroppableDimensionIsEnabled = exports.updateDroppableDimensionScroll = exports.publishDroppableDimension = exports.publishDraggableDimension = exports.requestDimensions = undefined;

@@ -13,5 +13,5 @@ var _noImpact = require('./no-impact');

var _getNewHomeClientOffset = require('./get-new-home-client-offset');
var _getNewHomeClientCenter = require('./get-new-home-client-center');
var _getNewHomeClientOffset2 = _interopRequireDefault(_getNewHomeClientOffset);
var _getNewHomeClientCenter2 = _interopRequireDefault(_getNewHomeClientCenter);

@@ -24,10 +24,12 @@ var _position = require('./position');

var getScrollDiff = function getScrollDiff(initial, current, droppable) {
var getScrollDiff = function getScrollDiff(_ref) {
var initial = _ref.initial,
current = _ref.current,
droppable = _ref.droppable;
var windowScrollDiff = (0, _position.subtract)(initial.windowScroll, current.windowScroll);
var droppableScrollDiff = (0, _position.subtract)(droppable.scroll.initial, droppable.scroll.current);
return {
window: windowScrollDiff,
droppable: droppableScrollDiff
};
var droppableScrollDiff = droppable ? (0, _position.subtract)(droppable.scroll.initial, droppable.scroll.current) : origin;
return (0, _position.add)(windowScrollDiff, droppableScrollDiff);
};

@@ -48,3 +50,3 @@

var completeLift = function completeLift(id, type, client, page, windowScroll) {
var completeLift = function completeLift(id, type, client, page, windowScroll, isScrollAllowed) {
return {

@@ -57,3 +59,4 @@ type: 'COMPLETE_LIFT',

page: page,
windowScroll: windowScroll
windowScroll: windowScroll,
isScrollAllowed: isScrollAllowed
}

@@ -87,2 +90,12 @@ };

var updateDroppableDimensionIsEnabled = exports.updateDroppableDimensionIsEnabled = function updateDroppableDimensionIsEnabled(id, isEnabled) {
return {
type: 'UPDATE_DROPPABLE_DIMENSION_IS_ENABLED',
payload: {
id: id,
isEnabled: isEnabled
}
};
};
var move = exports.move = function move(id, client, page, windowScroll) {

@@ -124,2 +137,16 @@ return {

var crossAxisMoveForward = exports.crossAxisMoveForward = function crossAxisMoveForward(id) {
return {
type: 'CROSS_AXIS_MOVE_FORWARD',
payload: id
};
};
var crossAxisMoveBackward = exports.crossAxisMoveBackward = function crossAxisMoveBackward(id) {
return {
type: 'CROSS_AXIS_MOVE_BACKWARD',
payload: id
};
};
var clean = exports.clean = function clean() {

@@ -132,7 +159,7 @@ return {

var animateDrop = function animateDrop(_ref) {
var trigger = _ref.trigger,
newHomeOffset = _ref.newHomeOffset,
impact = _ref.impact,
result = _ref.result;
var animateDrop = function animateDrop(_ref2) {
var trigger = _ref2.trigger,
newHomeOffset = _ref2.newHomeOffset,
impact = _ref2.impact,
result = _ref2.result;
return {

@@ -183,4 +210,4 @@ type: 'DROP_ANIMATE',

var sourceDroppable = state.dimension.droppable[initial.source.droppableId];
var destinationDroppable = impact.destination ? state.dimension.droppable[impact.destination.droppableId] : null;
var droppable = impact.destination ? state.dimension.droppable[impact.destination.droppableId] : null;
var draggable = state.dimension.draggable[current.id];

@@ -194,14 +221,13 @@ var result = {

var scrollDiff = getScrollDiff(initial, current, sourceDroppable);
var newHomeOffset = (0, _getNewHomeClientOffset2.default)({
var newCenter = (0, _getNewHomeClientCenter2.default)({
movement: impact.movement,
clientOffset: current.client.offset,
pageOffset: current.page.offset,
droppableScrollDiff: scrollDiff.droppable,
windowScrollDiff: scrollDiff.window,
draggable: draggable,
draggables: state.dimension.draggable,
axis: destinationDroppable ? destinationDroppable.axis : null
destination: droppable
});
var clientOffset = (0, _position.subtract)(newCenter, draggable.client.withMargin.center);
var scrollDiff = getScrollDiff({ initial: initial, current: current, droppable: droppable });
var newHomeOffset = (0, _position.add)(clientOffset, scrollDiff);
var isAnimationRequired = !(0, _position.isEqual)(current.client.offset, newHomeOffset);

@@ -259,7 +285,7 @@

var scrollDiff = getScrollDiff(initial, current, droppable);
var scrollDiff = getScrollDiff({ initial: initial, current: current, droppable: droppable });
dispatch(animateDrop({
trigger: 'CANCEL',
newHomeOffset: (0, _position.add)(scrollDiff.droppable, scrollDiff.window),
newHomeOffset: scrollDiff,
impact: _noImpact2.default,

@@ -291,3 +317,3 @@ result: result

var lift = exports.lift = function lift(id, type, client, page, windowScroll) {
var lift = exports.lift = function lift(id, type, client, page, windowScroll, isScrollAllowed) {
return function (dispatch, getState) {

@@ -323,3 +349,3 @@ (function () {

}
dispatch(completeLift(id, type, client, page, windowScroll));
dispatch(completeLift(id, type, client, page, windowScroll, isScrollAllowed));
});

@@ -326,0 +352,0 @@ });

@@ -9,5 +9,9 @@ 'use strict';

line: 'y',
crossLine: 'x',
start: 'top',
end: 'bottom',
size: 'height'
size: 'height',
crossAxisStart: 'left',
crossAxisEnd: 'right',
crossAxisSize: 'width'
};

@@ -18,5 +22,9 @@

line: 'x',
crossLine: 'y',
start: 'left',
end: 'right',
size: 'width'
size: 'width',
crossAxisStart: 'top',
crossAxisEnd: 'bottom',
crossAxisSize: 'height'
};

@@ -6,9 +6,15 @@ 'use strict';

});
exports.getDroppableDimension = exports.getDraggableDimension = exports.noMargin = undefined;
exports.getDroppableDimension = exports.getDraggableDimension = exports.noSpacing = undefined;
var _axis = require('./axis');
var _getClientRect = require('./get-client-rect');
var _getClientRect2 = _interopRequireDefault(_getClientRect);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var origin = { x: 0, y: 0 };
var noMargin = exports.noMargin = {
var noSpacing = exports.noSpacing = {
top: 0,

@@ -24,32 +30,24 @@ right: 0,

bottom = clientRect.bottom,
left = clientRect.left,
width = clientRect.width,
height = clientRect.height;
left = clientRect.left;
return {
return (0, _getClientRect2.default)({
top: top + point.y,
left: left + point.x,
bottom: bottom + point.y,
right: right + point.x,
height: height,
width: width
};
right: right + point.x
});
};
var getWithMargin = function getWithMargin(clientRect, margin) {
var getWithSpacing = function getWithSpacing(clientRect, spacing) {
var top = clientRect.top,
right = clientRect.right,
bottom = clientRect.bottom,
left = clientRect.left,
height = clientRect.height,
width = clientRect.width;
left = clientRect.left;
return {
top: top + margin.top,
left: left + margin.left,
bottom: bottom + margin.bottom,
right: right + margin.right,
height: height + margin.top + margin.bottom,
width: width + margin.left + margin.right
};
return (0, _getClientRect2.default)({
top: top + spacing.top,
left: left + spacing.left,
bottom: bottom + spacing.bottom,
right: right + spacing.right
});
};

@@ -59,12 +57,20 @@

var point = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : origin;
return {
var rect = (0, _getClientRect2.default)({
top: initial.top + point.y,
left: initial.left + point.x,
bottom: initial.bottom + point.y,
right: initial.right + point.x,
width: initial.width,
height: initial.height,
right: initial.right + point.x
});
return {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left,
width: rect.width,
height: rect.height,
center: {
x: (initial.right + point.x + (initial.left + point.x)) / 2,
y: (initial.bottom + point.y + (initial.top + point.y)) / 2
x: (rect.right + rect.left) / 2,
y: (rect.bottom + rect.top) / 2
}

@@ -79,3 +85,3 @@ };

_ref$margin = _ref.margin,
margin = _ref$margin === undefined ? noMargin : _ref$margin,
margin = _ref$margin === undefined ? noSpacing : _ref$margin,
_ref$windowScroll = _ref.windowScroll,

@@ -85,3 +91,2 @@ windowScroll = _ref$windowScroll === undefined ? origin : _ref$windowScroll;

var withScroll = getWithPosition(clientRect, windowScroll);
var withScrollAndMargin = getWithMargin(withScroll, margin);

@@ -94,3 +99,3 @@ var dimension = {

withoutMargin: getFragment(clientRect),
withMargin: getFragment(getWithMargin(clientRect, margin))
withMargin: getFragment(getWithSpacing(clientRect, margin))
},

@@ -100,3 +105,3 @@

withoutMargin: getFragment(withScroll),
withMargin: getFragment(withScrollAndMargin)
withMargin: getFragment(getWithSpacing(withScroll, margin))
}

@@ -108,2 +113,11 @@ };

var add = function add(spacing1, spacing2) {
return {
top: spacing1.top + spacing2.top,
left: spacing1.left + spacing2.left,
right: spacing1.right + spacing2.right,
bottom: spacing1.bottom + spacing2.bottom
};
};
var getDroppableDimension = exports.getDroppableDimension = function getDroppableDimension(_ref2) {

@@ -115,13 +129,18 @@ var id = _ref2.id,

_ref2$margin = _ref2.margin,
margin = _ref2$margin === undefined ? noMargin : _ref2$margin,
margin = _ref2$margin === undefined ? noSpacing : _ref2$margin,
_ref2$padding = _ref2.padding,
padding = _ref2$padding === undefined ? noSpacing : _ref2$padding,
_ref2$windowScroll = _ref2.windowScroll,
windowScroll = _ref2$windowScroll === undefined ? origin : _ref2$windowScroll,
_ref2$scroll = _ref2.scroll,
scroll = _ref2$scroll === undefined ? origin : _ref2$scroll;
scroll = _ref2$scroll === undefined ? origin : _ref2$scroll,
_ref2$isEnabled = _ref2.isEnabled,
isEnabled = _ref2$isEnabled === undefined ? true : _ref2$isEnabled;
var withMargin = getWithSpacing(clientRect, margin);
var withWindowScroll = getWithPosition(clientRect, windowScroll);
var withWindowScrollAndMargin = getWithMargin(withWindowScroll, margin);
var dimension = {
id: id,
isEnabled: isEnabled,
axis: direction === 'vertical' ? _axis.vertical : _axis.horizontal,

@@ -133,5 +152,11 @@ scroll: {

},
client: {
withoutMargin: getFragment(clientRect),
withMargin: getFragment(withMargin),
withMarginAndPadding: getFragment(getWithSpacing(withMargin, padding))
},
page: {
withoutMargin: getFragment(withWindowScroll),
withMargin: getFragment(withWindowScrollAndMargin)
withMargin: getFragment(getWithSpacing(withWindowScroll, margin)),
withMarginAndPadding: getFragment(getWithSpacing(withWindowScroll, add(margin, padding)))
}

@@ -138,0 +163,0 @@ };

@@ -23,9 +23,19 @@ 'use strict';

exports.default = function (_ref) {
var page = _ref.page,
withinDroppable = _ref.withinDroppable,
draggableId = _ref.draggableId,
draggables = _ref.draggables,
droppables = _ref.droppables;
var getDroppablesScrollDiff = function getDroppablesScrollDiff(_ref) {
var sourceDroppable = _ref.sourceDroppable,
destinationDroppable = _ref.destinationDroppable,
line = _ref.line;
var sourceScrollDiff = sourceDroppable.scroll.initial[line] - sourceDroppable.scroll.current[line];
var destinationScrollDiff = destinationDroppable.scroll.initial[line] - destinationDroppable.scroll.current[line];
return destinationScrollDiff - sourceScrollDiff;
};
exports.default = function (_ref2) {
var page = _ref2.page,
withinDroppable = _ref2.withinDroppable,
draggableId = _ref2.draggableId,
draggables = _ref2.draggables,
droppables = _ref2.droppables;
var droppableId = (0, _getDroppableOver2.default)(page, droppables);

@@ -37,12 +47,22 @@

var droppable = droppables[droppableId];
var axis = droppable.axis;
if (!droppable.isEnabled) {
return {
movement: _noImpact.noMovement,
direction: axis.direction,
destination: null
};
}
var insideDroppable = (0, _getDraggablesInsideDroppable2.default)(droppable, draggables);
var newCenter = withinDroppable.center;
var draggingDimension = draggables[draggableId];
var droppableDimension = droppables[droppableId];
var isWithinHomeDroppable = draggingDimension.droppableId === droppableId;
var insideDroppable = (0, _getDraggablesInsideDroppable2.default)(droppableDimension, draggables);
var axis = droppableDimension.axis;
var draggableCenter = draggingDimension.page.withoutMargin.center;
var isBeyondStartPosition = newCenter[axis.line] - draggableCenter[axis.line] > 0;
var shouldDisplaceItemsForward = isWithinHomeDroppable ? isBeyondStartPosition : false;

@@ -56,2 +76,11 @@ var moved = insideDroppable.filter(function (dimension) {

if (!isWithinHomeDroppable) {
var scrollDiff = getDroppablesScrollDiff({
sourceDroppable: droppables[draggingDimension.droppableId],
destinationDroppable: droppable,
line: axis.line
});
return newCenter[axis.line] - scrollDiff < fragment[axis.end];
}
if (isBeyondStartPosition) {

@@ -74,4 +103,15 @@ if (fragment.center[axis.line] < draggableCenter[axis.line]) {

var ordered = function () {
if (!isWithinHomeDroppable) {
return moved;
}
return isBeyondStartPosition ? moved.reverse() : moved;
}();
var startIndex = insideDroppable.indexOf(draggingDimension);
var index = function () {
if (!isWithinHomeDroppable) {
return insideDroppable.length - moved.length;
}
if (!moved.length) {

@@ -94,4 +134,4 @@ return startIndex;

amount: amount,
draggables: moved,
isBeyondStartPosition: isBeyondStartPosition
draggables: ordered,
isBeyondStartPosition: shouldDisplaceItemsForward
};

@@ -98,0 +138,0 @@

@@ -17,10 +17,10 @@ 'use strict';

exports.default = (0, _memoizeOne2.default)(function (droppableDimension, draggableDimensions) {
return (0, _keys2.default)(draggableDimensions).map(function (key) {
return draggableDimensions[key];
}).filter(function (dimension) {
return dimension.droppableId === droppableDimension.id;
exports.default = (0, _memoizeOne2.default)(function (droppable, draggables) {
return (0, _keys2.default)(draggables).map(function (id) {
return draggables[id];
}).filter(function (draggable) {
return droppable.id === draggable.droppableId;
}).sort(function (a, b) {
return a.page.withoutMargin.center[droppableDimension.axis.line] - b.page.withoutMargin.center[droppableDimension.axis.line];
return a.page.withoutMargin.center[droppable.axis.line] - b.page.withoutMargin.center[droppable.axis.line];
});
});

@@ -11,14 +11,14 @@ 'use strict';

var _isInsideDroppable = require('./is-inside-droppable');
var _isWithinVisibleBoundsOfDroppable = require('./is-within-visible-bounds-of-droppable');
var _isInsideDroppable2 = _interopRequireDefault(_isInsideDroppable);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.default = function (target, droppables) {
var maybeId = (0, _keys2.default)(droppables).find(function (key) {
return (0, _isInsideDroppable2.default)(target, droppables[key]);
var maybe = (0, _keys2.default)(droppables).map(function (id) {
return droppables[id];
}).find(function (droppable) {
return (0, _isWithinVisibleBoundsOfDroppable.isPointWithin)(droppable)(target);
});
return maybeId || null;
return maybe ? maybe.id : null;
};

@@ -10,3 +10,3 @@ 'use strict';

var noMovement = {
var noMovement = exports.noMovement = {
draggables: [],

@@ -13,0 +13,0 @@ amount: origin,

@@ -6,2 +6,14 @@ 'use strict';

});
exports.closest = exports.distance = exports.patch = exports.absolute = exports.negate = exports.isEqual = exports.subtract = exports.add = undefined;
var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
var _defineProperty2 = require('babel-runtime/helpers/defineProperty');
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var add = exports.add = function add(point1, point2) {

@@ -32,7 +44,24 @@ return {

var patch = exports.patch = function patch(line, value) {
var absolute = exports.absolute = function absolute(point) {
return {
x: line === 'x' ? value : 0,
y: line === 'y' ? value : 0
x: Math.abs(point.x),
y: Math.abs(point.y)
};
};
var patch = exports.patch = function patch(line, value) {
var _ref;
var otherValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
return _ref = {}, (0, _defineProperty3.default)(_ref, line, value), (0, _defineProperty3.default)(_ref, line === 'x' ? 'y' : 'x', otherValue), _ref;
};
var distance = exports.distance = function distance(point1, point2) {
return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
};
var closest = exports.closest = function closest(target, points) {
return Math.min.apply(Math, (0, _toConsumableArray3.default)(points.map(function (point) {
return distance(target, point);
})));
};

@@ -7,2 +7,6 @@ 'use strict';

var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);
var _defineProperty2 = require('babel-runtime/helpers/defineProperty');

@@ -12,5 +16,5 @@

var _extends5 = require('babel-runtime/helpers/extends');
var _extends6 = require('babel-runtime/helpers/extends');
var _extends6 = _interopRequireDefault(_extends5);
var _extends7 = _interopRequireDefault(_extends6);

@@ -21,2 +25,6 @@ var _memoizeOne = require('memoize-one');

var _getInitialImpact = require('./get-initial-impact');
var _getInitialImpact2 = _interopRequireDefault(_getInitialImpact);
var _position = require('./position');

@@ -28,9 +36,9 @@

var _jumpToNextIndex = require('./jump-to-next-index');
var _moveToNextIndex = require('./move-to-next-index/');
var _jumpToNextIndex2 = _interopRequireDefault(_jumpToNextIndex);
var _moveToNextIndex2 = _interopRequireDefault(_moveToNextIndex);
var _getDroppableOver = require('./get-droppable-over');
var _moveCrossAxis = require('./move-cross-axis/');
var _getDroppableOver2 = _interopRequireDefault(_getDroppableOver);
var _moveCrossAxis2 = _interopRequireDefault(_moveCrossAxis);

@@ -116,2 +124,3 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

type: previous.type,
isScrollAllowed: previous.isScrollAllowed,
client: client,

@@ -138,3 +147,3 @@ page: page,

return (0, _extends6.default)({}, state, {
return (0, _extends7.default)({}, state, {
drag: drag

@@ -189,7 +198,7 @@ });

return (0, _extends6.default)({}, state, {
return (0, _extends7.default)({}, state, {
dimension: {
request: state.dimension.request,
droppable: state.dimension.droppable,
draggable: (0, _extends6.default)({}, state.dimension.draggable, (0, _defineProperty3.default)({}, dimension.id, dimension))
draggable: (0, _extends7.default)({}, state.dimension.draggable, (0, _defineProperty3.default)({}, dimension.id, dimension))
}

@@ -212,7 +221,7 @@ });

return (0, _extends6.default)({}, state, {
return (0, _extends7.default)({}, state, {
dimension: {
request: state.dimension.request,
draggable: state.dimension.draggable,
droppable: (0, _extends6.default)({}, state.dimension.droppable, (0, _defineProperty3.default)({}, _dimension.id, _dimension))
droppable: (0, _extends7.default)({}, state.dimension.droppable, (0, _defineProperty3.default)({}, _dimension.id, _dimension))
}

@@ -233,23 +242,26 @@ });

page = _action$payload.page,
_windowScroll = _action$payload.windowScroll;
_windowScroll = _action$payload.windowScroll,
isScrollAllowed = _action$payload.isScrollAllowed;
var withinDroppable = {
center: page.center
};
var draggables = state.dimension.draggable;
var draggable = state.dimension.draggable[id];
var droppable = state.dimension.droppable[draggable.droppableId];
var _impact = (0, _getDragImpact2.default)({
page: page.selection,
withinDroppable: withinDroppable,
draggableId: id,
draggables: state.dimension.draggable,
droppables: state.dimension.droppable
var _impact = (0, _getInitialImpact2.default)({
draggable: draggable,
droppable: droppable,
draggables: draggables
});
var source = _impact.destination;
if (!source) {
console.error('lifting a draggable that is not inside a droppable');
if (!_impact || !_impact.destination) {
console.error('invalid lift state');
return clean();
}
var source = _impact.destination;
var withinDroppable = {
center: page.center
};
var initial = {

@@ -278,6 +290,7 @@ source: source,

windowScroll: _windowScroll,
isScrollAllowed: isScrollAllowed,
shouldAnimate: false
};
return (0, _extends6.default)({}, state, {
return (0, _extends7.default)({}, state, {
phase: 'DRAGGING',

@@ -303,2 +316,6 @@ drag: {

if (!state.drag.current.isScrollAllowed) {
return clean();
}
var _action$payload2 = action.payload,

@@ -316,3 +333,3 @@ _id = _action$payload2.id,

var _dimension2 = (0, _extends6.default)({}, target, {
var _dimension2 = (0, _extends7.default)({}, target, {
scroll: {

@@ -324,7 +341,7 @@ initial: target.scroll.initial,

var withUpdatedDimension = (0, _extends6.default)({}, state, {
var withUpdatedDimension = (0, _extends7.default)({}, state, {
dimension: {
request: state.dimension.request,
draggable: state.dimension.draggable,
droppable: (0, _extends6.default)({}, state.dimension.droppable, (0, _defineProperty3.default)({}, _id, _dimension2))
droppable: (0, _extends7.default)({}, state.dimension.droppable, (0, _defineProperty3.default)({}, _id, _dimension2))
}

@@ -345,8 +362,40 @@ });

if (action.type === 'MOVE') {
if (action.type === 'UPDATE_DROPPABLE_DIMENSION_IS_ENABLED') {
if (!(0, _keys2.default)(state.dimension.droppable).length) {
return state;
}
var _action$payload3 = action.payload,
_client2 = _action$payload3.client,
_page2 = _action$payload3.page,
_windowScroll2 = _action$payload3.windowScroll;
_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,
_client2 = _action$payload4.client,
_page2 = _action$payload4.page,
_windowScroll2 = _action$payload4.windowScroll;
return move({

@@ -403,8 +452,15 @@ state: state,

var result = (0, _jumpToNextIndex2.default)({
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,
draggables: state.dimension.draggable,
droppables: state.dimension.droppable
droppable: _droppable,
draggables: state.dimension.draggable
});

@@ -416,20 +472,59 @@

var _diff = result.diff;
var _impact2 = result.impact;
var _page4 = result.pageCenter;
var _client4 = (0, _position.subtract)(_page4, existing.current.windowScroll);
var _page4 = (0, _position.add)(existing.current.page.selection, _diff);
var _client4 = (0, _position.add)(existing.current.client.selection, _diff);
return move({
state: state,
impact: _impact2,
clientSelection: _client4,
pageSelection: _page4,
shouldAnimate: true
});
}
var droppableId = (0, _getDroppableOver2.default)(_page4, state.dimension.droppable);
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 (!droppableId) {
console.info('currently not supporting moving a draggable outside the visibility bounds of a droppable');
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 _current2 = state.drag.current;
var draggableId = _current2.id;
var center = _current2.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 _page5 = _result.pageCenter;
var _client5 = (0, _position.subtract)(_page5, _current2.windowScroll);
return move({
state: state,
impact: _impact2,
clientSelection: _client4,
pageSelection: _page4,
clientSelection: _client5,
pageSelection: _page5,
impact: _result.impact,
shouldAnimate: true

@@ -440,7 +535,7 @@ });

if (action.type === 'DROP_ANIMATE') {
var _action$payload4 = action.payload,
trigger = _action$payload4.trigger,
newHomeOffset = _action$payload4.newHomeOffset,
_impact3 = _action$payload4.impact,
_result = _action$payload4.result;
var _action$payload5 = action.payload,
trigger = _action$payload5.trigger,
newHomeOffset = _action$payload5.newHomeOffset,
_impact3 = _action$payload5.impact,
_result2 = _action$payload5.result;

@@ -461,3 +556,3 @@

newHomeOffset: newHomeOffset,
result: _result,
result: _result2,
impact: _impact3

@@ -478,3 +573,3 @@ };

if (action.type === 'DROP_COMPLETE') {
var _result2 = action.payload;
var _result3 = action.payload;

@@ -486,3 +581,3 @@ return {

pending: null,
result: _result2
result: _result3
},

@@ -489,0 +584,0 @@ dimension: noDimensions

@@ -6,2 +6,6 @@ 'use strict';

});
exports.draggingDraggableSelector = exports.dragSelector = exports.pendingDropSelector = exports.phaseSelector = undefined;
var _reselect = require('reselect');
var phaseSelector = exports.phaseSelector = function phaseSelector(state) {

@@ -20,2 +24,34 @@ return state.phase;

return state.drag;
};
};
var draggableMapSelector = function draggableMapSelector(state) {
return state.dimension.draggable;
};
var draggingDraggableSelector = exports.draggingDraggableSelector = (0, _reselect.createSelector)([phaseSelector, dragSelector, pendingDropSelector, draggableMapSelector], function (phase, drag, pending, draggables) {
if (phase === 'DRAGGING') {
if (!drag) {
console.error('cannot get placeholder dimensions as there is an invalid drag state');
return null;
}
var draggable = draggables[drag.current.id];
return draggable;
}
if (phase === 'DROP_ANIMATING') {
if (!pending) {
console.error('cannot get placeholder dimensions as there is an invalid drag state');
return null;
}
if (!pending.result.destination) {
return null;
}
var _draggable = draggables[pending.result.draggableId];
return _draggable;
}
return null;
});

@@ -91,2 +91,6 @@ 'use strict';

_this.ifDragging(_this.props.callbacks.onMoveBackward);
}), _this.scheduleCrossAxisMoveForward = (0, _rafSchd2.default)(function () {
_this.ifDragging(_this.props.callbacks.onCrossAxisMoveForward);
}), _this.scheduleCrossAxisMoveBackward = (0, _rafSchd2.default)(function () {
_this.ifDragging(_this.props.callbacks.onCrossAxisMoveBackward);
}), _this.scheduleWindowScrollMove = (0, _rafSchd2.default)(function () {

@@ -211,2 +215,12 @@ _this.ifDragging(_this.props.callbacks.onWindowScroll);

_this.startPendingMouseDrag(point);
}, _this.executeBasedOnDirection = function (fns) {
if (!_this.props.direction) {
console.error('cannot move based on direction when none is provided');
_this.stopDragging(function () {
return _this.props.callbacks.onCancel();
});
return;
}
_this.props.direction === 'vertical' ? fns.vertical() : fns.horizontal();
}, _this.onWindowKeydown = function (event) {

@@ -272,13 +286,17 @@ var isMouseDragPending = Boolean(_this.state.pending);

if (_this.props.direction === 'vertical') {
if (event.keyCode === keyCodes.arrowDown) {
event.preventDefault();
_this.scheduleMoveForward();
}
if (event.keyCode === keyCodes.arrowDown) {
event.preventDefault();
_this.executeBasedOnDirection({
vertical: _this.scheduleMoveForward,
horizontal: _this.scheduleCrossAxisMoveForward
});
return;
}
if (event.keyCode === keyCodes.arrowUp) {
event.preventDefault();
_this.scheduleMoveBackward();
}
if (event.keyCode === keyCodes.arrowUp) {
event.preventDefault();
_this.executeBasedOnDirection({
vertical: _this.scheduleMoveBackward,
horizontal: _this.scheduleCrossAxisMoveBackward
});
return;

@@ -289,3 +307,6 @@ }

event.preventDefault();
_this.scheduleMoveForward();
_this.executeBasedOnDirection({
vertical: _this.scheduleCrossAxisMoveForward,
horizontal: _this.scheduleMoveForward
});
return;

@@ -296,3 +317,6 @@ }

event.preventDefault();
_this.scheduleMoveBackward();
_this.executeBasedOnDirection({
vertical: _this.scheduleCrossAxisMoveBackward,
horizontal: _this.scheduleMoveBackward
});
}

@@ -299,0 +323,0 @@ }, _this.onKeyDown = function (event) {

@@ -172,4 +172,6 @@ 'use strict';

move: _actionCreators.move,
moveForward: _actionCreators.moveForward,
moveBackward: _actionCreators.moveBackward,
moveForward: _actionCreators.moveForward,
crossAxisMoveForward: _actionCreators.crossAxisMoveForward,
crossAxisMoveBackward: _actionCreators.crossAxisMoveBackward,
moveByWindowScroll: _actionCreators.moveByWindowScroll,

@@ -176,0 +178,0 @@ drop: _actionCreators.drop,

@@ -70,3 +70,3 @@ 'use strict';

var _placeholder = require('./placeholder');
var _placeholder = require('../placeholder');

@@ -127,3 +127,5 @@ var _placeholder2 = _interopRequireDefault(_placeholder);

lift(draggableId, type, client, page, windowScroll);
var isScrollAllowed = true;
lift(draggableId, type, client, page, windowScroll, isScrollAllowed);
};

@@ -152,3 +154,5 @@

lift(draggableId, type, client, page, windowScroll);
var isScrollAllowed = false;
lift(draggableId, type, client, page, windowScroll, isScrollAllowed);
};

@@ -184,2 +188,12 @@

_this.onCrossAxisMoveForward = function () {
_this.throwIfCannotDrag();
_this.props.crossAxisMoveForward(_this.props.draggableId);
};
_this.onCrossAxisMoveBackward = function () {
_this.throwIfCannotDrag();
_this.props.crossAxisMoveBackward(_this.props.draggableId);
};
_this.onWindowScroll = function () {

@@ -286,3 +300,3 @@ _this.throwIfCannotDrag();

_this.callbacks = {
var callbacks = {
onLift: _this.onLift,

@@ -295,4 +309,8 @@ onMove: _this.onMove,

onMoveForward: _this.onMoveForward,
onCrossAxisMoveForward: _this.onCrossAxisMoveForward,
onCrossAxisMoveBackward: _this.onCrossAxisMoveBackward,
onWindowScroll: _this.onWindowScroll
};
_this.callbacks = callbacks;
return _this;

@@ -299,0 +317,0 @@ }

@@ -55,5 +55,6 @@ 'use strict';

publish: _actionCreators.publishDroppableDimension,
updateScroll: _actionCreators.updateDroppableDimensionScroll
updateScroll: _actionCreators.updateDroppableDimensionScroll,
updateIsEnabled: _actionCreators.updateDroppableDimensionIsEnabled
};
exports.default = (0, _reactRedux.connect)(makeMapStateToProps, mapDispatchToProps, null, { storeKey: _contextKeys.storeKey })(_droppableDimensionPublisher2.default);

@@ -1,1 +0,3 @@

'use strict';
'use strict';
var _actionCreators = require('../../state/action-creators');

@@ -45,2 +45,6 @@ 'use strict';

var _getClientRect = require('../../state/get-client-rect');
var _getClientRect2 = _interopRequireDefault(_getClientRect);
var _dimension = require('../../state/dimension');

@@ -85,2 +89,3 @@

direction = _this$props.direction,
isDropDisabled = _this$props.isDropDisabled,
targetRef = _this$props.targetRef;

@@ -90,2 +95,3 @@

var scroll = _this.getScrollOffset();
var style = window.getComputedStyle(targetRef);

@@ -99,10 +105,43 @@

};
var padding = {
top: parseInt(style.paddingTop, 10),
right: parseInt(style.paddingRight, 10),
bottom: parseInt(style.paddingBottom, 10),
left: parseInt(style.paddingLeft, 10)
};
var clientRect = function () {
var current = targetRef.getBoundingClientRect();
if (!_this.closestScrollable) {
return current;
}
if (_this.closestScrollable === targetRef) {
return current;
}
var top = current.top + scroll.y;
var bottom = current.bottom + scroll.y;
var left = current.left + scroll.x;
var right = current.right + scroll.x;
var parent = _this.closestScrollable.getBoundingClientRect();
return (0, _getClientRect2.default)({
top: Math.max(top, parent.top),
left: Math.max(left, parent.left),
right: Math.min(right, parent.right),
bottom: Math.min(bottom, parent.bottom)
});
}();
var dimension = (0, _dimension.getDroppableDimension)({
id: droppableId,
direction: direction,
clientRect: targetRef.getBoundingClientRect(),
clientRect: clientRect,
margin: margin,
padding: padding,
windowScroll: (0, _getWindowScrollPosition2.default)(),
scroll: _this.getScrollOffset()
scroll: scroll,
isEnabled: !isDropDisabled
});

@@ -153,12 +192,8 @@

value: function componentWillReceiveProps(nextProps) {
if (nextProps.targetRef !== this.props.targetRef) {
if (this.isWatchingScroll) {
console.warn('changing targetRef while watching scroll!');
this.unwatchScroll();
}
}
var shouldPublish = !this.props.shouldPublish && nextProps.shouldPublish;
var shouldStartPublishing = !this.props.shouldPublish && nextProps.shouldPublish;
var alreadyPublishing = this.props.shouldPublish && nextProps.shouldPublish;
var stopPublishing = this.props.shouldPublish && !nextProps.shouldPublish;
if (!nextProps.shouldPublish) {
if (stopPublishing) {
this.unwatchScroll();

@@ -168,6 +203,21 @@ return;

if (!shouldPublish) {
if (alreadyPublishing) {
if (nextProps.targetRef !== this.props.targetRef) {
if (this.isWatchingScroll) {
console.warn('changing targetRef while watching scroll!');
this.unwatchScroll();
}
}
if (nextProps.isDropDisabled !== this.props.isDropDisabled) {
this.props.updateIsEnabled(this.props.droppableId, !nextProps.isDropDisabled);
}
return;
}
if (!shouldStartPublishing) {
return;
}
this.closestScrollable = (0, _getClosestScrollable2.default)(this.props.targetRef);

@@ -174,0 +224,0 @@ this.props.publish(this.getDimension());

@@ -41,11 +41,40 @@ 'use strict';

var getMapProps = (0, _memoizeOne2.default)(function (isDraggingOver) {
var memoizedPlaceholder = (0, _memoizeOne2.default)(function (width, height) {
return {
isDraggingOver: isDraggingOver
width: width, height: height
};
});
return (0, _reselect.createSelector)([_selectors.phaseSelector, _selectors.dragSelector, _selectors.pendingDropSelector, idSelector, isDropDisabledSelector], function (phase, drag, pending, id, isDropDisabled) {
var getPlaceholder = (0, _memoizeOne2.default)(function (id, source, destination, draggable) {
if (!destination) {
return null;
}
if (destination.droppableId !== id) {
return null;
}
if (source.droppableId === destination.droppableId) {
return null;
}
if (!draggable) {
return null;
}
var placeholder = memoizedPlaceholder(draggable.page.withMargin.width, draggable.page.withMargin.height);
return placeholder;
});
var getMapProps = (0, _memoizeOne2.default)(function (isDraggingOver, placeholder) {
return {
isDraggingOver: isDraggingOver,
placeholder: placeholder
};
});
return (0, _reselect.createSelector)([_selectors.phaseSelector, _selectors.dragSelector, _selectors.draggingDraggableSelector, _selectors.pendingDropSelector, idSelector, isDropDisabledSelector], function (phase, drag, draggable, pending, id, isDropDisabled) {
if (isDropDisabled) {
return getMapProps(false);
return getMapProps(false, null);
}

@@ -56,7 +85,9 @@

console.error('cannot determine dragging over as there is not drag');
return getMapProps(false);
return getMapProps(false, null);
}
var isDraggingOver = getIsDraggingOver(id, drag.impact.destination);
return getMapProps(isDraggingOver);
var placeholder = getPlaceholder(id, drag.initial.source, drag.impact.destination, draggable);
return getMapProps(isDraggingOver, placeholder);
}

@@ -67,10 +98,11 @@

console.error('cannot determine dragging over as there is no pending result');
return getMapProps(false);
return getMapProps(false, null);
}
var _isDraggingOver = getIsDraggingOver(id, pending.impact.destination);
return getMapProps(_isDraggingOver);
var _placeholder = getPlaceholder(id, pending.result.source, pending.result.destination, draggable);
return getMapProps(_isDraggingOver, _placeholder);
}
return getMapProps(false);
return getMapProps(false, null);
});

@@ -77,0 +109,0 @@ };

@@ -43,2 +43,6 @@ 'use strict';

var _placeholder = require('../placeholder/');
var _placeholder2 = _interopRequireDefault(_placeholder);
var _contextKeys = require('../context-keys');

@@ -86,9 +90,30 @@

}, {
key: 'getPlaceholder',
value: function getPlaceholder() {
if (!this.props.placeholder) {
return null;
}
return _react2.default.createElement(_placeholder2.default, {
height: this.props.placeholder.height,
width: this.props.placeholder.width
});
}
}, {
key: 'render',
value: function render() {
var _props = this.props,
children = _props.children,
direction = _props.direction,
droppableId = _props.droppableId,
isDraggingOver = _props.isDraggingOver,
isDropDisabled = _props.isDropDisabled,
type = _props.type;
var provided = {
innerRef: this.setRef
innerRef: this.setRef,
placeholder: this.getPlaceholder()
};
var snapshot = {
isDraggingOver: this.props.isDraggingOver
isDraggingOver: isDraggingOver
};

@@ -99,8 +124,9 @@

{
droppableId: this.props.droppableId,
direction: this.props.direction,
type: this.props.type,
droppableId: droppableId,
direction: direction,
isDropDisabled: isDropDisabled,
type: type,
targetRef: this.state.ref
},
this.props.children(provided, snapshot)
children(provided, snapshot)
);

@@ -107,0 +133,0 @@ }

@@ -6,10 +6,12 @@ 'use strict';

});
exports.default = undefined;
var _placeholder = require('./placeholder');
var _placeholder2 = _interopRequireDefault(_placeholder);
Object.defineProperty(exports, 'default', {
enumerable: true,
get: function get() {
return _interopRequireDefault(_placeholder).default;
}
});
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.default = _placeholder2.default;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
{
"name": "react-beautiful-dnd",
"version": "2.1.1",
"version": "2.2.0",
"description": "Beautiful, accessible drag and drop for lists with React.js",

@@ -73,3 +73,3 @@ "author": "Alex Reardon <areardon@atlassian.com>",

"peerDependencies": {
"react": "15.6.1"
"react": ">=15.4.0"
},

@@ -76,0 +76,0 @@ "license": "Apache-2.0",

@@ -37,6 +37,6 @@ # react-beautiful-dnd

- Mouse 🐭 and **keyboard 🎹** dragging
- Independent nested lists (list can be a child of another list, but you cannot drag items from the parent list into a child list)
- Flexible height items (the draggable items can have different heights)
- Custom drag handle (you can drag a whole item by just a part of it)
- The vertical list can be a scroll container (without a scrollable parent) or be the child of a scroll container (that also does not have a scrollable parent)
- Independent nested lists - a list can be a child of another list, but you cannot drag items from the parent list into a child list
- Flexible item sizes - the draggable items can have different heights (vertical) or widths (horizontal))
- Custom drag handle - you can drag a whole item by just a part of it
- A droppable list can be a scroll container (without a scrollable parent) or be the child of a scroll container (that also does not have a scrollable parent)
- Server side rendering compatible

@@ -147,2 +147,3 @@

))}
{provided.placeholder}
</div>

@@ -395,3 +396,3 @@ )}

**Block updates during a drag**
#### Block updates during a drag

@@ -410,9 +411,4 @@ It is **highly** recommended that while a user is dragging that you block any state updates that might impact the amount of `Draggable`s and `Droppable`s, or their dimensions. Please listen to `onDragStart` and block updates to the `Draggable`s and `Droppable`s until you receive at `onDragEnd`.

#### Add a cursor style and block selection
**`onDragStart` and `onDragEnd` pairing**
We try very hard to ensure that each `onDragStart` event is paired with a single `onDragEnd` event. However, there maybe a rouge situation where this is not the case. If that occurs - it is a bug. Currently there is no mechanism to tell the library to cancel a current drag externally.
**Style**
During a drag it is recommended that you add two styles to the body:

@@ -427,5 +423,20 @@

#### Force focus after a transition between lists
When an item is moved from one list to a different list it looses browser focus if it had it. This is because `React` creates a new node in this situation. It will not loose focus if transitioned within the same list. The dragging item will always have had browser focus if it is dragging with a keyboard. It is highly recommended that you give the item (which is now in a different list) focus again. You can see an example of how to do this in our stories. Here is an example of how you could do it:
- `onDragEnd`: move the item into the new list and record the id fo the item that has moved
- When rendering the reordered list pass down a prop which will tell the newly moved item to obtain focus
- In the `componentDidMount` lifecycle call back check if the item needs to gain focus based on its props (such as an `autoFocus` prop)
- If focus is required - call `.focus` on the node. You can obtain the node by using `ReactDOM.findDOMNode` or monkey patching the `provided.innerRef` callback.
### Other `hooks` information
**`onDragStart` and `onDragEnd` pairing**
We try very hard to ensure that each `onDragStart` event is paired with a single `onDragEnd` event. However, there maybe a rouge situation where this is not the case. If that occurs - it is a bug. Currently there is no mechanism to tell the library to cancel a current drag externally.
**Dynamic hooks**
Your *hook* functions will only be captured *once at start up*. Please do not change the function after that. If there is a valid use case for this then dynamic hooks could be supported. However, at this time it is not.
Your *hook* functions will only be captured *once at start up*. Please do not change the function after that. This behaviour will be changed soon to allow dynamic hooks.

@@ -445,3 +456,4 @@ ## `Droppable`

>
I am a droppable!
<h2>I am a droppable!</h2>
{provided.placeholder}
</div>

@@ -477,10 +489,19 @@ )}

innerRef: (?HTMLElement) => void,
placeholder: ?ReactElement,
|}
```
In order for the droppable to function correctly, **you must** bind the `provided.innerRef` to the highest possible DOM node in the `ReactElement`. We do this in order to avoid needing to use `ReactDOM` to look up your DOM node.
- `provided.innerRef`: In order for the droppable to function correctly, **you must** bind the `provided.innerRef` to the highest possible DOM node in the `ReactElement`. We do this in order to avoid needing to use `ReactDOM` to look up your DOM node.
- `provided.placeholder`: This is used to create space in the `Droppable` as needed during a drag. This space is needed when a user is dragging over a list that is not the home list. Please be sure to put the placeholder inside of the component that you have provided the ref for. We need to increase the side of the `Droppable` itself. This is different from `Draggable` where the `placeholder` needs to be a *silbing* to the draggable node.
```js
<Droppable droppableId="droppable-1">
{(provided, snapshot) => <div ref={provided.innerRef}>Good to go</div>}
{(provided, snapshot) => (
<div ref={provided.innerRef}>
Good to go
{provided.placeholder}
</div>
)}
</Droppable>;

@@ -507,2 +528,4 @@ ```

I am a droppable!
{provided.placeholder}
</div>

@@ -692,3 +715,3 @@ )}

- `provided.placeholder (?ReactElement)` The `Draggable` element has `position: fixed` applied to it while it is dragging. The role of the `placeholder` is to sit in the place that the `Draggable` was during a drag. It is needed to stop the `Droppable` list from collapsing when you drag. It is advised to render it as a sibling to the `Draggable` node. When the library moves to `React` 16 the `placeholder` will be removed from api.
- `provided.placeholder (?ReactElement)` The `Draggable` element has `position: fixed` applied to it while it is dragging. The role of the `placeholder` is to sit in the place that the `Draggable` was during a drag. It is needed to stop the `Droppable` list from collapsing when you drag. It is advised to render it as a sibling to the `Draggable` node. This is unlike `Droppable` where the `placeholder` needs to be *within* the `Droppable` node. When the library moves to `React` 16 the `placeholder` will be removed from api.

@@ -868,4 +891,9 @@ ```js

innerRef: (?HTMLElement) => void,
placeholder: ?ReactElement,
|}
type DraggableStateSnapshot = {|
isDraggingOver: boolean,
|}
// Draggable

@@ -878,2 +906,7 @@ type DraggableProvided = {|

|}
type DraggableStateSnapshot = {|
isDragging: boolean,
|}
type DraggableStyle = DraggingStyle | NotDraggingStyle

@@ -880,0 +913,0 @@ type DraggingStyle = {|

@@ -19,3 +19,3 @@ // @flow

import noImpact from './no-impact';
import getNewHomeClientOffset from './get-new-home-client-offset';
import getNewHomeClientCenter from './get-new-home-client-center';
import { add, subtract, isEqual } from './position';

@@ -25,12 +25,13 @@

type ScrollDiffResult = {|
droppable: Position,
window: Position,
type ScrollDiffArgs = {|
initial: InitialDrag,
current: CurrentDrag,
droppable: ?DroppableDimension
|}
const getScrollDiff = (
initial: InitialDrag,
current: CurrentDrag,
droppable: DroppableDimension
): ScrollDiffResult => {
const getScrollDiff = ({
initial,
current,
droppable,
}: ScrollDiffArgs): Position => {
const windowScrollDiff: Position = subtract(

@@ -40,11 +41,9 @@ initial.windowScroll,

);
const droppableScrollDiff: Position = subtract(
const droppableScrollDiff: Position = droppable ? subtract(
droppable.scroll.initial,
droppable.scroll.current
);
) : origin;
return {
window: windowScrollDiff,
droppable: droppableScrollDiff,
};
return add(windowScrollDiff, droppableScrollDiff);
};

@@ -78,2 +77,3 @@

windowScroll: Position,
isScrollAllowed: boolean,
|}

@@ -87,2 +87,3 @@ |}

windowScroll: Position,
isScrollAllowed: boolean,
): CompleteLiftAction => ({

@@ -96,2 +97,3 @@ type: 'COMPLETE_LIFT',

windowScroll,
isScrollAllowed,
},

@@ -139,2 +141,19 @@ });

export type UpdateDroppableDimensionIsEnabledAction = {|
type: 'UPDATE_DROPPABLE_DIMENSION_IS_ENABLED',
payload: {
id: DroppableId,
isEnabled: boolean,
}
|}
export const updateDroppableDimensionIsEnabled =
(id: DroppableId, isEnabled: boolean): UpdateDroppableDimensionIsEnabledAction => ({
type: 'UPDATE_DROPPABLE_DIMENSION_IS_ENABLED',
payload: {
id,
isEnabled,
},
});
export type MoveAction = {|

@@ -200,2 +219,22 @@ type: 'MOVE',

export type CrossAxisMoveForwardAction = {|
type: 'CROSS_AXIS_MOVE_FORWARD',
payload: DraggableId
|}
export const crossAxisMoveForward = (id: DraggableId): CrossAxisMoveForwardAction => ({
type: 'CROSS_AXIS_MOVE_FORWARD',
payload: id,
});
export type CrossAxisMoveBackwardAction = {|
type: 'CROSS_AXIS_MOVE_BACKWARD',
payload: DraggableId
|}
export const crossAxisMoveBackward = (id: DraggableId): CrossAxisMoveBackwardAction => ({
type: 'CROSS_AXIS_MOVE_BACKWARD',
payload: id,
});
type CleanAction = {

@@ -280,7 +319,6 @@ type: 'CLEAN',

const { impact, initial, current } = state.drag;
const sourceDroppable: DroppableDimension =
state.dimension.droppable[initial.source.droppableId];
const destinationDroppable: ?DroppableDimension = impact.destination ?
const droppable: ?DroppableDimension = impact.destination ?
state.dimension.droppable[impact.destination.droppableId] :
null;
const draggable: DraggableDimension = state.dimension.draggable[current.id];

@@ -294,18 +332,13 @@ const result: DropResult = {

const scrollDiff = getScrollDiff(
initial,
current,
sourceDroppable,
);
const newHomeOffset: Position = getNewHomeClientOffset({
const newCenter: Position = getNewHomeClientCenter({
movement: impact.movement,
clientOffset: current.client.offset,
pageOffset: current.page.offset,
droppableScrollDiff: scrollDiff.droppable,
windowScrollDiff: scrollDiff.window,
draggable,
draggables: state.dimension.draggable,
axis: destinationDroppable ? destinationDroppable.axis : null,
destination: droppable,
});
const clientOffset: Position = subtract(newCenter, draggable.client.withMargin.center);
const scrollDiff: Position = getScrollDiff({ initial, current, droppable });
const newHomeOffset: Position = add(clientOffset, scrollDiff);
// Do not animate if you do not need to.

@@ -366,7 +399,7 @@ // This will be the case if either you are dragging with a

const scrollDiff = getScrollDiff(initial, current, droppable);
const scrollDiff: Position = getScrollDiff({ initial, current, droppable });
dispatch(animateDrop({
trigger: 'CANCEL',
newHomeOffset: add(scrollDiff.droppable, scrollDiff.window),
newHomeOffset: scrollDiff,
impact: noImpact,

@@ -404,2 +437,3 @@ result,

windowScroll: Position,
isScrollAllowed: boolean,
|}

@@ -414,2 +448,3 @@ |}

windowScroll: Position,
isScrollAllowed: boolean,
) => (dispatch: Dispatch, getState: Function) => {

@@ -452,3 +487,3 @@ (() => {

}
dispatch(completeLift(id, type, client, page, windowScroll));
dispatch(completeLift(id, type, client, page, windowScroll, isScrollAllowed));
});

@@ -466,4 +501,6 @@ });

MoveForwardAction |
CrossAxisMoveForwardAction |
CrossAxisMoveBackwardAction |
DropAnimateAction |
DropCompleteAction |
CleanAction;

@@ -7,5 +7,9 @@ // @flow

line: 'y',
crossLine: 'x',
start: 'top',
end: 'bottom',
size: 'height',
crossAxisStart: 'left',
crossAxisEnd: 'right',
crossAxisSize: 'width',
};

@@ -16,5 +20,9 @@

line: 'x',
crossLine: 'y',
start: 'left',
end: 'right',
size: 'width',
crossAxisStart: 'top',
crossAxisEnd: 'bottom',
crossAxisSize: 'height',
};
// @flow
import { vertical, horizontal } from './axis';
import getClientRect from './get-client-rect';
import type {

@@ -11,23 +12,9 @@ DroppableId,

DimensionFragment,
Spacing,
ClientRect,
} from '../types';
export type ClientRect = {|
top: number,
right: number,
bottom: number,
left: number,
width: number,
height: number,
|}
export type Margin = {|
top: number,
right: number,
bottom: number,
left: number,
|}
const origin: Position = { x: 0, y: 0 };
export const noMargin: Margin = {
export const noSpacing: Spacing = {
top: 0,

@@ -40,4 +27,4 @@ right: 0,

const getWithPosition = (clientRect: ClientRect, point: Position): ClientRect => {
const { top, right, bottom, left, width, height } = clientRect;
return {
const { top, right, bottom, left } = clientRect;
return getClientRect({
top: top + point.y,

@@ -47,17 +34,13 @@ left: left + point.x,

right: right + point.x,
height,
width,
};
});
};
const getWithMargin = (clientRect: ClientRect, margin: Margin): ClientRect => {
const { top, right, bottom, left, height, width } = clientRect;
return {
top: top + margin.top,
left: left + margin.left,
bottom: bottom + margin.bottom,
right: right + margin.right,
height: height + margin.top + margin.bottom,
width: width + margin.left + margin.right,
};
const getWithSpacing = (clientRect: ClientRect, spacing: Spacing): ClientRect => {
const { top, right, bottom, left } = clientRect;
return getClientRect({
top: top + spacing.top,
left: left + spacing.left,
bottom: bottom + spacing.bottom,
right: right + spacing.right,
});
};

@@ -68,15 +51,24 @@

point?: Position = origin,
): DimensionFragment => ({
top: initial.top + point.y,
left: initial.left + point.x,
bottom: initial.bottom + point.y,
right: initial.right + point.x,
width: initial.width,
height: initial.height,
center: {
x: ((initial.right + point.x) + (initial.left + point.x)) / 2,
y: ((initial.bottom + point.y) + (initial.top + point.y)) / 2,
},
});
): DimensionFragment => {
const rect: ClientRect = getClientRect({
top: initial.top + point.y,
left: initial.left + point.x,
bottom: initial.bottom + point.y,
right: initial.right + point.x,
});
return {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left,
width: rect.width,
height: rect.height,
center: {
x: (rect.right + rect.left) / 2,
y: (rect.bottom + rect.top) / 2,
},
};
};
type GetDraggableArgs = {|

@@ -86,3 +78,3 @@ id: DraggableId,

clientRect: ClientRect,
margin?: Margin,
margin?: Spacing,
windowScroll?: Position,

@@ -95,7 +87,6 @@ |};

clientRect,
margin = noMargin,
margin = noSpacing,
windowScroll = origin,
}: GetDraggableArgs): DraggableDimension => {
const withScroll = getWithPosition(clientRect, windowScroll);
const withScrollAndMargin = getWithMargin(withScroll, margin);

@@ -108,3 +99,3 @@ const dimension: DraggableDimension = {

withoutMargin: getFragment(clientRect),
withMargin: getFragment(getWithMargin(clientRect, margin)),
withMargin: getFragment(getWithSpacing(clientRect, margin)),
},

@@ -114,3 +105,3 @@ // with scroll

withoutMargin: getFragment(withScroll),
withMargin: getFragment(withScrollAndMargin),
withMargin: getFragment(getWithSpacing(withScroll, margin)),
},

@@ -126,7 +117,18 @@ };

direction?: Direction,
margin?: Margin,
margin?: Spacing,
padding?: Spacing,
windowScroll?: Position,
scroll?: Position,
scroll ?: Position,
// Whether or not the droppable is currently enabled (can change at during a drag)
// defaults to true
isEnabled?: boolean,
|}
const add = (spacing1: Spacing, spacing2: Spacing): Spacing => ({
top: spacing1.top + spacing2.top,
left: spacing1.left + spacing2.left,
right: spacing1.right + spacing2.right,
bottom: spacing1.bottom + spacing2.bottom,
});
export const getDroppableDimension = ({

@@ -136,11 +138,14 @@ id,

direction = 'vertical',
margin = noMargin,
margin = noSpacing,
padding = noSpacing,
windowScroll = origin,
scroll = origin,
isEnabled = true,
}: GetDroppableArgs): DroppableDimension => {
const withMargin = getWithSpacing(clientRect, margin);
const withWindowScroll = getWithPosition(clientRect, windowScroll);
const withWindowScrollAndMargin = getWithMargin(withWindowScroll, margin);
const dimension: DroppableDimension = {
id,
isEnabled,
axis: direction === 'vertical' ? vertical : horizontal,

@@ -152,5 +157,11 @@ scroll: {

},
client: {
withoutMargin: getFragment(clientRect),
withMargin: getFragment(withMargin),
withMarginAndPadding: getFragment(getWithSpacing(withMargin, padding)),
},
page: {
withoutMargin: getFragment(withWindowScroll),
withMargin: getFragment(withWindowScrollAndMargin),
withMargin: getFragment(getWithSpacing(withWindowScroll, margin)),
withMarginAndPadding: getFragment(getWithSpacing(withWindowScroll, add(margin, padding))),
},

@@ -157,0 +168,0 @@ };

@@ -18,4 +18,22 @@ // @flow

import getDraggablesInsideDroppable from './get-draggables-inside-droppable';
import noImpact from './no-impact';
import noImpact, { noMovement } from './no-impact';
// Calculates the net scroll diff along the main axis
// between two droppables with internal scrolling
const getDroppablesScrollDiff = ({
sourceDroppable,
destinationDroppable,
line,
}: {
sourceDroppable: DroppableDimension,
destinationDroppable: DroppableDimension,
line: 'x' | 'y',
}): number => {
const sourceScrollDiff = sourceDroppable.scroll.initial[line] -
sourceDroppable.scroll.current[line];
const destinationScrollDiff = destinationDroppable.scroll.initial[line] -
destinationDroppable.scroll.current[line];
return destinationScrollDiff - sourceScrollDiff;
};
// It is the responsibility of this function

@@ -29,3 +47,5 @@ // to return the impact of a drag

withinDroppable: WithinDroppable,
// item being dragged
draggableId: DraggableId,
// all dimensions in system
draggables: DraggableDimensionMap,

@@ -51,12 +71,21 @@ droppables: DroppableDimensionMap

const newCenter = withinDroppable.center;
const draggingDimension: DraggableDimension = draggables[draggableId];
const droppableDimension: DroppableDimension = droppables[droppableId];
const droppable: DroppableDimension = droppables[droppableId];
const axis: Axis = droppable.axis;
if (!droppable.isEnabled) {
return {
movement: noMovement,
direction: axis.direction,
destination: null,
};
}
const insideDroppable: DraggableDimension[] = getDraggablesInsideDroppable(
droppableDimension,
droppable,
draggables,
);
const axis: Axis = droppableDimension.axis;
const newCenter: Position = withinDroppable.center;
const draggingDimension: DraggableDimension = draggables[draggableId];
const isWithinHomeDroppable = draggingDimension.droppableId === droppableId;

@@ -66,2 +95,3 @@ // not considering margin so that items move based on visible edges

const isBeyondStartPosition: boolean = newCenter[axis.line] - draggableCenter[axis.line] > 0;
const shouldDisplaceItemsForward = isWithinHomeDroppable ? isBeyondStartPosition : false;

@@ -77,2 +107,13 @@ const moved: DraggableId[] = insideDroppable

// If we're over a new droppable items will be displaced
// if they sit ahead of the dragging item
if (!isWithinHomeDroppable) {
const scrollDiff = getDroppablesScrollDiff({
sourceDroppable: droppables[draggingDimension.droppableId],
destinationDroppable: droppable,
line: axis.line,
});
return (newCenter[axis.line] - scrollDiff) < fragment[axis.end];
}
if (isBeyondStartPosition) {

@@ -98,4 +139,16 @@ // 1. item needs to start ahead of the moving item

// Need to ensure that we always order by the closest impacted item
const ordered: DraggableId[] = (() => {
if (!isWithinHomeDroppable) {
return moved;
}
return isBeyondStartPosition ? moved.reverse() : moved;
})();
const startIndex = insideDroppable.indexOf(draggingDimension);
const index: number = (() => {
if (!isWithinHomeDroppable) {
return insideDroppable.length - moved.length;
}
if (!moved.length) {

@@ -121,4 +174,4 @@ return startIndex;

amount,
draggables: moved,
isBeyondStartPosition,
draggables: ordered,
isBeyondStartPosition: shouldDisplaceItemsForward,
};

@@ -125,0 +178,0 @@

// @flow
import memoizeOne from 'memoize-one';
import type {
DraggableId,
DraggableDimension,
DroppableDimension,
DraggableDimensionMap,
DraggableId,
} from '../types';
export default memoizeOne(
(droppableDimension: DroppableDimension,
draggableDimensions: DraggableDimensionMap,
(droppable: DroppableDimension,
draggables: DraggableDimensionMap,
): DraggableDimension[] =>
Object.keys(draggableDimensions)
.map((key: DraggableId): DraggableDimension => draggableDimensions[key])
.filter((dimension: DraggableDimension): boolean =>
dimension.droppableId === droppableDimension.id
)
Object.keys(draggables)
.map((id: DraggableId): DraggableDimension => draggables[id])
.filter((draggable: DraggableDimension): boolean => (
droppable.id === draggable.droppableId
))
// Dimensions are not guarenteed to be ordered in the same order as keys
// So we need to sort them so they are in the correct order
.sort((a: DraggableDimension, b: DraggableDimension): number =>
a.page.withoutMargin.center[droppableDimension.axis.line] -
b.page.withoutMargin.center[droppableDimension.axis.line]
)
);
.sort((a: DraggableDimension, b: DraggableDimension): number => (
a.page.withoutMargin.center[droppable.axis.line] -
b.page.withoutMargin.center[droppable.axis.line]
))
);
// @flow
import type { DroppableId, Position, DroppableDimensionMap } from '../types';
import isInsideDroppable from './is-inside-droppable';
import { isPointWithin } from './is-within-visible-bounds-of-droppable';
import type {
DroppableId,
Position,
DroppableDimensionMap,
DroppableDimension,
} from '../types';

@@ -9,6 +14,10 @@ export default (

): ?DroppableId => {
const maybeId: ?DroppableId = Object.keys(droppables)
.find(key => isInsideDroppable(target, droppables[key]));
const maybe: ?DroppableDimension =
Object.keys(droppables)
.map((id: DroppableId): DroppableDimension => droppables[id])
.find((droppable: DroppableDimension): boolean => (
isPointWithin(droppable)(target)
));
return maybeId || null;
return maybe ? maybe.id : null;
};

@@ -6,3 +6,3 @@ // @flow

const noMovement: DragMovement = {
export const noMovement: DragMovement = {
draggables: [],

@@ -9,0 +9,0 @@ amount: origin,

@@ -23,6 +23,32 @@ // @flow

export const patch = (line: 'x' | 'y', value: number): Position => ({
x: line === 'x' ? value : 0,
y: line === 'y' ? value : 0,
export const absolute = (point: Position): Position => ({
x: Math.abs(point.x),
y: Math.abs(point.y),
});
// Allows you to build a position from values.
// Really useful when working with the Axis type
// patch('x', 5) = { x: 5, y: 0 }
// patch('y', 5, 1) = { x: 1, y: 5 }
export const patch = (
line: 'x' | 'y',
value: number,
otherValue?: number = 0
): Position => ({
// set the value of 'x', or 'y'
[line]: value,
// set the value of the other line
[line === 'x' ? 'y' : 'x']: otherValue,
});
// Returns the distance between two points
// https://www.mathsisfun.com/algebra/distance-2-points.html
export const distance = (point1: Position, point2: Position): number =>
Math.sqrt(
Math.pow((point2.x - point1.x), 2) +
Math.pow((point2.y - point1.y), 2)
);
// When given a list of points, it finds the smallest distance to any point
export const closest = (target: Position, points: Position[]): number =>
Math.min(...points.map((point: Position) => distance(target, point)));

@@ -8,3 +8,5 @@ // @flow

DroppableDimension,
DraggableDimensionMap,
DroppableId,
DraggableId,
DimensionState,

@@ -23,7 +25,9 @@ DragImpact,

} from '../types';
import getInitialImpact from './get-initial-impact';
import { add, subtract, negate } from './position';
import getDragImpact from './get-drag-impact';
import jumpToNextIndex from './jump-to-next-index';
import type { JumpToNextResult } from './jump-to-next-index';
import getDroppableOver from './get-droppable-over';
import moveToNextIndex from './move-to-next-index/';
import type { Result as MoveToNextResult } from './move-to-next-index/move-to-next-index-types';
import type { Result as MoveCrossAxisResult } from './move-cross-axis/move-cross-axis-types';
import moveCrossAxis from './move-cross-axis/';

@@ -117,2 +121,3 @@ const noDimensions: DimensionState = {

type: previous.type,
isScrollAllowed: previous.isScrollAllowed,
client,

@@ -232,24 +237,24 @@ page,

const { id, type, client, page, windowScroll } = action.payload;
const { id, type, client, page, windowScroll, isScrollAllowed } = action.payload;
const draggables: DraggableDimensionMap = state.dimension.draggable;
const draggable: DraggableDimension = state.dimension.draggable[id];
const droppable: DroppableDimension = state.dimension.droppable[draggable.droppableId];
// no scroll diff yet so withinDroppable is just the center position
const withinDroppable: WithinDroppable = {
center: page.center,
};
const impact: DragImpact = getDragImpact({
page: page.selection,
withinDroppable,
draggableId: id,
draggables: state.dimension.draggable,
droppables: state.dimension.droppable,
const impact: ?DragImpact = getInitialImpact({
draggable,
droppable,
draggables,
});
const source: ?DraggableLocation = impact.destination;
if (!source) {
console.error('lifting a draggable that is not inside a droppable');
if (!impact || !impact.destination) {
console.error('invalid lift state');
return clean();
}
const source: DraggableLocation = impact.destination;
const withinDroppable: WithinDroppable = {
center: page.center,
};
const initial: InitialDrag = {

@@ -278,2 +283,3 @@ source,

windowScroll,
isScrollAllowed,
shouldAnimate: false,

@@ -304,2 +310,10 @@ };

// Currently not supporting container scrolling while dragging with a keyboard
// We do not store whether we are dragging with a keyboard in the state but this flag
// does this trick. Ideally this check would not exist.
// Kill the drag instantly
if (!state.drag.current.isScrollAllowed) {
return clean();
}
const { id, offset } = action.payload;

@@ -346,2 +360,37 @@

if (action.type === 'UPDATE_DROPPABLE_DIMENSION_IS_ENABLED') {
if (!Object.keys(state.dimension.droppable).length) {
return state;
}
const { id, isEnabled } = action.payload;
const target = state.dimension.droppable[id];
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;
}
const updatedDroppableDimension = {
...target,
isEnabled,
};
return {
...state,
dimension: {
...state.dimension,
droppable: {
...state.dimension.droppable,
[id]: updatedDroppableDimension,
},
},
};
}
if (action.type === 'MOVE') {

@@ -406,8 +455,17 @@ const { client, page, windowScroll } = action.payload;

const result: ?JumpToNextResult = jumpToNextIndex({
if (!existing.impact.destination) {
console.error('cannot move if there is no previous destination');
return clean();
}
const droppable: DroppableDimension = state.dimension.droppable[
existing.impact.destination.droppableId
];
const result: ?MoveToNextResult = moveToNextIndex({
isMovingForward,
draggableId: existing.current.id,
impact: existing.impact,
droppable,
draggables: state.dimension.draggable,
droppables: state.dimension.droppable,
});

@@ -420,24 +478,59 @@

const diff: Position = result.diff;
const impact: DragImpact = result.impact;
const page: Position = result.pageCenter;
const client: Position = subtract(page, existing.current.windowScroll);
const page: Position = add(existing.current.page.selection, diff);
const client: Position = add(existing.current.client.selection, diff);
return move({
state,
impact,
clientSelection: client,
pageSelection: page,
shouldAnimate: true,
});
}
// current limitation: cannot go beyond visible border of list
const droppableId: ?DroppableId = getDroppableOver(
page, state.dimension.droppable,
);
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 (!droppableId) {
// eslint-disable-next-line no-console
console.info('currently not supporting moving a draggable outside the visibility bounds of a droppable');
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();
}
const current: CurrentDrag = state.drag.current;
const draggableId: DraggableId = current.id;
const center: Position = current.page.center;
const droppableId: DroppableId = state.drag.impact.destination.droppableId;
const home: DraggableLocation = state.drag.initial.source;
const result: ?MoveCrossAxisResult = moveCrossAxis({
isMovingForward: action.type === 'CROSS_AXIS_MOVE_FORWARD',
pageCenter: center,
draggableId,
droppableId,
home,
draggables: state.dimension.draggable,
droppables: state.dimension.droppable,
});
if (!result) {
return state;
}
const page: Position = result.pageCenter;
const client: Position = subtract(page, current.windowScroll);
return move({
state,
impact,
clientSelection: client,
pageSelection: page,
impact: result.impact,
shouldAnimate: true,

@@ -444,0 +537,0 @@ });

// @flow
import { createSelector } from 'reselect';
import type {
PendingDrop,
DragState,
DraggableDimension,
DraggableDimensionMap,
Phase,

@@ -19,1 +22,41 @@ State,

export const dragSelector = (state: State): ?DragState => state.drag;
const draggableMapSelector = (state: State): DraggableDimensionMap => state.dimension.draggable;
export const draggingDraggableSelector = createSelector([
phaseSelector,
dragSelector,
pendingDropSelector,
draggableMapSelector,
], (phase: Phase,
drag: ?DragState,
pending: ?PendingDrop,
draggables: DraggableDimensionMap
): ?DraggableDimension => {
if (phase === 'DRAGGING') {
if (!drag) {
console.error('cannot get placeholder dimensions as there is an invalid drag state');
return null;
}
const draggable: DraggableDimension = draggables[drag.current.id];
return draggable;
}
if (phase === 'DROP_ANIMATING') {
if (!pending) {
console.error('cannot get placeholder dimensions as there is an invalid drag state');
return null;
}
if (!pending.result.destination) {
return null;
}
const draggable: DraggableDimension = draggables[pending.result.draggableId];
return draggable;
}
return null;
}
);

@@ -16,2 +16,18 @@ // @flow

export type Spacing = {|
top: number,
right: number,
bottom: number,
left: number,
|}
export type ClientRect = {|
top: number,
right: number,
bottom: number,
left: number,
width: number,
height: number,
|}
export type Direction = 'horizontal' | 'vertical';

@@ -22,5 +38,9 @@

line: 'y',
crossLine: 'x',
start: 'top',
end: 'bottom',
size: 'height',
crossAxisStart: 'left',
crossAxisEnd: 'right',
crossAxisSize: 'width',
|}

@@ -31,5 +51,9 @@

line: 'x',
crossLine: 'y',
start: 'left',
end: 'right',
size: 'width',
crossAxisStart: 'top',
crossAxisEnd: 'bottom',
crossAxisSize: 'height',
|}

@@ -40,8 +64,3 @@

export type DimensionFragment = {|
top: number,
left: number,
bottom: number,
right: number,
width: number,
height: number,
...ClientRect,
center: Position,

@@ -53,10 +72,12 @@ |}

droppableId: DroppableId,
page: {|
// relative to the viewport when the drag started
client: {|
withMargin: DimensionFragment,
withoutMargin: DimensionFragment,
|},
client: {|
// relative to the whole page
page: {|
withMargin: DimensionFragment,
withoutMargin: DimensionFragment,
|}
|},
|}

@@ -67,2 +88,3 @@

axis: Axis,
isEnabled: boolean,
scroll: {|

@@ -72,6 +94,16 @@ initial: Position,

|},
// relative to the current viewport
client: {|
withMargin: DimensionFragment,
withoutMargin: DimensionFragment,
// the area in which content presses up against
withMarginAndPadding: DimensionFragment,
|},
// relative to the whole page
page: {|
withMargin: DimensionFragment,
withoutMargin: DimensionFragment,
|}
// the area in which content presses up against
withMarginAndPadding: DimensionFragment,
|},
|}

@@ -87,2 +119,4 @@ export type DraggableLocation = {|

export type DragMovement = {|
// The draggables that need to move in response to a drag.
// Ordered by closest draggable to the *current* location of the dragging item
draggables: DraggableId[],

@@ -98,3 +132,3 @@ amount: Position,

direction: ?Direction,
destination: ?DraggableLocation
destination: ?DraggableLocation,
|}

@@ -113,5 +147,5 @@

source: DraggableLocation,
// viewport
// relative to the viewport when the drag started
client: InitialDragLocation,
// viewport + window scroll
// viewport + window scroll (position relative to 0, 0)
page: InitialDragLocation,

@@ -138,2 +172,4 @@ // Storing scroll directly to support movement during a window scroll.

type: TypeId,
// whether scrolling is allowed - otherwise a scroll will cancel the drag
isScrollAllowed: boolean,
// viewport

@@ -148,2 +184,3 @@ client: CurrentDragLocation,

withinDroppable: WithinDroppable,
// whether or not movements should be animated
shouldAnimate: boolean,

@@ -165,3 +202,3 @@ |}

// may not have any destination (drag to nowhere)
destination: ?DraggableLocation
destination: ?DraggableLocation,
|}

@@ -168,0 +205,0 @@

@@ -12,2 +12,4 @@ import type { Position, Direction } from '../../types';

onMoveBackward: () => void,
onCrossAxisMoveForward: () => void,
onCrossAxisMoveBackward: () => void,
onDrop: () => void,

@@ -14,0 +16,0 @@ onCancel: () => void,

@@ -5,3 +5,3 @@ // @flow

import memoizeOne from 'memoize-one';
import rafScheduler from 'raf-schd';
import rafSchedule from 'raf-schd';
// Using keyCode's for consistent event pattern matching between

@@ -33,2 +33,7 @@ // React synthetic events as well as raw browser events.

type ExecuteBasedOnDirection = {|
vertical: () => void,
horizontal: () => void,
|}
export default class DragHandle extends Component {

@@ -65,15 +70,23 @@ /* eslint-disable react/sort-comp */

// scheduled functions
scheduleMove = rafScheduler((point: Position) => {
scheduleMove = rafSchedule((point: Position) => {
this.ifDragging(() => this.memoizedMove(point.x, point.y));
});
scheduleMoveForward = rafScheduler(() => {
scheduleMoveForward = rafSchedule(() => {
this.ifDragging(this.props.callbacks.onMoveForward);
})
scheduleMoveBackward = rafScheduler(() => {
scheduleMoveBackward = rafSchedule(() => {
this.ifDragging(this.props.callbacks.onMoveBackward);
});
scheduleWindowScrollMove = rafScheduler(() => {
scheduleCrossAxisMoveForward = rafSchedule(() => {
this.ifDragging(this.props.callbacks.onCrossAxisMoveForward);
})
scheduleCrossAxisMoveBackward = rafSchedule(() => {
this.ifDragging(this.props.callbacks.onCrossAxisMoveBackward);
});
scheduleWindowScrollMove = rafSchedule(() => {
this.ifDragging(this.props.callbacks.onWindowScroll);

@@ -243,2 +256,13 @@ });

executeBasedOnDirection = (fns: ExecuteBasedOnDirection) => {
if (!this.props.direction) {
console.error('cannot move based on direction when none is provided');
this.stopDragging(() => this.props.callbacks.onCancel());
return;
}
// eslint-disable-next-line no-unused-expressions
this.props.direction === 'vertical' ? fns.vertical() : fns.horizontal();
}
// window keyboard events are bound during a keyboard drag

@@ -305,20 +329,26 @@ // or after the user presses the mouse down

if (this.props.direction === 'vertical') {
if (event.keyCode === keyCodes.arrowDown) {
event.preventDefault();
this.scheduleMoveForward();
}
if (event.keyCode === keyCodes.arrowDown) {
event.preventDefault();
this.executeBasedOnDirection({
vertical: this.scheduleMoveForward,
horizontal: this.scheduleCrossAxisMoveForward,
});
return;
}
if (event.keyCode === keyCodes.arrowUp) {
event.preventDefault();
this.scheduleMoveBackward();
}
if (event.keyCode === keyCodes.arrowUp) {
event.preventDefault();
this.executeBasedOnDirection({
vertical: this.scheduleMoveBackward,
horizontal: this.scheduleCrossAxisMoveBackward,
});
return;
}
// horizontal dragging
if (event.keyCode === keyCodes.arrowRight) {
event.preventDefault();
this.scheduleMoveForward();
this.executeBasedOnDirection({
vertical: this.scheduleCrossAxisMoveForward,
horizontal: this.scheduleMoveForward,
});
return;

@@ -329,3 +359,6 @@ }

event.preventDefault();
this.scheduleMoveBackward();
this.executeBasedOnDirection({
vertical: this.scheduleCrossAxisMoveBackward,
horizontal: this.scheduleMoveBackward,
});
}

@@ -332,0 +365,0 @@ }

@@ -6,5 +6,3 @@ // @flow

import { getDraggableDimension } from '../../state/dimension';
// eslint-disable-next-line no-duplicate-imports
import type { Margin } from '../../state/dimension';
import type { DraggableDimension } from '../../types';
import type { DraggableDimension, Spacing } from '../../types';
import type { Props } from './draggable-dimension-publisher-types';

@@ -27,3 +25,3 @@

const margin: Margin = {
const margin: Spacing = {
top: parseInt(style.marginTop, 10),

@@ -30,0 +28,0 @@ right: parseInt(style.marginRight, 10),

@@ -18,2 +18,4 @@ // @flow

moveBackward as moveBackwardAction,
crossAxisMoveForward as crossAxisMoveForwardAction,
crossAxisMoveBackward as crossAxisMoveBackwardAction,
drop as dropAction,

@@ -232,4 +234,6 @@ cancel as cancelAction,

move: moveAction,
moveForward: moveForwardAction,
moveBackward: moveBackwardAction,
moveForward: moveForwardAction,
crossAxisMoveForward: crossAxisMoveForwardAction,
crossAxisMoveBackward: crossAxisMoveBackwardAction,
moveByWindowScroll: moveByWindowScrollAction,

@@ -236,0 +240,0 @@ drop: dropAction,

@@ -22,2 +22,4 @@ // @flow

moveBackward,
crossAxisMoveForward,
crossAxisMoveBackward,
drop,

@@ -101,2 +103,4 @@ cancel,

moveBackward: PropType<typeof moveBackward, Function>,
crossAxisMoveForward: PropType<typeof crossAxisMoveForward, Function>,
crossAxisMoveBackward: PropType<typeof crossAxisMoveBackward, Function>,
drop: PropType<typeof drop, Function>,

@@ -103,0 +107,0 @@ cancel: PropType<typeof cancel, Function>,

@@ -23,3 +23,3 @@ // @flow

import getCenterPosition from '../get-center-position';
import Placeholder from './placeholder';
import Placeholder from '../placeholder';
import { droppableIdKey } from '../context-keys';

@@ -73,3 +73,3 @@ import { add } from '../../state/position';

this.callbacks = {
const callbacks: DragHandleCallbacks = {
onLift: this.onLift,

@@ -82,4 +82,8 @@ onMove: this.onMove,

onMoveForward: this.onMoveForward,
onCrossAxisMoveForward: this.onCrossAxisMoveForward,
onCrossAxisMoveBackward: this.onCrossAxisMoveBackward,
onWindowScroll: this.onWindowScroll,
};
this.callbacks = callbacks;
}

@@ -123,3 +127,6 @@

lift(draggableId, type, client, page, windowScroll);
// Allowing scrolling with a mouse when lifting with a mouse
const isScrollAllowed = true;
lift(draggableId, type, client, page, windowScroll, isScrollAllowed);
}

@@ -145,4 +152,6 @@

};
// not allowing scrolling with a mouse when lifting with a keyboard
const isScrollAllowed = false;
lift(draggableId, type, client, page, windowScroll);
lift(draggableId, type, client, page, windowScroll, isScrollAllowed);
}

@@ -176,2 +185,12 @@

onCrossAxisMoveForward = () => {
this.throwIfCannotDrag();
this.props.crossAxisMoveForward(this.props.draggableId);
}
onCrossAxisMoveBackward = () => {
this.throwIfCannotDrag();
this.props.crossAxisMoveBackward(this.props.draggableId);
}
onWindowScroll = () => {

@@ -178,0 +197,0 @@ this.throwIfCannotDrag();

@@ -17,2 +17,3 @@ // @flow

updateDroppableDimensionScroll,
updateDroppableDimensionIsEnabled,
} from '../../state/action-creators';

@@ -47,2 +48,3 @@

updateScroll: updateDroppableDimensionScroll,
updateIsEnabled: updateDroppableDimensionIsEnabled,
};

@@ -49,0 +51,0 @@

// @flow
import type { PropType } from 'babel-plugin-react-flow-props-to-prop-types';
import {
publishDroppableDimension,
updateDroppableDimensionIsEnabled,
updateDroppableDimensionScroll,
} from '../../state/action-creators';
import type {
DroppableDimension,
DroppableId,

@@ -8,3 +13,2 @@ TypeId,

HTMLElement,
Position,
Direction,

@@ -18,4 +22,5 @@ } from '../../types';

export type DispatchProps = {|
publish: (dimension: DroppableDimension) => mixed,
updateScroll: (id: DroppableId, offset: Position) => mixed,
publish: PropType<typeof publishDroppableDimension, Function>,
updateIsEnabled: PropType<typeof updateDroppableDimensionIsEnabled, Function>,
updateScroll: PropType<typeof updateDroppableDimensionScroll, Function>,
|}

@@ -26,2 +31,3 @@

direction: Direction,
isDropDisabled: boolean,
type: TypeId,

@@ -32,3 +38,7 @@ targetRef: ?HTMLElement,

export type Props = MapProps & DispatchProps & OwnProps;
export type Props = {
...MapProps,
...DispatchProps,
...OwnProps
}

@@ -35,0 +45,0 @@ // Having issues getting the correct reselect type

@@ -7,7 +7,13 @@ // @flow

import getWindowScrollPosition from '../get-window-scroll-position';
import getClientRect from '../../state/get-client-rect';
import { getDroppableDimension } from '../../state/dimension';
import getClosestScrollable from '../get-closest-scrollable';
// eslint-disable-next-line no-duplicate-imports
import type { Margin } from '../../state/dimension';
import type { DroppableDimension, Position, HTMLElement } from '../../types';
import type {
DroppableDimension,
Position,
HTMLElement,
ClientRect,
Spacing,
} from '../../types';
import type { Props } from './droppable-dimension-publisher-types';

@@ -38,8 +44,11 @@

getDimension = (): DroppableDimension => {
const { droppableId, direction, targetRef } = this.props;
const { droppableId, direction, isDropDisabled, targetRef } = this.props;
invariant(targetRef, 'DimensionPublisher cannot calculate a dimension when not attached to the DOM');
const scroll: Position = this.getScrollOffset();
const style = window.getComputedStyle(targetRef);
const margin: Margin = {
// keeping it simple and always using the margin of the droppable
const margin: Spacing = {
top: parseInt(style.marginTop, 10),

@@ -50,10 +59,48 @@ right: parseInt(style.marginRight, 10),

};
const padding: Spacing = {
top: parseInt(style.paddingTop, 10),
right: parseInt(style.paddingRight, 10),
bottom: parseInt(style.paddingBottom, 10),
left: parseInt(style.paddingLeft, 10),
};
const clientRect: ClientRect = (() => {
const current: ClientRect = targetRef.getBoundingClientRect();
if (!this.closestScrollable) {
return current;
}
if (this.closestScrollable === targetRef) {
return current;
}
// We need to trim the dimension by the visible area of the scroll container
// Adjust the current dimension with the parents scroll
const top = current.top + scroll.y;
const bottom = current.bottom + scroll.y;
const left = current.left + scroll.x;
const right = current.right + scroll.x;
// Trim the dimension by the size of the parent
const parent: ClientRect = this.closestScrollable.getBoundingClientRect();
return getClientRect({
top: Math.max(top, parent.top),
left: Math.max(left, parent.left),
right: Math.min(right, parent.right),
bottom: Math.min(bottom, parent.bottom),
});
})();
const dimension: DroppableDimension = getDroppableDimension({
id: droppableId,
direction,
clientRect: targetRef.getBoundingClientRect(),
clientRect,
margin,
padding,
windowScroll: getWindowScrollPosition(),
scroll: this.getScrollOffset(),
scroll,
isEnabled: !isDropDisabled,
});

@@ -111,17 +158,12 @@

// TODO: componentDidUpdate?
componentWillReceiveProps(nextProps: Props) {
if (nextProps.targetRef !== this.props.targetRef) {
if (this.isWatchingScroll) {
console.warn('changing targetRef while watching scroll!');
this.unwatchScroll();
}
}
// Because the dimension publisher wraps children - it might render even when its props do
// not change. We need to ensure that it does not publish when it should not.
const shouldPublish = !this.props.shouldPublish && nextProps.shouldPublish;
const shouldStartPublishing = !this.props.shouldPublish && nextProps.shouldPublish;
const alreadyPublishing = this.props.shouldPublish && nextProps.shouldPublish;
const stopPublishing = this.props.shouldPublish && !nextProps.shouldPublish;
// should no longer watch for scrolling
if (!nextProps.shouldPublish) {
if (stopPublishing) {
this.unwatchScroll();

@@ -131,6 +173,26 @@ return;

if (!shouldPublish) {
if (alreadyPublishing) {
// if ref changes and watching scroll - unwatch the scroll
if (nextProps.targetRef !== this.props.targetRef) {
if (this.isWatchingScroll) {
console.warn('changing targetRef while watching scroll!');
this.unwatchScroll();
}
}
// publish any changes to the disabled flag
if (nextProps.isDropDisabled !== this.props.isDropDisabled) {
this.props.updateIsEnabled(this.props.droppableId, !nextProps.isDropDisabled);
}
return;
}
// This will be the default when nothing is happening
if (!shouldStartPublishing) {
return;
}
// Need to start publishing
// discovering the closest scrollable for a drag

@@ -137,0 +199,0 @@ this.closestScrollable = getClosestScrollable(this.props.targetRef);

@@ -6,3 +6,8 @@ // @flow

import { storeKey } from '../context-keys';
import { dragSelector, pendingDropSelector, phaseSelector } from '../../state/selectors';
import {
dragSelector,
pendingDropSelector,
phaseSelector,
draggingDraggableSelector,
} from '../../state/selectors';
import Droppable from './droppable';

@@ -16,2 +21,3 @@ import type {

DraggableLocation,
DraggableDimension,
} from '../../types';

@@ -22,2 +28,3 @@ import type {

Selector,
Placeholder,
} from './droppable-types';

@@ -40,9 +47,49 @@

const getMapProps = memoizeOne((isDraggingOver: boolean): MapProps => ({
isDraggingOver,
const memoizedPlaceholder = memoizeOne((width: number, height: number): Placeholder => ({
width, height,
}));
const getPlaceholder = memoizeOne(
(id: DroppableId,
source: DraggableLocation,
destination: ?DraggableLocation,
draggable: ?DraggableDimension
): ?Placeholder => {
if (!destination) {
return null;
}
// no placeholder needed for this droppable
if (destination.droppableId !== id) {
return null;
}
// no placeholder needed when dragging over the source list
if (source.droppableId === destination.droppableId) {
return null;
}
if (!draggable) {
return null;
}
const placeholder: Placeholder = memoizedPlaceholder(
draggable.page.withMargin.width,
draggable.page.withMargin.height,
);
return placeholder;
}
);
const getMapProps = memoizeOne(
(isDraggingOver: boolean, placeholder: ?Placeholder): MapProps => ({
isDraggingOver,
placeholder,
})
);
return createSelector(
[phaseSelector,
dragSelector,
draggingDraggableSelector,
pendingDropSelector,

@@ -54,2 +101,3 @@ idSelector,

drag: ?DragState,
draggable: ?DraggableDimension,
pending: ?PendingDrop,

@@ -60,3 +108,3 @@ id: DroppableId,

if (isDropDisabled) {
return getMapProps(false);
return getMapProps(false, null);
}

@@ -67,7 +115,14 @@

console.error('cannot determine dragging over as there is not drag');
return getMapProps(false);
return getMapProps(false, null);
}
const isDraggingOver = getIsDraggingOver(id, drag.impact.destination);
return getMapProps(isDraggingOver);
const placeholder: ?Placeholder = getPlaceholder(
id,
drag.initial.source,
drag.impact.destination,
draggable
);
return getMapProps(isDraggingOver, placeholder);
}

@@ -78,10 +133,16 @@

console.error('cannot determine dragging over as there is no pending result');
return getMapProps(false);
return getMapProps(false, null);
}
const isDraggingOver = getIsDraggingOver(id, pending.impact.destination);
return getMapProps(isDraggingOver);
const placeholder: ?Placeholder = getPlaceholder(
id,
pending.result.source,
pending.result.destination,
draggable
);
return getMapProps(isDraggingOver, placeholder);
}
return getMapProps(false);
return getMapProps(false, null);
},

@@ -88,0 +149,0 @@ );

@@ -14,4 +14,10 @@ // @flow

export type Placeholder = {|
height: number,
width: number,
|}
export type Provided = {|
innerRef: (?HTMLElement) => void,
placeholder: ?ReactElement,
|}

@@ -25,2 +31,6 @@

isDraggingOver: boolean,
// placeholder is used to hold space when
// not the user is dragging over a list that
// is not the source list
placeholder: ?Placeholder,
|}

@@ -27,0 +37,0 @@

@@ -6,2 +6,3 @@ import React, { Component } from 'react';

import DroppableDimensionPublisher from '../droppable-dimension-publisher/';
import Placeholder from '../placeholder/';
import { droppableIdKey } from '../context-keys';

@@ -64,8 +65,30 @@

getPlaceholder() {
if (!this.props.placeholder) {
return null;
}
return (
<Placeholder
height={this.props.placeholder.height}
width={this.props.placeholder.width}
/>
);
}
render() {
const {
children,
direction,
droppableId,
isDraggingOver,
isDropDisabled,
type,
} = this.props;
const provided: Provided = {
innerRef: this.setRef,
placeholder: this.getPlaceholder(),
};
const snapshot: StateSnapshot = {
isDraggingOver: this.props.isDraggingOver,
isDraggingOver,
};

@@ -75,8 +98,9 @@

<DroppableDimensionPublisher
droppableId={this.props.droppableId}
direction={this.props.direction}
type={this.props.type}
droppableId={droppableId}
direction={direction}
isDropDisabled={isDropDisabled}
type={type}
targetRef={this.state.ref}
>
{this.props.children(provided, snapshot)}
{children(provided, snapshot)}
</DroppableDimensionPublisher>

@@ -83,0 +107,0 @@ );

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc