UNPKG

@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
"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 }; }