@react-querybuilder/dnd
Version:
Drag-and-drop-enabled version of react-querybuilder (DnD-library-agnostic)
271 lines (270 loc) • 10.3 kB
JavaScript
import { add, findPath, getParentPath, group, insert, isAncestor, lc, pathsAreEqual } from "react-querybuilder";
//#region src/isHotkeyPressed.ts
/**
* Adapted from
* https://github.com/JohannesKlauss/react-hotkeys-hook/blob/bc55a281f1d212d09de786aeb5cd236c58d9531d/src/isHotkeyPressed.ts
* and
* https://github.com/JohannesKlauss/react-hotkeys-hook/blob/bc55a281f1d212d09de786aeb5cd236c58d9531d/src/parseHotkey.ts
*/
const reservedModifierKeywords = new Set([
"shift",
"alt",
"meta",
"mod",
"ctrl"
]);
const mappedKeys = {
esc: "escape",
return: "enter",
".": "period",
",": "comma",
"-": "slash",
" ": "space",
"`": "backquote",
"#": "backslash",
"+": "bracketright",
ShiftLeft: "shift",
ShiftRight: "shift",
AltLeft: "alt",
AltRight: "alt",
MetaLeft: "meta",
MetaRight: "meta",
OSLeft: "meta",
OSRight: "meta",
ControlLeft: "ctrl",
ControlRight: "ctrl"
};
const mapKey = (key) => lc((key && mappedKeys[key] || key || "").trim()).replace(/key|digit|numpad|arrow/, "");
const isHotkeyModifier = (key) => reservedModifierKeywords.has(key);
const keyAliases = {
"⌘": "meta",
cmd: "meta",
command: "meta",
"⊞": "meta",
win: "meta",
windows: "meta",
"⇧": "shift",
"⌥": "alt",
"⌃": "ctrl",
control: "ctrl"
};
(() => {
if (typeof document !== "undefined") {
document.addEventListener("keydown", (e) => {
if (e.key === void 0) return;
pushToCurrentlyPressedKeys([mapKey(e.key), mapKey(e.code)]);
});
document.addEventListener("keyup", (e) => {
if (e.key === void 0) return;
removeFromCurrentlyPressedKeys([mapKey(e.key), mapKey(e.code)]);
});
}
if (typeof window !== "undefined") window.addEventListener("blur", () => {
currentlyPressedKeys.clear();
});
})();
const currentlyPressedKeys = /* @__PURE__ */ new Set();
const isReadonlyArray = (value) => Array.isArray(value);
const isHotkeyPressed = (key, splitKey = ",") => (isReadonlyArray(key) ? key : key.split(splitKey)).every((hotkey) => {
var _keyAliases$hk;
const hk = lc(hotkey.trim());
return currentlyPressedKeys.has((_keyAliases$hk = keyAliases[hk]) !== null && _keyAliases$hk !== void 0 ? _keyAliases$hk : hk);
});
const pushToCurrentlyPressedKeys = (key) => {
const hotkeyArray = Array.isArray(key) ? key : [key];
if (currentlyPressedKeys.has("meta")) {
for (const k of currentlyPressedKeys) if (!isHotkeyModifier(k)) currentlyPressedKeys.delete(lc(k));
}
for (const hotkey of hotkeyArray) currentlyPressedKeys.add(lc(hotkey));
};
const removeFromCurrentlyPressedKeys = (key) => {
const hotkeyArray = Array.isArray(key) ? key : [key];
if (key === "meta") currentlyPressedKeys.clear();
else for (const hotkey of hotkeyArray) currentlyPressedKeys.delete(lc(hotkey));
};
//#endregion
//#region \0@oxc-project+runtime@0.134.0/helpers/esm/typeof.js
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
return typeof o;
} : function(o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
//#endregion
//#region \0@oxc-project+runtime@0.134.0/helpers/esm/toPrimitive.js
function toPrimitive(t, r) {
if ("object" != _typeof(t) || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != _typeof(i)) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
//#endregion
//#region \0@oxc-project+runtime@0.134.0/helpers/esm/toPropertyKey.js
function toPropertyKey(t) {
var i = toPrimitive(t, "string");
return "symbol" == _typeof(i) ? i : i + "";
}
//#endregion
//#region \0@oxc-project+runtime@0.134.0/helpers/esm/defineProperty.js
function _defineProperty(e, r, t) {
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: !0,
configurable: !0,
writable: !0
}) : e[r] = t, e;
}
//#endregion
//#region \0@oxc-project+runtime@0.134.0/helpers/esm/objectSpread2.js
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 _objectSpread2(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) {
_defineProperty(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;
}
//#endregion
//#region src/dndLogic.ts
/**
* Determines whether a drag item can be dropped on a rule target.
*/
const canDropOnRule = ({ dragging, path, schema, canDrop, groupModeModifierKey, disabled, rule }) => {
if (isHotkeyPressed(groupModeModifierKey) && disabled || dragging && typeof canDrop === "function" && !canDrop({
dragging,
hovering: _objectSpread2(_objectSpread2({}, rule), {}, {
path,
qbId: schema.qbId
})
})) return false;
if (schema.qbId !== dragging.qbId) return true;
const parentHoverPath = getParentPath(path);
const parentItemPath = getParentPath(dragging.path);
const hoverIndex = path.at(-1);
const itemIndex = dragging.path.at(-1);
return !(isAncestor(dragging.path, path) || pathsAreEqual(path, dragging.path) || !isHotkeyPressed(groupModeModifierKey) && pathsAreEqual(parentHoverPath, parentItemPath) && (hoverIndex === itemIndex - 1 || schema.independentCombinators && hoverIndex === itemIndex - 2));
};
/**
* Determines whether a drag item can be dropped on a rule group target.
*/
const canDropOnRuleGroup = ({ dragging, path, schema, canDrop, disabled, ruleGroup }) => {
if (disabled || dragging && typeof canDrop === "function" && !canDrop({
dragging,
hovering: _objectSpread2(_objectSpread2({}, ruleGroup), {}, {
path,
qbId: schema.qbId
})
})) return false;
if (schema.qbId !== dragging.qbId) return true;
const parentItemPath = getParentPath(dragging.path);
const itemIndex = dragging.path.at(-1);
return !(isAncestor(dragging.path, path) || pathsAreEqual(path, parentItemPath) && itemIndex === 0 || pathsAreEqual(path, dragging.path));
};
/**
* Determines whether a drag item can be dropped on an inline combinator target.
*/
const canDropOnInlineCombinator = ({ dragging, path, schema, canDrop, groupModeModifierKey, hoveringItem }) => {
const { path: itemPath } = dragging;
if (isHotkeyPressed(groupModeModifierKey) || dragging && typeof canDrop === "function" && !canDrop({
dragging,
hovering: _objectSpread2(_objectSpread2({}, hoveringItem), {}, {
path,
qbId: schema.qbId
})
})) return false;
const parentHoverPath = getParentPath(path);
const parentItemPath = getParentPath(itemPath);
const hoverIndex = path.at(-1);
const itemIndex = itemPath.at(-1);
return !(isAncestor(itemPath, path) || pathsAreEqual(itemPath, path) || pathsAreEqual(parentHoverPath, parentItemPath) && hoverIndex - 1 === itemIndex || schema.independentCombinators && pathsAreEqual(parentHoverPath, parentItemPath) && hoverIndex === itemIndex - 1);
};
/**
* Builds a {@link DropResult} for a given target.
*/
const buildDropResult = ({ type, path, schema, copyModeModifierKey, groupModeModifierKey, copyModeOverride, groupModeOverride }) => {
const { qbId, getQuery, dispatchQuery } = schema;
return {
type,
path,
qbId,
getQuery,
dispatchQuery,
groupItems: groupModeOverride || isHotkeyPressed(groupModeModifierKey),
dropEffect: copyModeOverride || isHotkeyPressed(copyModeModifierKey) ? "copy" : "move"
};
};
/**
* Computes the destination path for a drop operation based on the drop target
* type and whether grouping mode is active.
*/
const getDestinationPath = (dropResult, groupItems) => {
const parentHoverPath = getParentPath(dropResult.path);
const hoverIndex = dropResult.path.at(-1);
if (groupItems) return dropResult.path;
if (dropResult.type === "ruleGroup") return [...dropResult.path, 0];
if (dropResult.type === "inlineCombinator") return [...parentHoverPath, hoverIndex];
return [...parentHoverPath, hoverIndex + 1];
};
/**
* Handles the actual query mutation when a drop completes.
* Supports move, copy, group, and cross-query-builder operations.
*/
const handleDrop = ({ item, dropResult, schema, actions, copyModeModifierKey, groupModeModifierKey, copyModeOverride, groupModeOverride, onRuleDrop }) => {
if (!dropResult) return;
const dropEffect = copyModeOverride || isHotkeyPressed(copyModeModifierKey) ? "copy" : "move";
const groupItems = groupModeOverride || isHotkeyPressed(groupModeModifierKey);
const destinationPath = getDestinationPath(dropResult, groupItems);
const isCrossBuilder = schema.qbId !== dropResult.qbId;
if (!isCrossBuilder) if (groupItems) actions.groupRule(item.path, destinationPath, dropEffect === "copy");
else actions.moveRule(item.path, destinationPath, dropEffect === "copy");
else {
const otherBuilderQuery = dropResult.getQuery();
// v8 ignore else
if (otherBuilderQuery) {
if (groupItems) dropResult.dispatchQuery(group(add(otherBuilderQuery, item, []), [otherBuilderQuery.rules.length], destinationPath, { clone: false }));
else dropResult.dispatchQuery(insert(otherBuilderQuery, item, destinationPath));
// v8 ignore else
if (dropEffect !== "copy") actions.onRuleRemove(item.path);
}
}
onRuleDrop === null || onRuleDrop === void 0 || onRuleDrop({
draggedItem: item,
sourceQbId: schema.qbId,
targetQbId: dropResult.qbId,
sourcePath: item.path,
targetPath: destinationPath,
dropEffect,
groupItems,
isCrossBuilder
});
};
/**
* Creates the drag item from the current path and schema, used by
* drag-start callbacks.
*/
const getDragItem = (path, schema) => _objectSpread2(_objectSpread2({}, findPath(path, schema.getQuery())), {}, {
path,
qbId: schema.qbId
});
//#endregion
export { getDragItem as a, isHotkeyPressed as c, canDropOnRuleGroup as i, canDropOnInlineCombinator as n, handleDrop as o, canDropOnRule as r, _objectSpread2 as s, buildDropResult as t };
//# sourceMappingURL=dndLogic-CX9kFh1l.js.map