{"version":3,"file":"shadowQuery-Z2qhxCGM.mjs","names":[],"sources":["../src/DragPreviewContext.ts","../src/shadowQuery.ts"],"sourcesContent":["import type { Context } from 'react';\nimport { createContext } from 'react';\nimport type { DndDropTargetType, Path } from 'react-querybuilder';\nimport type { DragPreviewState } from './types';\n\n/**\n * Context value for the drag preview state during update-while-dragging.\n *\n * @group DnD\n */\nexport interface DragPreviewContextValue {\n  /** Current drag preview state, or `null` when not actively dragging. */\n  dragPreviewState: DragPreviewState | null;\n  /**\n   * Update the preview position. Called by adapter hooks when the cursor\n   * enters a new quadrant of a rule or group.\n   */\n  updatePreviewPosition: (\n    targetPath: Path,\n    targetType: DndDropTargetType,\n    quadrant: 'upper' | 'lower'\n  ) => void;\n  /**\n   * Commit the current shadow query as the real query and clear preview state.\n   * Called on drop.\n   */\n  commitDrag: () => void;\n  /**\n   * Discard the shadow query and revert to the original query.\n   * Called on cancel.\n   */\n  cancelDrag: () => void;\n}\n\n// v8 ignore next\nconst noop = (): void => {};\n\n/** @group Components */\nexport const DragPreviewContext: Context<DragPreviewContextValue> =\n  createContext<DragPreviewContextValue>({\n    dragPreviewState: null,\n    updatePreviewPosition: noop,\n    commitDrag: noop,\n    cancelDrag: noop,\n  });\n","import type {\n  DndDropTargetType,\n  DraggedItem,\n  DropEffect,\n  Path,\n  RuleGroupTypeAny,\n} from 'react-querybuilder';\nimport { getParentPath, group, move } from 'react-querybuilder';\n\n/**\n * Computes the destination path for a quadrant-based drag target.\n *\n * - **Rule, upper quadrant**: Insert before the target rule.\n * - **Rule, lower quadrant**: Insert after the target rule.\n * - **RuleGroup header**: Insert as first child of the group (position 0).\n */\nexport const computeDestinationFromQuadrant = (\n  targetPath: Path,\n  targetType: DndDropTargetType,\n  quadrant: 'upper' | 'lower'\n): Path => {\n  if (targetType === 'ruleGroup') {\n    // Group header → insert as first child\n    return [...targetPath, 0];\n  }\n\n  // Rule target\n  const parentPath = getParentPath(targetPath);\n  const targetIndex = targetPath.at(-1)!;\n\n  if (quadrant === 'upper') {\n    // Insert before the target\n    return [...parentPath, targetIndex];\n  }\n  // Insert after the target\n  return [...parentPath, targetIndex + 1];\n};\n\n/**\n * Checks whether the dragged item is already at the computed destination,\n * meaning no visual change would occur.\n */\nconst isNoOp = (draggedPath: Path, destinationPath: Path): boolean => {\n  if (draggedPath.length !== destinationPath.length) return false;\n\n  const parentDragged = getParentPath(draggedPath);\n  const parentDest = getParentPath(destinationPath);\n\n  // Different parents → not a no-op\n  // v8 ignore next -- unreachable: paths of equal length always have equal-length parents\n  if (parentDragged.length !== parentDest.length) return false;\n  for (let i = 0; i < parentDragged.length; i++) {\n    if (parentDragged[i] !== parentDest[i]) return false;\n  }\n\n  const dragIdx = draggedPath.at(-1)!;\n  const destIdx = destinationPath.at(-1)!;\n\n  // Moving to same position or position+1 (which resolves to same after removal)\n  return destIdx === dragIdx || destIdx === dragIdx + 1;\n};\n\n/**\n * Computes a shadow query given the current drag state and target position.\n *\n * Uses the existing `move()` and `group()` utilities from `@react-querybuilder/core`\n * to produce an immutable preview of the query with the dragged item at its\n * prospective position.\n *\n * @returns The shadow query and the path where the dragged item now lives,\n *          or `null` if the move would be a no-op.\n */\nexport const computeShadowQuery = ({\n  originalQuery,\n  // draggedItem,\n  draggedPath,\n  targetPath,\n  targetType,\n  quadrant,\n  dropEffect,\n  groupItems,\n}: {\n  originalQuery: RuleGroupTypeAny;\n  draggedItem: DraggedItem;\n  draggedPath: Path;\n  targetPath: Path;\n  targetType: DndDropTargetType;\n  quadrant: 'upper' | 'lower';\n  dropEffect: DropEffect;\n  groupItems: boolean;\n}): { shadowQuery: RuleGroupTypeAny; previewPath: Path } | null => {\n  const destinationPath = computeDestinationFromQuadrant(targetPath, targetType, quadrant);\n  const isClone = dropEffect === 'copy';\n\n  if (groupItems) {\n    // Group mode: create a new group containing both items\n    try {\n      const shadowQuery = group(originalQuery, draggedPath, targetPath, { clone: isClone });\n      // After grouping, the dragged item is inside the new group.\n      // The new group is at targetPath, and the source item is at index 0 or 1\n      // depending on relative positions. For preview purposes, use targetPath.\n      return { shadowQuery, previewPath: targetPath };\n    } catch {\n      // v8 ignore next\n      return null;\n    }\n  }\n\n  // Normal move/copy\n  if (!isClone && isNoOp(draggedPath, destinationPath)) {\n    return null;\n  }\n\n  try {\n    const shadowQuery = move(originalQuery, draggedPath, destinationPath, { clone: isClone });\n    // Compute the preview path: where the item ended up after the move.\n    // After a move, the destination path may shift if the source was before it.\n    // For preview purposes, we approximate: if source was before dest in same parent,\n    // the effective dest shifts back by 1.\n    let previewPath = destinationPath;\n    if (!isClone) {\n      const parentDragged = getParentPath(draggedPath);\n      const parentDest = getParentPath(destinationPath);\n      const sameParent =\n        parentDragged.length === parentDest.length &&\n        parentDragged.every((v, i) => v === parentDest[i]);\n      if (sameParent) {\n        const dragIdx = draggedPath.at(-1)!;\n        const destIdx = destinationPath.at(-1)!;\n        if (dragIdx < destIdx) {\n          previewPath = [...parentDest, destIdx - 1];\n        }\n      }\n    }\n    return { shadowQuery, previewPath };\n  } catch {\n    // v8 ignore next\n    return null;\n  }\n};\n"],"mappings":"8GAmCA,MAAM,MAAmB,CAAC,EAGb,EACX,EAAuC,CACrC,iBAAkB,KAClB,sBAAuB,EACvB,WAAY,EACZ,WAAY,CACd,CAAC,EC5BU,GACX,EACA,EACA,IACS,CACT,GAAI,IAAe,YAEjB,MAAO,CAAC,GAAG,EAAY,CAAC,EAI1B,IAAM,EAAa,EAAc,CAAU,EACrC,EAAc,EAAW,GAAG,EAAE,EAOpC,OALI,IAAa,QAER,CAAC,GAAG,EAAY,CAAW,EAG7B,CAAC,GAAG,EAAY,EAAc,CAAC,CACxC,EAMM,GAAU,EAAmB,IAAmC,CACpE,GAAI,EAAY,SAAW,EAAgB,OAAQ,MAAO,GAE1D,IAAM,EAAgB,EAAc,CAAW,EACzC,EAAa,EAAc,CAAe,EAIhD,GAAI,EAAc,SAAW,EAAW,OAAQ,MAAO,GACvD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAc,OAAQ,IACxC,GAAI,EAAc,KAAO,EAAW,GAAI,MAAO,GAGjD,IAAM,EAAU,EAAY,GAAG,EAAE,EAC3B,EAAU,EAAgB,GAAG,EAAE,EAGrC,OAAO,IAAY,GAAW,IAAY,EAAU,CACtD,EAYa,GAAsB,CACjC,gBAEA,cACA,aACA,aACA,WACA,aACA,gBAUiE,CACjE,IAAM,EAAkB,EAA+B,EAAY,EAAY,CAAQ,EACjF,EAAU,IAAe,OAE/B,GAAI,EAEF,GAAI,CAKF,MAAO,CAAE,YAJW,EAAM,EAAe,EAAa,EAAY,CAAE,MAAO,CAAQ,CAIhE,EAAG,YAAa,CAAW,CAChD,MAAQ,CAEN,OAAO,IACT,CAIF,GAAI,CAAC,GAAW,EAAO,EAAa,CAAe,EACjD,OAAO,KAGT,GAAI,CACF,IAAM,EAAc,EAAK,EAAe,EAAa,EAAiB,CAAE,MAAO,CAAQ,CAAC,EAKpF,EAAc,EAClB,GAAI,CAAC,EAAS,CACZ,IAAM,EAAgB,EAAc,CAAW,EACzC,EAAa,EAAc,CAAe,EAIhD,GAFE,EAAc,SAAW,EAAW,QACpC,EAAc,OAAO,EAAG,IAAM,IAAM,EAAW,EAAE,EACnC,CACd,IAAM,EAAU,EAAY,GAAG,EAAE,EAC3B,EAAU,EAAgB,GAAG,EAAE,EACjC,EAAU,IACZ,EAAc,CAAC,GAAG,EAAY,EAAU,CAAC,EAE7C,CACF,CACA,MAAO,CAAE,cAAa,aAAY,CACpC,MAAQ,CAEN,OAAO,IACT,CACF"}