Skip to content

Conversation

benceruleanlu
Copy link
Member

@benceruleanlu benceruleanlu commented Sep 26, 2025

Summary

Snap link preview to the nearest compatible slot while dragging in Vue Nodes mode, and complete the connection on drop using the snapped target. Mirrors LiteGraph’s first-compatible-slot logic for node-level snapping and reuses the computed candidate for performance.

Changes

  • Snap preview end to compatible slot
    • slot under cursor via data-slot-key fast-path
    • node under cursor via findInputByType / findOutputByType
  • Render path
    • slotLinkPreviewRenderer.ts now renders to state.candidate.layout.position
  • Complete on drop
    • Prefer state.candidate (no re-hit-testing)
    • Fallbacks: DOM slot → node first-compatible → reroute
    • Disconnects moving input link when dropped on canvas

Review Focus

  • UX feel of snapping and drop completion (both directions)
  • Performance on large graphs (mousemove path is O(1) with dataset + single validation)
  • Edge cases: reroutes, moving existing links, collapsed nodes

Screenshots (if applicable)

Recording.2025-09-25.172342.mp4

┆Issue is synchronized with this Notion page by Unito

@benceruleanlu
Copy link
Member Author

@codex review

Copy link

Codex Review: Something went wrong. Try again later by commenting “@codex review”.

Script failed: Script exited with code 1
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting

Base automatically changed from bl-more-slots to main September 30, 2025 01:23
@dosubot dosubot bot added size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Sep 30, 2025
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:XXL This PR changes 1000+ lines, ignoring generated files. labels Sep 30, 2025
Copy link

github-actions bot commented Sep 30, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 10/03/2025, 10:31:41 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@benceruleanlu
Copy link
Member Author

regenerating after the canvasonly flag was added, widgets moved around, links stayed the same though

@benceruleanlu benceruleanlu added New Browser Test Expectations New browser test screenshot should be set by github action and removed New Browser Test Expectations New browser test screenshot should be set by github action labels Sep 30, 2025
@benceruleanlu benceruleanlu added New Browser Test Expectations New browser test screenshot should be set by github action and removed New Browser Test Expectations New browser test screenshot should be set by github action labels Sep 30, 2025
@benceruleanlu
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting

@christian-byrne christian-byrne added the claude-review Add to trigger a PR code review from Claude Code label Oct 1, 2025
When vue nodes is enabled, switch to the new getSlotPosition for
subgraph nodes as well.

This aligns links to slots in subgraphs.

Do note, getSlotPosition is actually the new standard, but we fallback
to inputNode.getInputPos since it's so core, idea is to switch over
fully to getSlotPosition without the vue flag once things are more
stable.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5876-Align-links-to-slots-in-subgraphs-27f6d73d365081148b92f312a0af84a0)
by [Unito](https://www.unito.io)
christian-byrne
christian-byrne previously approved these changes Oct 2, 2025
- Snap preview target: use snapped candidate position when compatible
- Vue nodes interaction: track hovered candidate via setCandidate
- Keep PR browser test snapshots (ours) for link interactions
@benceruleanlu benceruleanlu added New Browser Test Expectations New browser test screenshot should be set by github action and removed New Browser Test Expectations New browser test screenshot should be set by github action labels Oct 3, 2025
Copy link
Contributor

@DrJKL DrJKL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a lot of state to keep synchronized 🫤

Comment on lines +31 to +41
reset: () => {
state.compatCache = new Map()
state.nodePreferred = new Map()
state.lastHoverSlotKey = null
state.lastHoverNodeId = null
state.lastCandidateKey = null
state.pendingMove = null
},
dispose: () => {
state.reset()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would this persist and be reset instead of just being dropped and garbage collected?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's because it will be alive for the lifetime of the composable

it's called as const dragSession = createSlotLinkDragSession()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like a microoptimization in advance to me. Did you see performance issues without it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this was meant for performance, just to save like a few lines from both files

Comment on lines +498 to 515
const snappedCandidate = state.candidate?.compatible
? state.candidate
: null

let connected = tryConnectToCandidate(snappedCandidate)

// Fallback to DOM slot under pointer (if any), then node fallback, then reroute
if (!connected) {
const domCandidate = candidateFromTarget(event.target)
connected = tryConnectToCandidate(domCandidate)
}

if (!connected) {
const nodeCandidate = candidateFromNodeTarget(event.target)
connected = tryConnectToCandidate(nodeCandidate)
}

if (!connected) connected = tryConnectViaRerouteAtPointer() || connected
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This kind of long chain of optional assignment to a mutable variable is a great case for extraction to a more pure function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a lot of scuffed code that I want to fix next week, this can be one of them

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
claude-review Add to trigger a PR code review from Claude Code New Browser Test Expectations New browser test screenshot should be set by github action size:L This PR changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants