@atlaskit/pragmatic-drag-and-drop-react-beautiful-dnd-migration
Version:
An optional Pragmatic drag and drop package that enables rapid migration from react-beautiful-dnd to Pragmatic drag and drop
330 lines (323 loc) • 12.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useKeyboardControls = useKeyboardControls;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = require("react");
var _bindEventListener = require("bind-event-listener");
var _attributes = require("../../utils/attributes");
var _findClosestScrollContainer = require("../../utils/find-closest-scroll-container");
var _findElement = require("../../utils/find-element");
var _getBestCrossAxisDroppable = require("../../utils/get-best-cross-axis-droppable");
var _getElementByDraggableLocation = require("../../utils/get-element-by-draggable-location");
var _draggableLocation = require("../draggable-location");
var _getDestination = require("../get-destination");
var _rbdInvariant = require("../rbd-invariant");
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
/**
* Finds the element's scroll container and scrolls it to the top.
*
* This is used for cross-axis drags to provide a consistent starting point
* in the list.
*
* The behavior differs to `react-beautiful-dnd` which would find the
* index closest to the current visual position. That was not preserved for
* performance cost reasons.
*/
function scrollToTop(element) {
var scrollContainer = (0, _findClosestScrollContainer.findClosestScrollContainer)(element);
if (!scrollContainer) {
return;
}
scrollContainer.scrollTo(0, 0);
}
var moveHandlers = {
mainAxis: {
prev: function prev(event, _ref) {
var dragController = _ref.dragController;
/**
* Preventing default to stop scrolling caused by arrow key press.
*/
event.preventDefault();
var dragState = dragController.getDragState();
(0, _rbdInvariant.rbdInvariant)(dragState.isDragging);
var sourceLocation = dragState.sourceLocation,
targetLocation = dragState.targetLocation;
if (!targetLocation) {
return;
}
if (targetLocation.index === 0) {
return;
}
var nextLocation = _objectSpread(_objectSpread({}, targetLocation), {}, {
index: targetLocation.index - 1
});
var nextDestination = (0, _getDestination.getActualDestination)({
start: sourceLocation,
target: nextLocation
});
/**
* There are two target indexes that correspond to a drop in the source location:
*
* 1. source.index (before the source, but after previous item)
* 2. source.index + 1 (after the source, but before next item)
*
* We decrement by 2 when going over the source location,
* so the user only perceives one of these indexes.
*/
if ((0, _draggableLocation.isSameLocation)(sourceLocation, nextDestination)) {
nextLocation.index = targetLocation.index - 2;
}
dragController.updateDrag({
targetLocation: nextLocation
});
},
next: function next(event, _ref2) {
var dragController = _ref2.dragController,
contextId = _ref2.contextId;
/**
* Preventing default to stop scrolling caused by arrow key press.
*/
event.preventDefault();
var dragState = dragController.getDragState();
(0, _rbdInvariant.rbdInvariant)(dragState.isDragging);
var sourceLocation = dragState.sourceLocation,
targetLocation = dragState.targetLocation;
if (!targetLocation) {
return;
}
/**
* Checks if we can move to the next position.
*
* Reasoning: if there is already a draggable with the current index,
* then it is a possible target.
*/
var element = (0, _getElementByDraggableLocation.getElementByDraggableLocation)(contextId, targetLocation);
/**
* This check is for virtual lists, and is a special case.
*
* When dragging, the element will unmount and we won't be able to find
* the element for that index.
*
* This means for virtual lists, the normal check (element check) will fail.
*/
var isSame = (0, _draggableLocation.isSameLocation)(sourceLocation, targetLocation);
if (!isSame && !element) {
return;
}
var nextLocation = _objectSpread(_objectSpread({}, targetLocation), {}, {
index: targetLocation.index + 1
});
var nextDestination = (0, _getDestination.getActualDestination)({
start: sourceLocation,
target: nextLocation
});
/**
* There are two target indexes that correspond to a drop in the source location:
*
* 1. source.index (before the source, but after previous item)
* 2. source.index + 1 (after the source, but before next item)
*
* We increment by 2 when going over the source location,
* so the user only perceives one of these indexes.
*/
if ((0, _draggableLocation.isSameLocation)(sourceLocation, nextDestination)) {
nextLocation.index = targetLocation.index + 2;
}
dragController.updateDrag({
targetLocation: nextLocation
});
}
},
crossAxis: {
prev: function prev(event, _ref3) {
var dragController = _ref3.dragController,
droppableRegistry = _ref3.droppableRegistry,
contextId = _ref3.contextId;
/**
* Preventing default to stop scrolling caused by arrow key press.
*/
event.preventDefault();
var dragState = dragController.getDragState();
(0, _rbdInvariant.rbdInvariant)(dragState.isDragging);
var targetLocation = dragState.targetLocation,
type = dragState.type;
if (!targetLocation) {
return;
}
var before = (0, _getBestCrossAxisDroppable.getBestCrossAxisDroppable)({
droppableId: targetLocation.droppableId,
type: type,
isMovingForward: false,
contextId: contextId,
droppableRegistry: droppableRegistry
});
if (!before) {
return;
}
scrollToTop(before);
var nextLocation = {
droppableId: (0, _attributes.getAttribute)(before, _attributes.attributes.droppable.id),
index: 0
};
dragController.updateDrag({
targetLocation: nextLocation
});
},
next: function next(event, _ref4) {
var dragController = _ref4.dragController,
droppableRegistry = _ref4.droppableRegistry,
contextId = _ref4.contextId;
/**
* Preventing default to stop scrolling caused by arrow key press.
*/
event.preventDefault();
var dragState = dragController.getDragState();
(0, _rbdInvariant.rbdInvariant)(dragState.isDragging);
var targetLocation = dragState.targetLocation,
type = dragState.type;
if (!targetLocation) {
return;
}
var after = (0, _getBestCrossAxisDroppable.getBestCrossAxisDroppable)({
droppableId: targetLocation.droppableId,
type: type,
isMovingForward: true,
contextId: contextId,
droppableRegistry: droppableRegistry
});
if (!after) {
return;
}
scrollToTop(after);
var nextLocation = {
droppableId: (0, _attributes.getAttribute)(after, _attributes.attributes.droppable.id),
index: 0
};
dragController.updateDrag({
targetLocation: nextLocation
});
}
}
};
function preventDefault(event) {
event.preventDefault();
}
/**
* These keys mostly have their default behavior prevented to stop scrolling.
*
* The tab key is prevented to lock focus in place.
*/
var commonKeyHandlers = {
PageUp: preventDefault,
PageDown: preventDefault,
Home: preventDefault,
End: preventDefault,
Enter: preventDefault,
Tab: preventDefault
};
/**
* Maps actions to keys.
*/
var keyHandlers = {
vertical: _objectSpread(_objectSpread({}, commonKeyHandlers), {}, {
ArrowUp: moveHandlers.mainAxis.prev,
ArrowDown: moveHandlers.mainAxis.next,
ArrowLeft: moveHandlers.crossAxis.prev,
ArrowRight: moveHandlers.crossAxis.next
}),
horizontal: _objectSpread(_objectSpread({}, commonKeyHandlers), {}, {
ArrowUp: moveHandlers.crossAxis.prev,
ArrowDown: moveHandlers.crossAxis.next,
ArrowLeft: moveHandlers.mainAxis.prev,
ArrowRight: moveHandlers.mainAxis.next
})
};
function useKeyboardControls(_ref5) {
var dragController = _ref5.dragController,
droppableRegistry = _ref5.droppableRegistry,
contextId = _ref5.contextId,
setKeyboardCleanupFn = _ref5.setKeyboardCleanupFn;
var startKeyboardDrag = (0, _react.useCallback)(function (_ref6) {
var startEvent = _ref6.event,
draggableId = _ref6.draggableId,
type = _ref6.type,
getSourceLocation = _ref6.getSourceLocation,
sourceElement = _ref6.sourceElement;
dragController.startDrag({
draggableId: draggableId,
type: type,
getSourceLocation: getSourceLocation,
sourceElement: sourceElement,
mode: 'SNAP'
});
var sourceLocation = getSourceLocation();
var droppable = (0, _findElement.getElement)({
attribute: _attributes.attributes.droppable.id,
value: sourceLocation.droppableId
});
var direction = (0, _attributes.getAttribute)(droppable, _attributes.customAttributes.droppable.direction);
(0, _rbdInvariant.rbdInvariant)(direction === 'vertical' || direction === 'horizontal');
function cancelDrag() {
dragController.stopDrag({
reason: 'CANCEL'
});
}
/**
* All of these events should cancel the drag.
*
* These events were taken from `react-beautiful-dnd`.
*/
var cancelBindings = ['mousedown', 'mouseup', 'click', 'touchstart', 'resize', 'wheel', 'visibilitychange'].map(function (type) {
return {
type: type,
listener: cancelDrag
};
});
var cleanupFn = (0, _bindEventListener.bindAll)(window, [{
type: 'keydown',
listener: function listener(event) {
var _keyHandlers$directio, _keyHandlers$directio2;
/**
* Ignores the keydown event which triggered the drag start,
* so it doesn't trigger an immediate drop.
*/
if (event === startEvent) {
return;
}
var _dragController$getDr = dragController.getDragState(),
isDragging = _dragController$getDr.isDragging;
if (!isDragging) {
return;
}
if (event.key === ' ') {
event.preventDefault();
dragController.stopDrag({
reason: 'DROP'
});
return;
}
if (event.key === 'Escape') {
event.preventDefault();
dragController.stopDrag({
reason: 'CANCEL'
});
return;
}
(_keyHandlers$directio = (_keyHandlers$directio2 = keyHandlers[direction])[event.key]) === null || _keyHandlers$directio === void 0 || _keyHandlers$directio.call(_keyHandlers$directio2, event, {
dragController: dragController,
droppableRegistry: droppableRegistry,
contextId: contextId
});
}
}].concat((0, _toConsumableArray2.default)(cancelBindings)));
setKeyboardCleanupFn(cleanupFn);
}, [contextId, dragController, droppableRegistry, setKeyboardCleanupFn]);
return {
startKeyboardDrag: startKeyboardDrag
};
}