-
Notifications
You must be signed in to change notification settings - Fork 378
feat(vue-nodes): snap link preview; connect on drop #5780
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
regenerating after the canvasonly flag was added, widgets moved around, links stayed the same though |
@codex review |
There was a problem hiding this 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
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)
- 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
There was a problem hiding this 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 🫤
reset: () => { | ||
state.compatCache = new Map() | ||
state.nodePreferred = new Map() | ||
state.lastHoverSlotKey = null | ||
state.lastHoverNodeId = null | ||
state.lastCandidateKey = null | ||
state.pendingMove = null | ||
}, | ||
dispose: () => { | ||
state.reset() | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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()
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
Summary - Route LGraphNode slot position queries through a single source of truth that prefers layoutStore’s DOM‑tracked slot positions and falls back to geometry when unavailable. - Ensures that reroute‑origin drags snap to the same visual slot centers used by Vue nodes when hovering compatible nodes. What changed - LGraphNode.getInputPos/getOutputPos now resolve via getSlotPosition(), which: - Returns the Vue nodes layoutStore position if the slot has been tracked. - Otherwise, computes from node geometry (unchanged fallback behavior). - LGraphNode.getInputSlotPos(input) resolves index→getSlotPosition() and retains a safe fallback when an input slot object doesn’t map to an index. Why - Previously, when starting a drag from a reroute and hovering a node, the temporary link endpoint would render toward LiteGraph’s calculated slot position, not the Vue‑tracked slot position, causing a visible mismatch. - By making all slot position lookups consult the layout store first, node hover snap rendering is consistent across slot‑origin and reroute‑origin drags. Impact - No behavior change for non‑Vue nodes mode or when no tracked layout exists — the legacy calculated positions are still used. - Centralizes slot positioning in one place, reducing special‑case logic and making hover/drag rendering more predictable. #5780 (snapping) <-- #5898 (drop on canvas + linkconnectoradapter refactor) <-- #5903 (fix reroute snapping) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5903-Use-layoutStore-slot-positions-for-node-slot-queries-fix-reroute-origin-node-snap-2816d73d36508184b297f46b39105545) by [Unito](https://www.unito.io)
## 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) https://github.com/user-attachments/assets/fbed0ae2-2231-473b-a05a-9aaf68e3f820 #5780 (snapping) <-- #5898 (drop on canvas + linkconnectoradapter refactor) <-- #5903 (fix reroute snapping) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5780-feat-vue-nodes-snap-link-preview-connect-on-drop-27a6d73d365081d89c8cf570e2049c89) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <[email protected]>
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. - 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 - 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 https://github.com/user-attachments/assets/fbed0ae2-2231-473b-a05a-9aaf68e3f820 #5780 (snapping) <-- #5898 (drop on canvas + linkconnectoradapter refactor) <-- #5903 (fix reroute snapping) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5780-feat-vue-nodes-snap-link-preview-connect-on-drop-27a6d73d365081d89c8cf570e2049c89) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <[email protected]>
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
data-slot-key
fast-pathfindInputByType
/findOutputByType
slotLinkPreviewRenderer.ts
now renders tostate.candidate.layout.position
state.candidate
(no re-hit-testing)Review Focus
Screenshots (if applicable)
Recording.2025-09-25.172342.mp4
#5780 (snapping) <-- #5898 (drop on canvas + linkconnectoradapter refactor) <-- #5903 (fix reroute snapping)
┆Issue is synchronized with this Notion page by Unito