feat(frontend): add hover state to edge delete button in FlowEditor (#11601)

<!-- Clearly explain the need for these changes: -->

The delete button on flow editor edges is always visible, which creates
visual clutter. This change makes the button only appear on hover,
improving the UI while keeping it accessible.

### Changes 🏗️

- Added hover state management using `useState` to track when the edge
delete button is hovered
- Applied opacity transition to the delete button (fades in on hover,
fades out when not hovered)
- Added `onMouseEnter` and `onMouseLeave` handlers to the button to
control hover state
- Used `cn` utility for conditional className management
- Button remains interactive even when `opacity-0` (still clickable for
better UX)

### Checklist 📋

#### For code changes:

- [x] I have clearly listed my changes in the PR description
- [x] I have made a test plan
- [x] I have tested my changes according to the test plan:
- [x] Hover over an edge in the flow editor and verify the delete button
fades in smoothly
- [x] Move mouse away from edge and verify the delete button fades out
smoothly
- [x] Click the delete button while hovered to verify it still removes
the edge connection
- [x] Test with multiple edges to ensure hover state is independent per
edge
This commit is contained in:
Abhimanyu Yadav
2025-12-22 07:00:58 +05:30
committed by GitHub
parent 08a60dcb9b
commit c3e407ef09

View File

@@ -1,3 +1,4 @@
import { memo, useState } from "react";
import { Button } from "@/components/atoms/Button/Button";
import {
BaseEdge,
@@ -20,7 +21,6 @@ export type CustomEdgeData = {
};
export type CustomEdge = XYEdge<CustomEdgeData, "custom">;
import { memo } from "react";
const CustomEdge = ({
id,
@@ -35,6 +35,8 @@ const CustomEdge = ({
selected,
}: EdgeProps<CustomEdge>) => {
const removeConnection = useEdgeStore((state) => state.removeEdge);
const [isHovered, setIsHovered] = useState(false);
const [edgePath, labelX, labelY] = getBezierPath({
sourceX,
sourceY,
@@ -69,12 +71,17 @@ const CustomEdge = ({
<EdgeLabelRenderer>
<Button
onClick={() => removeConnection(id)}
className={`absolute h-fit min-w-0 p-1`}
className={cn(
"absolute h-fit min-w-0 p-1 transition-opacity",
isHovered ? "opacity-100" : "opacity-0",
)}
variant="secondary"
style={{
transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,
pointerEvents: "all",
}}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<XIcon className="h-3 w-3" weight="bold" />
</Button>