Browse Source

fix: align handle connection points with visual handle positions

Use calc() to offset handle positions by 5px (half of 10px handle size)
to center handles at their percentage positions. This ensures edge
connection points align with the visible handle dots and labels.

Avoid using CSS transform which breaks React Flow's handle detection.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 6 months ago
parent
commit
69b097c0f0
  1. 8
      src/components/FloatingActionBar.tsx
  2. 8
      src/components/nodes/GenerateImageNode.tsx
  3. 8
      src/components/nodes/GenerateVideoNode.tsx

8
src/components/FloatingActionBar.tsx

@ -181,6 +181,12 @@ export function FloatingActionBar() {
} = useWorkflowStore();
const [runMenuOpen, setRunMenuOpen] = useState(false);
const runMenuRef = useRef<HTMLDivElement>(null);
const [mounted, setMounted] = useState(false);
// Defer client-only rendering to avoid hydration mismatch
useEffect(() => {
setMounted(true);
}, []);
const { valid, errors } = validateWorkflow();
@ -246,7 +252,7 @@ export function FloatingActionBar() {
<div className="w-px h-5 bg-neutral-600 mx-1.5" />
{/* Replicate icon - only show if API key is configured */}
{providerSettings.providers.replicate?.apiKey && (
{mounted && providerSettings.providers.replicate?.apiKey && (
<ProviderIconButton
provider="replicate"
onClick={() => setModelSearchOpen(true, "replicate")}

8
src/components/nodes/GenerateImageNode.tsx

@ -360,7 +360,7 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
type="target"
position={Position.Left}
id={input.name}
style={{ top: `${topPercent}%` }}
style={{ top: `calc(${topPercent}% - 5px)` }}
data-handletype={input.type}
isConnectable={true}
title={input.description || input.label}
@ -387,7 +387,7 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
type="target"
position={Position.Left}
id="image"
style={{ top: "35%" }}
style={{ top: "calc(35% - 5px)" }}
data-handletype="image"
isConnectable={true}
/>
@ -406,7 +406,7 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
type="target"
position={Position.Left}
id="text"
style={{ top: "65%" }}
style={{ top: "calc(65% - 5px)" }}
data-handletype="text"
/>
{/* Default text label */}
@ -427,7 +427,7 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
type="source"
position={Position.Right}
id="image"
style={{ top: "50%" }}
style={{ top: "calc(50% - 5px)" }}
data-handletype="image"
/>
{/* Output label */}

8
src/components/nodes/GenerateVideoNode.tsx

@ -195,7 +195,7 @@ export function GenerateVideoNode({ id, data, selected }: NodeProps<GenerateVide
type="target"
position={Position.Left}
id={input.name}
style={{ top: `${topPercent}%` }}
style={{ top: `calc(${topPercent}% - 5px)` }}
data-handletype={input.type}
isConnectable={true}
title={input.description || input.label}
@ -222,7 +222,7 @@ export function GenerateVideoNode({ id, data, selected }: NodeProps<GenerateVide
type="target"
position={Position.Left}
id="image"
style={{ top: "35%" }}
style={{ top: "calc(35% - 5px)" }}
data-handletype="image"
isConnectable={true}
/>
@ -241,7 +241,7 @@ export function GenerateVideoNode({ id, data, selected }: NodeProps<GenerateVide
type="target"
position={Position.Left}
id="text"
style={{ top: "65%" }}
style={{ top: "calc(65% - 5px)" }}
data-handletype="text"
/>
{/* Default text label */}
@ -262,7 +262,7 @@ export function GenerateVideoNode({ id, data, selected }: NodeProps<GenerateVide
type="source"
position={Position.Right}
id="image"
style={{ top: "50%" }}
style={{ top: "calc(50% - 5px)" }}
data-handletype="image"
/>
{/* Output label */}

Loading…
Cancel
Save