ragflow/web/src/pages/agent/hooks/use-dropdown-position.ts
balibabu ee9ac15174
Feat: Fixed an issue where dragged operators within an iteration were not associated with the iteration. #10866 (#10969)
### What problem does this PR solve?

Feat: Fixed an issue where dragged operators within an iteration were
not associated with the iteration. #10866

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
2025-11-03 19:19:26 +08:00

113 lines
3 KiB
TypeScript

import { ReactFlowInstance } from '@xyflow/react';
import { useCallback } from 'react';
import {
DROPDOWN_HORIZONTAL_OFFSET,
DROPDOWN_VERTICAL_OFFSET,
HALF_PLACEHOLDER_NODE_WIDTH,
} from '../constant';
/**
* Dropdown position calculation Hook
* Responsible for calculating dropdown menu position relative to placeholder node
*/
export const useDropdownPosition = (
reactFlowInstance?: ReactFlowInstance<any, any>,
) => {
/**
* Calculate dropdown menu position
* @param clientX Mouse click screen X coordinate
* @param clientY Mouse click screen Y coordinate
* @returns Dropdown menu screen coordinates
*/
const calculateDropdownPosition = useCallback(
(clientX: number, clientY: number) => {
if (!reactFlowInstance) {
return { x: clientX, y: clientY };
}
// Convert screen coordinates to flow coordinates
const placeholderNodePosition = reactFlowInstance.screenToFlowPosition({
x: clientX,
y: clientY,
});
// Calculate dropdown position in flow coordinate system
const dropdownFlowPosition = {
x:
placeholderNodePosition.x +
HALF_PLACEHOLDER_NODE_WIDTH +
DROPDOWN_HORIZONTAL_OFFSET,
y: placeholderNodePosition.y - DROPDOWN_VERTICAL_OFFSET,
};
// Convert flow coordinates back to screen coordinates
const dropdownScreenPosition =
reactFlowInstance.flowToScreenPosition(dropdownFlowPosition);
return {
x: dropdownScreenPosition.x,
y: dropdownScreenPosition.y,
};
},
[reactFlowInstance],
);
/**
* Calculate placeholder node flow coordinate position
* @param clientX Mouse click screen X coordinate
* @param clientY Mouse click screen Y coordinate
* @returns Placeholder node flow coordinates
*/
const getPlaceholderNodePosition = useCallback(
(clientX: number, clientY: number) => {
if (!reactFlowInstance) {
return { x: clientX, y: clientY };
}
return reactFlowInstance.screenToFlowPosition({
x: clientX,
y: clientY,
});
},
[reactFlowInstance],
);
/**
* Convert flow coordinates to screen coordinates
* @param flowPosition Flow coordinates
* @returns Screen coordinates
*/
const flowToScreenPosition = useCallback(
(flowPosition: { x: number; y: number }) => {
if (!reactFlowInstance) {
return flowPosition;
}
return reactFlowInstance.flowToScreenPosition(flowPosition);
},
[reactFlowInstance],
);
/**
* Convert screen coordinates to flow coordinates
* @param screenPosition Screen coordinates
* @returns Flow coordinates
*/
const screenToFlowPosition = useCallback(
(screenPosition: { x: number; y: number }) => {
if (!reactFlowInstance) {
return screenPosition;
}
return reactFlowInstance.screenToFlowPosition(screenPosition);
},
[reactFlowInstance],
);
return {
calculateDropdownPosition,
getPlaceholderNodePosition,
flowToScreenPosition,
screenToFlowPosition,
};
};