@react-querybuilder/dnd
Version:
Drag-and-drop-enabled version of react-querybuilder (DnD-library-agnostic)
91 lines (90 loc) • 3.46 kB
JavaScript
import { createContext } from "react";
import { getParentPath, group, move } from "react-querybuilder";
//#region src/DragPreviewContext.ts
// v8 ignore next
const noop = () => {};
/** @group Components */
const DragPreviewContext = createContext({
dragPreviewState: null,
updatePreviewPosition: noop,
commitDrag: noop,
cancelDrag: noop
});
//#endregion
//#region src/shadowQuery.ts
/**
* Computes the destination path for a quadrant-based drag target.
*
* - **Rule, upper quadrant**: Insert before the target rule.
* - **Rule, lower quadrant**: Insert after the target rule.
* - **RuleGroup header**: Insert as first child of the group (position 0).
*/
const computeDestinationFromQuadrant = (targetPath, targetType, quadrant) => {
if (targetType === "ruleGroup") return [...targetPath, 0];
const parentPath = getParentPath(targetPath);
const targetIndex = targetPath.at(-1);
if (quadrant === "upper") return [...parentPath, targetIndex];
return [...parentPath, targetIndex + 1];
};
/**
* Checks whether the dragged item is already at the computed destination,
* meaning no visual change would occur.
*/
const isNoOp = (draggedPath, destinationPath) => {
if (draggedPath.length !== destinationPath.length) return false;
const parentDragged = getParentPath(draggedPath);
const parentDest = getParentPath(destinationPath);
// v8 ignore next -- unreachable: paths of equal length always have equal-length parents
if (parentDragged.length !== parentDest.length) return false;
for (let i = 0; i < parentDragged.length; i++) if (parentDragged[i] !== parentDest[i]) return false;
const dragIdx = draggedPath.at(-1);
const destIdx = destinationPath.at(-1);
return destIdx === dragIdx || destIdx === dragIdx + 1;
};
/**
* Computes a shadow query given the current drag state and target position.
*
* Uses the existing `move()` and `group()` utilities from `@react-querybuilder/core`
* to produce an immutable preview of the query with the dragged item at its
* prospective position.
*
* @returns The shadow query and the path where the dragged item now lives,
* or `null` if the move would be a no-op.
*/
const computeShadowQuery = ({ originalQuery, draggedPath, targetPath, targetType, quadrant, dropEffect, groupItems }) => {
const destinationPath = computeDestinationFromQuadrant(targetPath, targetType, quadrant);
const isClone = dropEffect === "copy";
if (groupItems) try {
return {
shadowQuery: group(originalQuery, draggedPath, targetPath, { clone: isClone }),
previewPath: targetPath
};
} catch (_unused) {
// v8 ignore next
return null;
}
if (!isClone && isNoOp(draggedPath, destinationPath)) return null;
try {
const shadowQuery = move(originalQuery, draggedPath, destinationPath, { clone: isClone });
let previewPath = destinationPath;
if (!isClone) {
const parentDragged = getParentPath(draggedPath);
const parentDest = getParentPath(destinationPath);
if (parentDragged.length === parentDest.length && parentDragged.every((v, i) => v === parentDest[i])) {
const dragIdx = draggedPath.at(-1);
const destIdx = destinationPath.at(-1);
if (dragIdx < destIdx) previewPath = [...parentDest, destIdx - 1];
}
}
return {
shadowQuery,
previewPath
};
} catch (_unused2) {
// v8 ignore next
return null;
}
};
//#endregion
export { computeShadowQuery as n, DragPreviewContext as r, computeDestinationFromQuadrant as t };
//# sourceMappingURL=shadowQuery-B6n89EFI.js.map