Support space bar pan while dragging vue nodes - #12943
Conversation
📝 WalkthroughWalkthroughSpace key events now reach LiteGraph during Vue-node dragging. Space-held dragging pans the canvas without moving the node, pauses active auto-pan, preserves form-control input, and handles pointer release correctly. ChangesSpacebar canvas panning
Estimated code review effort: 3 (Moderate) | ~20 minutes Mergeability Score: 🔵 Low · up to Space-held dragging now pans the canvas, but focused controls may not retain their native Space behavior during that interaction, and a few drag-state regressions are not directly asserted. The change is mergeable with explicit owner follow-up on focused-control behavior and the targeted interaction tests. Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant User
participant TransformPane
participant LGraphCanvas
participant useNodeDrag
participant useNodePointerInteractions
User->>TransformPane: Hold Space and drag node
TransformPane->>LGraphCanvas: Forward eligible Space keydown
LGraphCanvas->>LGraphCanvas: Stop active auto-pan
useNodeDrag->>useNodeDrag: Update canvas offset and pointer state
User->>useNodePointerInteractions: Release pointer
useNodePointerInteractions->>useNodeDrag: End node drag
LGraphCanvas->>LGraphCanvas: Restart auto-pan on Space keyup when dragging
🚥 Pre-merge checks | ✅ 5 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is @@ Coverage Diff @@
## main #12943 +/- ##
==========================================
- Coverage 81.67% 78.68% -2.99%
==========================================
Files 1882 1880 -2
Lines 116978 114467 -2511
Branches 37411 36925 -486
==========================================
- Hits 95541 90074 -5467
- Misses 20969 23879 +2910
- Partials 468 514 +46
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 527 files with indirect coverage changes 🚀 New features to boost your workflow:
|
📦 Bundle: 8.72 MB gzip 🔴 +190 BDetailsSummary
Category Glance App Entry Points — 3.67 kB (baseline 3.67 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 1.37 MB (baseline 1.36 MB) • 🔴 +978 BGraph editor runtime, canvas, workflow orchestration
Status: 2 added / 2 removed / 1 unchanged Views & Navigation — 124 kB (baseline 124 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 13 added / 13 removed / 4 unchanged Panels & Settings — 565 kB (baseline 565 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 10 added / 10 removed / 16 unchanged User & Accounts — 27 kB (baseline 27 kB) • ⚪ 0 BAuthentication, profile, and account management bundles
Status: 6 added / 6 removed / 4 unchanged Editors & Dialogs — 125 kB (baseline 125 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors
Status: 7 added / 7 removed / 1 unchanged UI Components — 67.1 kB (baseline 67.1 kB) • ⚪ 0 BReusable component library chunks
Status: 6 added / 6 removed / 8 unchanged Data & Services — 3.51 MB (baseline 3.51 MB) • 🔴 +251 BStores, services, APIs, and repositories
Status: 14 added / 14 removed / 3 unchanged Utilities & Hooks — 550 kB (baseline 550 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 18 added / 18 removed / 20 unchanged Vendor & Third-Party — 16.3 MB (baseline 16.3 MB) • ⚪ 0 BExternal libraries and shared vendor chunks Status: 17 unchanged Other — 14.2 MB (baseline 14.2 MB) • ⚪ 0 BBundles that do not match a named category
Status: 68 added / 68 removed / 217 unchanged ⚡ Performance Report
Show regressions
All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-08-13T00:53:29.600Z",
"gitSha": "d582bb91f465b9eaa1a04b39405bba418faaaecc",
"branch": "austin/node-space-drag",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2035.000999999994,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.361,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 489.04600000000005,
"heapDeltaBytes": 5837316,
"heapUsedBytes": 70259964,
"domNodes": 16,
"jsHeapTotalBytes": 24379392,
"scriptDurationMs": 14.858000000000002,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-idle",
"durationMs": 2020.2429999999936,
"styleRecalcs": 9,
"styleRecalcDurationMs": 7.506,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 449.107,
"heapDeltaBytes": 5876384,
"heapUsedBytes": 70249268,
"domNodes": 18,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 14.446000000000003,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1974.7050000000286,
"styleRecalcs": 80,
"styleRecalcDurationMs": 44.882,
"layouts": 12,
"layoutDurationMs": 3.75,
"taskDurationMs": 947.4340000000001,
"heapDeltaBytes": -12116452,
"heapUsedBytes": 52394644,
"domNodes": -279,
"jsHeapTotalBytes": 24088576,
"scriptDurationMs": 129.286,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1766.7340000000422,
"styleRecalcs": 73,
"styleRecalcDurationMs": 32.738,
"layouts": 12,
"layoutDurationMs": 3.192,
"taskDurationMs": 848.2019999999999,
"heapDeltaBytes": -14971476,
"heapUsedBytes": 49557980,
"domNodes": -283,
"jsHeapTotalBytes": 23302144,
"scriptDurationMs": 116.08100000000002,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1718.1679999999915,
"styleRecalcs": 30,
"styleRecalcDurationMs": 15.568,
"layouts": 6,
"layoutDurationMs": 0.604,
"taskDurationMs": 360.695,
"heapDeltaBytes": 8813792,
"heapUsedBytes": 73215112,
"domNodes": 76,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 17.631,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1738.2179999999607,
"styleRecalcs": 31,
"styleRecalcDurationMs": 16.772000000000002,
"layouts": 6,
"layoutDurationMs": 0.6759999999999999,
"taskDurationMs": 374.411,
"heapDeltaBytes": 8851152,
"heapUsedBytes": 73212916,
"domNodes": 78,
"jsHeapTotalBytes": 24379392,
"scriptDurationMs": 18.117,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 628.1740000000013,
"styleRecalcs": 10,
"styleRecalcDurationMs": 7.813000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 397.968,
"heapDeltaBytes": -11576664,
"heapUsedBytes": 52879484,
"domNodes": 16,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 58.71999999999999,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "dom-widget-clipping",
"durationMs": 554.817000000071,
"styleRecalcs": 11,
"styleRecalcDurationMs": 6.612000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 353.065,
"heapDeltaBytes": -11185016,
"heapUsedBytes": 53217400,
"domNodes": 18,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 56.123000000000005,
"eventListeners": 0,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-idle",
"durationMs": 2015.9350000000131,
"styleRecalcs": 8,
"styleRecalcDurationMs": 6.8489999999999975,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 654.113,
"heapDeltaBytes": 4386440,
"heapUsedBytes": 63953424,
"domNodes": -285,
"jsHeapTotalBytes": 3768320,
"scriptDurationMs": 99.361,
"eventListeners": -179,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-idle",
"durationMs": 2033.4760000000642,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.416,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 672.325,
"heapDeltaBytes": 7273980,
"heapUsedBytes": 66263032,
"domNodes": -280,
"jsHeapTotalBytes": 2981888,
"scriptDurationMs": 103.211,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2146.0820000000354,
"styleRecalcs": 69,
"styleRecalcDurationMs": 13.537,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1247.343,
"heapDeltaBytes": 4546700,
"heapUsedBytes": 65444324,
"domNodes": -284,
"jsHeapTotalBytes": 4222976,
"scriptDurationMs": 422.531,
"eventListeners": -147,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2160.2120000000014,
"styleRecalcs": 70,
"styleRecalcDurationMs": 14.775999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1106.372,
"heapDeltaBytes": 4766324,
"heapUsedBytes": 65794416,
"domNodes": -282,
"jsHeapTotalBytes": 3698688,
"scriptDurationMs": 433.65400000000005,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3182.7369999999746,
"styleRecalcs": 64,
"styleRecalcDurationMs": 13.373,
"layouts": 60,
"layoutDurationMs": 6.9110000000000005,
"taskDurationMs": 1470.719,
"heapDeltaBytes": -3708548,
"heapUsedBytes": 59143568,
"domNodes": -287,
"jsHeapTotalBytes": 5865472,
"scriptDurationMs": 512.861,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3198.158000000035,
"styleRecalcs": 65,
"styleRecalcDurationMs": 15.412999999999997,
"layouts": 60,
"layoutDurationMs": 7.447,
"taskDurationMs": 1534.739,
"heapDeltaBytes": -2123852,
"heapUsedBytes": 59930324,
"domNodes": -288,
"jsHeapTotalBytes": 6389760,
"scriptDurationMs": 546.097,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "minimap-idle",
"durationMs": 2030.8330000000296,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.145000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 667.7180000000001,
"heapDeltaBytes": 6725056,
"heapUsedBytes": 67277056,
"domNodes": -284,
"jsHeapTotalBytes": 4292608,
"scriptDurationMs": 100.95700000000001,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2053.788000000054,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.173000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 681.967,
"heapDeltaBytes": 5351752,
"heapUsedBytes": 65949188,
"domNodes": -285,
"jsHeapTotalBytes": 3506176,
"scriptDurationMs": 104.94699999999999,
"eventListeners": -179,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 596.445000000017,
"styleRecalcs": 46,
"styleRecalcDurationMs": 9.706000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 390.321,
"heapDeltaBytes": -10726556,
"heapUsedBytes": 53950080,
"domNodes": 18,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 117.99200000000002,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 595.9609999999884,
"styleRecalcs": 47,
"styleRecalcDurationMs": 11.055999999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 403.698,
"heapDeltaBytes": -10478620,
"heapUsedBytes": 53889760,
"domNodes": 20,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 120.93299999999999,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-idle",
"durationMs": 2003.0100000000175,
"styleRecalcs": 7,
"styleRecalcDurationMs": 6.346999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 433.038,
"heapDeltaBytes": 5632384,
"heapUsedBytes": 70113424,
"domNodes": 14,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 12.922,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "subgraph-idle",
"durationMs": 1993.5460000000376,
"styleRecalcs": 10,
"styleRecalcDurationMs": 9.335,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 445.4100000000001,
"heapDeltaBytes": 5880792,
"heapUsedBytes": 70356924,
"domNodes": 20,
"jsHeapTotalBytes": 24379392,
"scriptDurationMs": 12.427999999999999,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1741.0110000000145,
"styleRecalcs": 76,
"styleRecalcDurationMs": 43.800000000000004,
"layouts": 16,
"layoutDurationMs": 5.027,
"taskDurationMs": 816.905,
"heapDeltaBytes": -16290564,
"heapUsedBytes": 48308532,
"domNodes": -282,
"jsHeapTotalBytes": 22253568,
"scriptDurationMs": 91.095,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1735.569000000055,
"styleRecalcs": 80,
"styleRecalcDurationMs": 35.138000000000005,
"layouts": 16,
"layoutDurationMs": 4.159999999999999,
"taskDurationMs": 786.9939999999999,
"heapDeltaBytes": -18413024,
"heapUsedBytes": 46144804,
"domNodes": 2,
"jsHeapTotalBytes": 23040000,
"scriptDurationMs": 90.781,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-transition-enter",
"durationMs": 1400.3920000000107,
"styleRecalcs": 17,
"styleRecalcDurationMs": 29.720000000000002,
"layouts": 13,
"layoutDurationMs": 12.400999999999998,
"taskDurationMs": 892.5789999999998,
"heapDeltaBytes": 30987320,
"heapUsedBytes": 99406660,
"domNodes": 13673,
"jsHeapTotalBytes": 15204352,
"scriptDurationMs": 32.772,
"eventListeners": 2375,
"totalBlockingTimeMs": 134,
"frameDurationMs": 16.666666666666696,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "viewport-pan-sweep",
"durationMs": 8281.339000000004,
"styleRecalcs": 250,
"styleRecalcDurationMs": 36.312999999999995,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4542.929,
"heapDeltaBytes": 15898660,
"heapUsedBytes": 76004084,
"domNodes": -282,
"jsHeapTotalBytes": 9465856,
"scriptDurationMs": 1510.861,
"eventListeners": -133,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.80000000000109
},
{
"name": "viewport-pan-sweep",
"durationMs": 8236.427999999933,
"styleRecalcs": 250,
"styleRecalcDurationMs": 37.922,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4469.103,
"heapDeltaBytes": 13061924,
"heapUsedBytes": 72622384,
"domNodes": -284,
"jsHeapTotalBytes": 6844416,
"scriptDurationMs": 1404.9740000000002,
"eventListeners": -133,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.80000000000109
},
{
"name": "vue-large-graph-idle",
"durationMs": 16260.201000000052,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 16235.197999999997,
"heapDeltaBytes": -35596708,
"heapUsedBytes": 166109656,
"domNodes": -8312,
"jsHeapTotalBytes": -3874816,
"scriptDurationMs": 526.014,
"eventListeners": -16387,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.219999999999953,
"p95FrameDurationMs": 16.80000000000291
},
{
"name": "vue-large-graph-idle",
"durationMs": 16474.218000000066,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 16457.661,
"heapDeltaBytes": -41194892,
"heapUsedBytes": 165793380,
"domNodes": -8312,
"jsHeapTotalBytes": -10686464,
"scriptDurationMs": 500.849,
"eventListeners": -16387,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.80000000000291
},
{
"name": "vue-large-graph-pan",
"durationMs": 19860.009999999987,
"styleRecalcs": 134,
"styleRecalcDurationMs": 14.282000000000018,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 19826.707,
"heapDeltaBytes": -58175340,
"heapUsedBytes": 166722424,
"domNodes": -8312,
"jsHeapTotalBytes": -8069120,
"scriptDurationMs": 847.022,
"eventListeners": -16381,
"totalBlockingTimeMs": 125,
"frameDurationMs": 17.77333333333336,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 20128.519999999982,
"styleRecalcs": 137,
"styleRecalcDurationMs": 14.812999999999965,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 20103.965000000004,
"heapDeltaBytes": -47245248,
"heapUsedBytes": 158425436,
"domNodes": -8312,
"jsHeapTotalBytes": -5705728,
"scriptDurationMs": 838.306,
"eventListeners": -16387,
"totalBlockingTimeMs": 151,
"frameDurationMs": 18.330000000000048,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "workflow-execution",
"durationMs": 469.6230000000128,
"styleRecalcs": 20,
"styleRecalcDurationMs": 24.783,
"layouts": 5,
"layoutDurationMs": 1.7750000000000001,
"taskDurationMs": 130.18400000000003,
"heapDeltaBytes": 5338956,
"heapUsedBytes": 69069984,
"domNodes": 150,
"jsHeapTotalBytes": 5242880,
"scriptDurationMs": 11.988000000000001,
"eventListeners": 99,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "workflow-execution",
"durationMs": 478.33300000002055,
"styleRecalcs": 11,
"styleRecalcDurationMs": 18.859,
"layouts": 3,
"layoutDurationMs": 0.7520000000000001,
"taskDurationMs": 125.5,
"heapDeltaBytes": 5049124,
"heapUsedBytes": 68713308,
"domNodes": 121,
"jsHeapTotalBytes": 6029312,
"scriptDurationMs": 9.793999999999999,
"eventListeners": 97,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
}
]
}🎨 Storybook: ✅ Built — View Storybook🎭 Playwright: ✅ 1805 passed, 0 failed · 3 flaky📊 Browser Reports
|
0988cb1 to
fa17e0f
Compare
fa17e0f to
f227084
Compare
f227084 to
2564834
Compare
93ac026 to
3e6362e
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts`:
- Around line 55-70: Update the “while dragging node, spacebar starts pan” test
to capture the node’s graph position before the post-Space pointer move, then
assert that the final move changes that position to verify node dragging
resumes. Add mouse-button cleanup by releasing the mouse at the end of the step.
In `@src/renderer/extensions/vueNodes/layout/useNodeDrag.ts`:
- Around line 199-210: In the isReadOnly branch of the drag handler, stop and
clear the existing autoPan state before modifying canvas.ds.offset. Use the
established autoPan control and cleanup symbols, then continue the direct
canvas-panning behavior without invoking its onPan callback.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 32bd41a8-ef2c-400f-a80a-d9dd5de408b7
📒 Files selected for processing (3)
browser_tests/tests/vueNodes/interactions/canvas/pan.spec.tssrc/components/graph/GraphCanvas.vuesrc/renderer/extensions/vueNodes/layout/useNodeDrag.ts
📄 Knowledge reviewDosu skipped reviewing this PR because your organization has used its |
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
| .not.toEqual(offsetBefore) | ||
| }) | ||
|
|
||
| await test.step('while dragging node, spacebar starts pan', async () => { |
There was a problem hiding this comment.
This seems like several steps...
| canvas.ds.offset[0] += delta[0] / canvas.ds.scale | ||
| canvas.ds.offset[1] += delta[1] / canvas.ds.scale | ||
| canvas.setDirty(true, true) | ||
| lastPointerX = event.clientX | ||
| lastPointerY = event.clientY | ||
| dragStartMouse.x += delta[0] | ||
| dragStartMouse.y += delta[1] |
There was a problem hiding this comment.
The fact that we have to update this many things at once is a pretty big code smell, IMO.
(Not for this PR, just whining)
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/graph/GraphCanvas.vue`:
- Line 73: Update the GraphCanvas Space keydown binding to use a handler that
ignores events originating from inputs, textareas, buttons, or contenteditable
elements, and otherwise forwards Space through
canvasInteractions.forwardEventToCanvas only when an eligible node drag is
active.
- Line 73: Update the forwardEventToCanvas function’s event parameter type to
include KeyboardEvent, preserving its existing event handling and redispatch
behavior for keyboard properties.
In `@src/lib/litegraph/src/LGraphCanvas.ts`:
- Line 4011: Update the Space keyup handling around _autoPan?.stop() to restart
the AutoPanController when the pointer remains down and node dragging or link
interaction is still active. Invoke start() only for those active-drag states,
preserving the existing stopped behavior when no interaction is in progress.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: c11a21b2-a375-40cc-a9a5-0ce9286d9f5f
📒 Files selected for processing (4)
browser_tests/tests/vueNodes/interactions/canvas/pan.spec.tssrc/components/graph/GraphCanvas.vuesrc/lib/litegraph/src/LGraphCanvas.tssrc/renderer/extensions/vueNodes/layout/useNodeDrag.ts
## Summary Adds Playwright coverage and minimal fixes for two Space-pan regressions in the parent PR. ## Changes - **What**: Keep Space input in focused text widgets instead of forwarding it to canvas panning. - **What**: End the active Vue node drag when pointerup occurs during Space-pan. - **Tests**: Cover focused text input and pointer-release behavior. ## Review Focus The first commit contains the failing regression tests. The second commit contains the production fixes that make them pass. --------- Co-authored-by: Amp <amp@ampcode.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/graph/GraphCanvas.vue (1)
623-635: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winDo not consume Space from focused select controls.
When
e.targetis anHTMLSelectElementduring a Vue-node drag, this handler callscomfyApp.canvas.processKey(e).processKeyprevents the default Space action, so the select cannot open or operate normally. ExcludeHTMLSelectElementwith the other native controls.Proposed fix
target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLButtonElement || + target instanceof HTMLSelectElement || (target instanceof HTMLElement && target.isContentEditable)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/graph/GraphCanvas.vue` around lines 623 - 635, Update forwardSpaceKeyEvent to also return when e.target is an HTMLSelectElement, alongside the existing native control checks, so Space is not forwarded to comfyApp.canvas.processKey while a select is focused.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/litegraph/src/LGraphCanvas.linkDragAutoPan.test.ts`:
- Around line 61-85: Rewrite the test around real canvas behavior instead of
spying on AutoPanController methods: set the pointer through the canvas
pointer-handling path, place it at an edge, and drive the real auto-pan loop.
Assert that canvas.ds.offset remains unchanged while Space panning is active and
changes again after keyup, removing direct canvas.mouse mutation and
implementation-detail spy assertions.
---
Outside diff comments:
In `@src/components/graph/GraphCanvas.vue`:
- Around line 623-635: Update forwardSpaceKeyEvent to also return when e.target
is an HTMLSelectElement, alongside the existing native control checks, so Space
is not forwarded to comfyApp.canvas.processKey while a select is focused.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 4bc79f38-912f-4044-ba13-924a788009c7
📒 Files selected for processing (3)
src/components/graph/GraphCanvas.vuesrc/lib/litegraph/src/LGraphCanvas.linkDragAutoPan.test.tssrc/lib/litegraph/src/LGraphCanvas.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/graph/GraphCanvas.vue`:
- Around line 627-630: Update the editable-control guard in GraphCanvas.vue’s
processKey-related Space forwarding logic to include HTMLSelectElement alongside
the existing input, textarea, and button checks, preventing native select
controls from triggering canvas panning. Add a browser test covering Space on a
focused native select and verify the control consumes the key without forwarding
it.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 79df96ea-6f18-4854-be82-fb013e3468f7
📒 Files selected for processing (6)
browser_tests/fixtures/ComfyMouse.tsbrowser_tests/fixtures/helpers/KeyboardHelper.tsbrowser_tests/tests/vueNodes/interactions/canvas/pan.spec.tssrc/components/graph/GraphCanvas.vuesrc/lib/litegraph/src/LGraphCanvas.linkDragAutoPan.test.tssrc/lib/litegraph/src/LGraphCanvas.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/litegraph/src/LGraphCanvas.linkDragAutoPan.test.ts`:
- Around line 63-79: Update the drag setup in the test around processMouseDown
and processMouseMove to use PointerEvent for both pointerdown and pointermove
events, and set isPrimary: true on each event so the primary-pointer handling
invokes pointer.down and pointer.move.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 431cbc4a-4057-4b41-8a9d-989f67a49d59
📒 Files selected for processing (1)
src/lib/litegraph/src/LGraphCanvas.linkDragAutoPan.test.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts`:
- Around line 110-148: Add browser coverage alongside the existing native select
Space-key test for a focused button and a focused contenteditable element.
Verify that holding Space while each element is focused does not start canvas
panning, exercising the separate exclusions in forwardSpaceKeyEvent.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: fee40729-af5e-45cf-94c3-dcf8c9ded03a
📒 Files selected for processing (3)
browser_tests/tests/vueNodes/interactions/canvas/pan.spec.tssrc/components/graph/GraphCanvas.vuesrc/lib/litegraph/src/LGraphCanvas.linkDragAutoPan.test.ts
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts (2)
41-52: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAssert node immobility during Space-held panning.
Both Space-panning paths verify only that the canvas offset changes. The active-drag path captures
positionBeforeResumeafter the Space-held move, so node movement during panning is not detected. Capture the node position before each Space-held move and assert that it remains unchanged until Space is released.Proposed assertions
const offsetBefore = await comfyPage.canvasOps.getOffset() + const positionBeforePan = [ + ...(await nodeRef.getProperty<[number, number]>('pos')) + ] ... await comfyMouse.dragElementBy(node.root, { x: -300, y: 0 }) + await softExpect + .poll(async () => [ + ...(await nodeRef.getProperty<[number, number]>('pos')) + ]) + .toEqual(positionBeforePan) await releaseSpace.disposeAsync() ... const offsetBeforePan = await comfyPage.canvasOps.getOffset() + const positionBeforePan = [ + ...(await nodeRef.getProperty<[number, number]>('pos')) + ] ... await comfyPage.page.mouse.move(400, 400, { steps: 5 }) + await softExpect + .poll(async () => [ + ...(await nodeRef.getProperty<[number, number]>('pos')) + ]) + .toEqual(positionBeforePan)Also applies to: 55-65
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts` around lines 41 - 52, Update both Space-held panning test steps around the node drag interactions to capture the node position before the Space-held move and assert it remains unchanged after the move, before releasing Space. Keep the existing canvas-offset assertions, and apply the same immobility check to the active-drag path using its node position symbol.
169-183: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winObserve the pointer-release state before releasing Space.
The test disposes
mouseReleaseandspaceReleaseback-to-back. It never checks node behavior after pointer release while Space remains held. A pointer-up regression can pass if Space-up clears the stale drag state. Assert that the initial+40move changed the node. AftermouseRelease.disposeAsync(), wait for a frame, move the pointer once before disposingspaceRelease, and assert that the node position remains unchanged.Proposed test sequence
await comfyPage.page.mouse.move(start.x, start.y) + const positionBeforeDrag = [ + ...(await nodeRef.getProperty<[number, number]>('pos')) + ] await using mouseRelease = await comfyMouse.hold() await comfyPage.page.mouse.move(start.x + 40, start.y + 40, { steps: 5 }) + await expect + .poll(async () => [ + ...(await nodeRef.getProperty<[number, number]>('pos')) + ]) + .not.toEqual(positionBeforeDrag) ... await mouseRelease.disposeAsync() + await comfyPage.nextFrame() + const positionAfterPointerRelease = [ + ...(await nodeRef.getProperty<[number, number]>('pos')) + ] + await comfyPage.page.mouse.move(start.x + 120, start.y + 120, { + steps: 5 + }) + await comfyPage.nextFrame() + await expect + .poll(async () => [ + ...(await nodeRef.getProperty<[number, number]>('pos')) + ]) + .toEqual(positionAfterPointerRelease) await spaceRelease.disposeAsync()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts` around lines 169 - 183, Update the “Release the pointer while Space-panning” step around positionAfterRelease to assert the initial +40 move changed the node, then dispose mouseRelease and wait for a frame before moving the pointer once more while Space remains held; assert the node position is unchanged, and only then dispose spaceRelease.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts`:
- Around line 41-52: Update both Space-held panning test steps around the node
drag interactions to capture the node position before the Space-held move and
assert it remains unchanged after the move, before releasing Space. Keep the
existing canvas-offset assertions, and apply the same immobility check to the
active-drag path using its node position symbol.
- Around line 169-183: Update the “Release the pointer while Space-panning” step
around positionAfterRelease to assert the initial +40 move changed the node,
then dispose mouseRelease and wait for a frame before moving the pointer once
more while Space remains held; assert the node position is unchanged, and only
then dispose spaceRelease.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 12a44c44-7644-4dd8-926a-c0a965ff2891
📒 Files selected for processing (1)
browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts
Pressing spacebar while dragging vue nodes will now initiate a pan operation.
Followup to #8998