@atlaskit/pragmatic-drag-and-drop-hitbox
Version:
An optional package for Pragmatic drag and drop that enables the attaching of interaction information to a drop target
153 lines (147 loc) • 5.6 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.attachInstruction = attachInstruction;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
var _isShallowEqual = require("./internal/isShallowEqual");
var _stable = require("./internal/stable");
var _treeItem = require("./tree-item");
var _excluded = ["block"];
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; }
function getCenter(rect) {
return {
x: (rect.right + rect.left) / 2,
y: (rect.bottom + rect.top) / 2
};
}
function standardHitbox(_ref) {
var client = _ref.client,
borderBox = _ref.borderBox;
var quarterOfHeight = borderBox.height / 4;
// In the top 1/4: reorder-above
// On the line = in the top 1/4 to give this zone a bit more space
if (client.y <= borderBox.top + quarterOfHeight) {
return 'reorder-above';
}
// In the bottom 1/4: reorder-below
// On the line = in the bottom 1/4 to give this zone a bit more space
if (client.y >= borderBox.bottom - quarterOfHeight) {
return 'reorder-below';
}
return 'make-child';
}
function getInstruction(_ref2) {
var element = _ref2.element,
input = _ref2.input,
currentLevel = _ref2.currentLevel,
indentPerLevel = _ref2.indentPerLevel,
mode = _ref2.mode;
var client = {
x: input.clientX,
y: input.clientY
};
var borderBox = element.getBoundingClientRect();
if (mode === 'standard') {
var type = standardHitbox({
borderBox: borderBox,
client: client
});
return {
type: type,
indentPerLevel: indentPerLevel,
currentLevel: currentLevel
};
}
var center = getCenter(borderBox);
if (mode === 'expanded') {
// leveraging "standard" hitbox to ensure that the 'reorder-above' hit zone is
// exactly the same for "standard" and "expanded" items
var _type = standardHitbox({
borderBox: borderBox,
client: client
});
return {
// Use the "standard" hitbox for "reorder above",
// The rest of the item is "make-child"
type: _type === 'reorder-above' ? _type : 'make-child',
indentPerLevel: indentPerLevel,
currentLevel: currentLevel
};
}
// `mode` is "last-in-group"
var visibleInset = indentPerLevel * currentLevel;
// Before the left edge of the visible item
if (client.x < borderBox.left + visibleInset) {
// Above the center: `reorder-above`
if (client.y < center.y) {
return {
type: 'reorder-above',
indentPerLevel: indentPerLevel,
currentLevel: currentLevel
};
}
// On or below the center: `reparent`
// On the center = `reparent` as we are giving a slightly bigger hitbox to this
// action as it is the only place a user can do it
var rawLevel = (client.x - borderBox.left) / indentPerLevel;
// We can get sub pixel negative numbers as getBoundingClientRect gives sub-pixel accuracy,
// where as clientX is rounded to the nearest pixel.
// Using Math.max() ensures we can never get a negative level
var desiredLevel = Math.max(Math.floor(rawLevel), 0);
return {
type: 'reparent',
desiredLevel: desiredLevel,
indentPerLevel: indentPerLevel,
currentLevel: currentLevel
};
}
// On the visible item
return {
type: standardHitbox({
borderBox: borderBox,
client: client
}),
indentPerLevel: indentPerLevel,
currentLevel: currentLevel
};
}
function areInstructionsEqual(a, b) {
// Shortcut
if (a.type !== b.type) {
return false;
}
if (a.type === 'instruction-blocked' && b.type === 'instruction-blocked') {
return areInstructionsEqual(a.desired, b.desired);
}
return (0, _isShallowEqual.isShallowEqual)(a, b);
}
// Note: not using `memoize-one` as all we need is a cached value.
// We do not need to avoid executing an expensive function.
var memoizeInstruction = (0, _stable.stable)(areInstructionsEqual);
function applyInstructionBlock(_ref3) {
var desired = _ref3.desired,
block = _ref3.block;
if (block !== null && block !== void 0 && block.includes(desired.type) && desired.type !== 'instruction-blocked') {
var blocked = {
type: 'instruction-blocked',
desired: desired
};
return blocked;
}
return desired;
}
function attachInstruction(userData, _ref4) {
var block = _ref4.block,
rest = (0, _objectWithoutProperties2.default)(_ref4, _excluded);
var desired = getInstruction(rest);
var withBlock = applyInstructionBlock({
desired: desired,
block: block
});
var memoized = memoizeInstruction(withBlock);
return _objectSpread(_objectSpread({}, userData), {}, (0, _defineProperty2.default)({}, _treeItem.uniqueKey, memoized));
}