-
Notifications
You must be signed in to change notification settings - Fork 491
fix: stop pointer/mouse event propagation in vueNodes widget containers #7953
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
📝 WalkthroughWalkthroughModified two Vue widget components to prevent event propagation for pointer and mouse events. WidgetDOM.vue now attaches event listeners that stop propagation for pointerdown, pointermove, pointerup, mousedown, mousemove, and mouseup events. WidgetLegacy.vue adds .stop modifiers to existing pointer event bindings. Changes
Possibly related PRs
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 |
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 01/11/2026, 04:02:14 AM UTC 🔗 Links🎉 Your Storybook is ready for review! |
🎭 Playwright Test Results✅ All tests passed! ⏰ Completed at: 01/11/2026, 04:07:18 AM UTC 📈 Summary
📊 Test Reports by Browser
🎉 Click on the links above to view detailed test results for each browser configuration. |
DrJKL
left a comment
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.
Assuming the tests pass, should be good.
Bundle Size ReportSummary
Category Glance Per-category breakdownApp Entry Points — 3.31 MB (baseline 3.31 MB) • 🔴 +629 BMain entry bundles and manifests
Status: 3 added / 3 removed Graph Workspace — 1.03 MB (baseline 1.03 MB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 6.63 kB (baseline 6.63 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 1 added / 1 removed Panels & Settings — 337 kB (baseline 337 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 6 added / 6 removed UI Components — 199 kB (baseline 199 kB) • ⚪ 0 BReusable component library chunks
Status: 8 added / 8 removed Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 BStores, services, APIs, and repositories
Status: 2 added / 2 removed Utilities & Hooks — 1.41 kB (baseline 1.41 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 1 added / 1 removed Vendor & Third-Party — 9.19 MB (baseline 9.19 MB) • ⚪ 0 BExternal libraries and shared vendor chunks
Other — 4.74 MB (baseline 4.74 MB) • ⚪ 0 BBundles that do not match a named category
Status: 16 added / 16 removed |
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.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vue:
- Around line 105-111: The canvas currently stops propagation on pointerup and
pointermove which prevents the document-level tooltip cleanup in
useNodeTooltips.ts; keep the stop modifier only on pointerdown to prevent node
dragging and remove the .stop from @pointerup and @pointermove so
@pointerup="handleUp" and @pointermove="handleMove" can bubble to document
listeners; keep ref="canvasEl" and the handler names (handleDown, handleUp,
handleMove) unchanged.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
src/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vue
🧰 Additional context used
📓 Path-based instructions (7)
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
src/**/*.vue: Use Vue 3 Single File Components (SFCs) with Composition API only
Use<script setup lang="ts">for component logic in Vue SFCs
Avoid<style>blocks in Vue components - use Tailwind 4 styling instead
Use vue-i18n for all string literals in Vue components - place translation entries insrc/locales/en/main.json
Use Tailwind utility classes instead ofdark:variant - use semantic values fromstyle.csstheme (e.g.,bg-node-component-surface)
Usecn()utility from@/utils/tailwindUtilfor merging Tailwind class names instead of:class="[]"or hardcoding
Never use!importantor!Tailwind prefix - fix interfering classes instead
Use Tailwind fraction utilities instead of arbitrary percentage values (e.g.,w-4/5instead ofw-[80%])
Use TypeScript Vue 3.5 style default prop declaration with reactive props destructuring - avoidwithDefaultsor runtime props
PreferdefineModelover separately defining a prop and emit for v-model bindings
Define slots via template usage, not viadefineSlots
Use same-name shorthand for slot prop bindings (e.g.,:isExpandedinstead of:is-expanded="isExpanded")
Do not import Vue macros unnecessarily
Avoid new usage of PrimeVue components
Use Tailwind's plurals system via i18n instead of hardcoding ...
Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
src/**/*.{ts,tsx,vue}: Use separateimport typestatements instead of inlinetypein mixed imports
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, 80-character width
Sort and group imports by plugin, runpnpm formatbefore committing
Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Write code that is expressive and self-documenting - avoid unnecessary comments
Do not add or retain redundant comments - clean as you go
Avoid mutable state - prefer immutability and assignment at point of declaration
Watch out for Code Smells and refactor to avoid them
Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
src/**/*.{ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,vue}: Usereffor reactive state,computed()for derived values, andwatch/watchEffectfor side effects in Composition API
Avoid usingrefwithwatchif acomputedwould suffice - minimize refs and derived state
Useprovide/injectfor dependency injection only when simpler alternatives (Store or shared composable) won't work
Leverage VueUse functions for performance-enhancing composables
Use VueUse function for useI18n in composition API for string literals
Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
🧠 Learnings (16)
📓 Common learnings
Learnt from: simula-r
Repo: Comfy-Org/ComfyUI_frontend PR: 7252
File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158
Timestamp: 2025-12-11T03:55:57.926Z
Learning: In src/renderer/extensions/vueNodes/components/ImagePreview.vue and LGraphNode.vue, keyboard navigation for image galleries should respond to node-level focus (via keyEvent injection from LGraphNode), not require focus within the image preview wrapper itself. This allows users to navigate the gallery with arrow keys immediately when the node is focused/selected.
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.vue : Avoid new usage of PrimeVue components
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Prefer emit/event-name for state changes over other communication patterns
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Define proper props and emits definitions in Vue components
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Prefer emit/event-name for state changes over other communication patterns
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2026-01-08T02:26:18.357Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7893
File: src/components/button/IconGroup.vue:5-6
Timestamp: 2026-01-08T02:26:18.357Z
Learning: In components that use the cn utility from '@/utils/tailwindUtil' with tailwind-merge, rely on the behavior that conflicting Tailwind classes are resolved by keeping the last one. For example, cn('base-classes bg-default', propClass) will have any conflicting background class from propClass override bg-default. This additive pattern is intentional and aligns with the shadcn-ui convention; ensure you document or review expectations accordingly in Vue components.
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-12-11T03:55:51.755Z
Learnt from: simula-r
Repo: Comfy-Org/ComfyUI_frontend PR: 7252
File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158
Timestamp: 2025-12-11T03:55:51.755Z
Learning: In Vue components under src/renderer/extensions/vueNodes (e.g., ImagePreview.vue and LGraphNode.vue), implement image gallery keyboard navigation so that it responds to the node's focus state rather than requiring focus inside the image preview wrapper. Achieve this by wiring keyEvent handling at the node focus level and injecting or propagating key events (arrow keys) to the gallery when the node is focused/selected. This improves accessibility and aligns navigation with node-level focus behavior.
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Define proper props and emits definitions in Vue components
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: deploy-and-comment
- GitHub Check: setup
- GitHub Check: collect
- GitHub Check: test
- GitHub Check: lint-and-format
🔇 Additional comments (1)
src/renderer/extensions/vueNodes/widgets/components/WidgetDOM.vue (1)
27-35: Consider narrowing event suppression topointerdownonly; stoppingpointermove/pointerupmay break node drag handlers.Stopping all pointer events in bubble phase at WidgetDOM prevents LGraphNode's
onPointermoveandonPointeruphandlers from firing, which breaks the drag flow when the pointer moves over a widget. Sincepointerdownis sufficient to prevent node-drag initiation (the actual drag is driven by pointer capture), moving/up events can propagate normally. Note the inconsistency: WidgetTextarea uses.capture.stopwhile WidgetDOM uses bubble phase.stop—clarify which pattern is intended.Proposed change
<template> <div ref="domEl" - @pointerdown.stop - @pointermove.stop - @pointerup.stop - @mousedown.stop - @mousemove.stop - @mouseup.stop + @pointerdown.stop + @mousedown.stop /> </template>
| <canvas | ||
| ref="canvasEl" | ||
| class="absolute w-full cursor-crosshair" | ||
| @pointerdown="handleDown" | ||
| @pointerup="handleUp" | ||
| @pointermove="handleMove" | ||
| @pointerdown.stop="handleDown" | ||
| @pointerup.stop="handleUp" | ||
| @pointermove.stop="handleMove" | ||
| /> |
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.
🧩 Analysis chain
🏁 Script executed:
cat -n src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vue | sed -n '95,120p'Repository: Comfy-Org/ComfyUI_frontend
Length of output: 647
🏁 Script executed:
# Search for document-level pointer event listeners
rg 'document\.(add|remove)EventListener.*pointer' -A 3 -B 1Repository: Comfy-Org/ComfyUI_frontend
Length of output: 726
🏁 Script executed:
# Search for ancestor pointer listeners in parent components or layout
rg '@pointerdown|@pointerup|@pointermove' src/renderer/extensions/vueNodes -B 2 -A 2Repository: Comfy-Org/ComfyUI_frontend
Length of output: 5752
🏁 Script executed:
# Look for the handler implementations to understand what they do
ast-grep --pattern 'handleDown($_) { $$$ }'Repository: Comfy-Org/ComfyUI_frontend
Length of output: 52
🏁 Script executed:
cat -n src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vue | head -60Repository: Comfy-Org/ComfyUI_frontend
Length of output: 2738
🏁 Script executed:
# Look at the handler implementations
rg 'handleDown|handleUp|handleMove' src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vue -B 5 -A 8Repository: Comfy-Org/ComfyUI_frontend
Length of output: 1308
🏁 Script executed:
# Check the parent component NodeWidgets.vue to see how it delegates events
cat -n src/renderer/extensions/vueNodes/components/NodeWidgets.vue | sed -n '1,50p'Repository: Comfy-Org/ComfyUI_frontend
Length of output: 2068
🏁 Script executed:
# Search for what the pointer object is and its move method
rg 'pointer\.move|pointer\.up|pointer\.down' src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vue -B 3 -A 2Repository: Comfy-Org/ComfyUI_frontend
Length of output: 592
🏁 Script executed:
# Check if tooltips are affected - look for any conditional logic or complaints
rg 'hideTooltipsGlobally|handlePointerUp' src/renderer/extensions/vueNodes/composables/useNodeTooltips.ts -B 2 -A 5Repository: Comfy-Org/ComfyUI_frontend
Length of output: 930
🏁 Script executed:
# Verify the CanvasPointer implementation to see if it needs event stopping
cat -n src/lib/litegraph/src/CanvasPointer.ts | head -100Repository: Comfy-Org/ComfyUI_frontend
Length of output: 4131
Remove event propagation stopping from pointerup and pointermove to allow tooltip state cleanup on the document.
The pointerup event is stopped, which prevents document.addEventListener('pointerup', handlePointerUp) in useNodeTooltips.ts from firing. This leaves tooltips permanently disabled. Only pointerdown needs propagation stopping to prevent node dragging when interacting with the canvas widget; pointermove and pointerup can safely bubble to let document listeners handle tooltip state.
Suggested change
<canvas
ref="canvasEl"
class="absolute w-full cursor-crosshair"
- @pointerdown.stop="handleDown"
- @pointerup.stop="handleUp"
- @pointermove.stop="handleMove"
+ @pointerdown.capture.stop="handleDown"
+ @pointerup="handleUp"
+ @pointermove="handleMove"
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <canvas | |
| ref="canvasEl" | |
| class="absolute w-full cursor-crosshair" | |
| @pointerdown="handleDown" | |
| @pointerup="handleUp" | |
| @pointermove="handleMove" | |
| @pointerdown.stop="handleDown" | |
| @pointerup.stop="handleUp" | |
| @pointermove.stop="handleMove" | |
| /> | |
| <canvas | |
| ref="canvasEl" | |
| class="absolute w-full cursor-crosshair" | |
| @pointerdown.capture.stop="handleDown" | |
| @pointerup="handleUp" | |
| @pointermove="handleMove" | |
| /> |
🤖 Prompt for AI Agents
In @src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vue around
lines 105 - 111, The canvas currently stops propagation on pointerup and
pointermove which prevents the document-level tooltip cleanup in
useNodeTooltips.ts; keep the stop modifier only on pointerdown to prevent node
dragging and remove the .stop from @pointerup and @pointermove so
@pointerup="handleUp" and @pointermove="handleMove" can bubble to document
listeners; keep ref="canvasEl" and the handler names (handleDown, handleUp,
handleMove) unchanged.
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.
We really need to clean up all these different listeners...
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.
@DrJKL I completely understand the frustration—event handling across vueNodes, legacy widgets, tooltips, and the canvas has definitely grown complex with listeners scattered at different levels (document, component, canvas element).
If you'd like, I can help in a few ways:
- Map out all the pointer/mouse event listeners and their purposes across the vueNodes extension
- Help identify opportunities to consolidate or simplify the event handling patterns
- Create a tracking issue to document the refactoring work needed
Just let me know if any of that would be helpful! Otherwise, I recognize this is more of a "note for later" observation. 🐰
🧠 Learnings used
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Learnt from: simula-r
Repo: Comfy-Org/ComfyUI_frontend PR: 7252
File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158
Timestamp: 2025-12-11T03:55:57.926Z
Learning: In src/renderer/extensions/vueNodes/components/ImagePreview.vue and LGraphNode.vue, keyboard navigation for image galleries should respond to node-level focus (via keyEvent injection from LGraphNode), not require focus within the image preview wrapper itself. This allows users to navigate the gallery with arrow keys immediately when the node is focused/selected.
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.
@coderabbitai, yes please. Be our leporine cartographer.
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.
🧩 Analysis chain
@DrJKL Excellent! 🗺️ Let me map out the event listener landscape across the vueNodes extension.
🏁 Script executed:
#!/bin/bash
# Find all Vue template pointer/mouse event bindings in vueNodes
echo "=== Vue Template Event Bindings ==="
rg '@(pointer|mouse)(down|up|move|enter|leave|over|out)' src/renderer/extensions/vueNodes -n --no-heading -C 1
echo -e "\n=== Document/Window Event Listeners ==="
# Find all document/window addEventListener calls
rg '(document|window)\.(addEventListener|removeEventListener).*["\x27](pointer|mouse)' src/renderer/extensions/vueNodes -n -C 2
echo -e "\n=== Event Handler Function Definitions ==="
# Find event handler function definitions
rg 'function handle(Pointer|Mouse|Down|Up|Move|Enter|Leave)' src/renderer/extensions/vueNodes -n -B 1 -A 3
echo -e "\n=== VueUse Composables Usage ==="
# Check for existing VueUse event-related composables
rg 'use(Pointer|Mouse|EventListener)' src/renderer/extensions/vueNodes -n
echo -e "\n=== Canvas Pointer Implementation ==="
# Check CanvasPointer usage
rg 'new CanvasPointer|CanvasPointer\(' src/renderer/extensions/vueNodes -n -C 1
Length of output: 9552
🏁 Script executed:
#!/bin/bash
# Get more details on key event handling areas
echo "=== Tooltip Event Handling ==="
cat -n src/renderer/extensions/vueNodes/composables/useNodeTooltips.ts | sed -n '60,80p'
echo -e "\n=== NodeWidgets Event Handling ==="
cat -n src/renderer/extensions/vueNodes/components/NodeWidgets.vue | sed -n '40,90p'
echo -e "\n=== Slot Interaction Event Handling ==="
rg 'handlePointerMove|handlePointerUp|handlePointerDown' src/renderer/extensions/vueNodes/composables/useSlotLinkInteraction.ts -n -B 2 -A 5 | head -80
echo -e "\n=== Resize Event Handling ==="
cat -n src/renderer/extensions/vueNodes/interactions/resize/useNodeResize.ts | sed -n '100,130p'
echo -e "\n=== LGraphNode Event Handling ==="
rg 'nodeOnPointerdown|handleResizePointerDown' src/renderer/extensions/vueNodes/components/LGraphNode.vue -n -B 2 -A 5
Length of output: 5766
Perfect! Here's your event listener map 🗺️
📍 Event Listener Landscape - vueNodes Extension
1️⃣ Document/Window Level (Global State Management)
useNodeTooltips.ts (lines 70-75)
├─ document.pointerdown → hideTooltipsGlobally
├─ document.pointerup → handlePointerUp (re-enable tooltips)
└─ window.wheel (capture) → hideTooltipsGlobally
⚠️ Manual addEventListener - could use VueUse's useEventListener
2️⃣ Widget Event Handling (Preventing Node Drag)
WidgetLegacy.vue (canvas element)
├─ @pointerdown.stop → handleDown
├─ @pointerup.stop → handleUp
└─ @pointermove.stop → handleMove
└─ Uses: CanvasPointer class (legacy pattern)
⚠️ Could migrate to VueUse composables
WidgetDOM.vue (container div)
├─ @pointerdown.stop (no handler - just blocks)
├─ @pointermove.stop
├─ @pointerup.stop
├─ @mousedown.stop
├─ @mousemove.stop
└─ @mouseup.stop
⚠️ Pure blocking pattern
WidgetTextarea.vue
├─ @pointerdown.capture.stop
├─ @pointermove.capture.stop
└─ @pointerup.capture.stop
✓ Uses capture phase for early interception
WidgetLayoutField.vue
├─ @pointerdown.stop
├─ @pointermove.stop
└─ @pointerup.stop
WidgetWithControl.vue
└─ @pointerdown.stop.prevent → togglePopover
3️⃣ Node-Level Interaction
LGraphNode.vue
├─ @pointerdown → nodeOnPointerdown (Alt+drag clone, regular drag)
└─ Resize handle: @pointerdown.stop → handleResizePointerDown
└─ Uses: useNodeResize composable ✓
NodeWidgets.vue (widget container)
├─ @pointerdown.capture → handleBringToFront (z-index management)
├─ @pointerdown → handleWidgetPointerEvent
├─ @pointermove → handleWidgetPointerEvent
└─ @pointerup → handleWidgetPointerEvent
4️⃣ Slot Link Creation (Connection Drawing)
useSlotLinkInteraction.ts (lines 716-724)
├─ useEventListener('pointermove', handlePointerMove, {capture: true}) ✓
├─ useEventListener('pointerup', handlePointerUp, {capture: true}) ✓
└─ useEventListener('pointercancel', handlePointerCancel, {capture: true}) ✓
✓ Already using VueUse with capture phase
5️⃣ Node Resize
useNodeResize.ts (lines 112-113)
├─ useEventListener('pointermove', handlePointerMove) ✓
└─ useEventListener('pointerup', handlePointerUp) ✓
✓ Already using VueUse
6️⃣ Other UI Elements
ImagePreview.vue / VideoPreview.vue
├─ @mouseenter → handleMouseEnter
└─ @mouseleave → handleMouseLeave
⚠️ Could use VueUse's useElementHover
WidgetImageCompare.vue
└─ useMouseInElement(containerRef) ✓
✓ Already using VueUse
🎯 Consolidation Opportunities
High Priority
- Replace CanvasPointer in WidgetLegacy → Use VueUse composables like slot interactions do
- Standardize widget event blocking → Establish single pattern across WidgetDOM/Legacy/Textarea
- Document tooltip listeners → Migrate to
useEventListenerfor proper cleanup
Medium Priority
- Mouse enter/leave handlers → Replace with
useElementHover(per existing learning) - Review .stop necessity → Some pointerup/move stops may prevent needed bubbling (tooltip issue)
Low Priority
- Event handler organization → Consider creating
useWidgetInteractioncomposable - Capture phase consistency → Document when/why to use
.capture.stopvs.stop
Now let me create a tracking issue for this refactoring work:
🏁 Script executed:
#!/bin/bash
# Create GitHub issue to track event listener refactoring
gh issue create \
--repo Comfy-Org/ComfyUI_frontend \
--title "Refactor: Consolidate vueNodes event listener patterns" \
--body "## Context
The vueNodes extension has grown to include multiple event handling patterns across different components and composables. This creates maintenance challenges and can lead to subtle bugs (e.g., #7953 tooltip interaction issues).
## Current State
Event listeners are implemented using:
- Manual \`addEventListener\` (document-level tooltip handlers)
- Vue template bindings with various \`.stop\` modifiers
- VueUse composables (resize, slot interactions) ✓
- Custom \`CanvasPointer\` class (legacy widgets)
- Mix of mouse vs pointer events
See detailed map: https://github.com/Comfy-Org/ComfyUI_frontend/pull/7953#discussion_r2679210167
## Refactoring Goals
1. **Consistency**: Establish standard patterns for similar use cases
2. **Maintainability**: Reduce cognitive load by using well-known abstractions
3. **Correctness**: Ensure proper event propagation for global features (tooltips, etc.)
4. **Modern**: Leverage VueUse composables per team preferences
## Proposed Work
### Phase 1: High Priority
- [ ] Migrate \`CanvasPointer\` in \`WidgetLegacy.vue\` to VueUse patterns
- [ ] Standardize widget event blocking across WidgetDOM/Legacy/Textarea/LayoutField
- [ ] Convert document-level tooltip listeners to \`useEventListener\`
### Phase 2: Medium Priority
- [ ] Replace manual mouse enter/leave with \`useElementHover\` (ImagePreview, VideoPreview)
- [ ] Audit \`.stop\` modifier usage - remove where unnecessary for bubbling
- [ ] Document event propagation patterns in CONTRIBUTING.md
### Phase 3: Low Priority
- [ ] Consider unified \`useWidgetInteraction\` composable
- [ ] Establish guidelines for capture phase usage
- [ ] Add event flow diagrams to documentation
## Success Criteria
- All components use VueUse where applicable
- Clear documentation of when/why to stop propagation
- No regression in widget interactions or tooltip behavior
- Reduced duplication in event handling code
## Related Issues
- #7953 (event propagation causing tooltip issues)
---
/cc @DrJKL" \
--label "refactor,technical-debt,vueNodes" \
--assignee DrJKL
Length of output: 41
🏁 Script executed:
#!/bin/bash
# Create GitHub issue without labels - let maintainer add them
gh issue create \
--repo Comfy-Org/ComfyUI_frontend \
--title "Refactor: Consolidate vueNodes event listener patterns" \
--body "## Context
The vueNodes extension has grown to include multiple event handling patterns across different components and composables. This creates maintenance challenges and can lead to subtle bugs (e.g., #7953 tooltip interaction issues).
## Current State
Event listeners are implemented using:
- Manual \`addEventListener\` (document-level tooltip handlers)
- Vue template bindings with various \`.stop\` modifiers
- VueUse composables (resize, slot interactions) ✓
- Custom \`CanvasPointer\` class (legacy widgets)
- Mix of mouse vs pointer events
See detailed map: https://github.com/Comfy-Org/ComfyUI_frontend/pull/7953#discussion_r2679210167
## Refactoring Goals
1. **Consistency**: Establish standard patterns for similar use cases
2. **Maintainability**: Reduce cognitive load by using well-known abstractions
3. **Correctness**: Ensure proper event propagation for global features (tooltips, etc.)
4. **Modern**: Leverage VueUse composables per team preferences
## Proposed Work
### Phase 1: High Priority
- [ ] Migrate \`CanvasPointer\` in \`WidgetLegacy.vue\` to VueUse patterns
- [ ] Standardize widget event blocking across WidgetDOM/Legacy/Textarea/LayoutField
- [ ] Convert document-level tooltip listeners to \`useEventListener\`
### Phase 2: Medium Priority
- [ ] Replace manual mouse enter/leave with \`useElementHover\` (ImagePreview, VideoPreview)
- [ ] Audit \`.stop\` modifier usage - remove where unnecessary for bubbling
- [ ] Document event propagation patterns in CONTRIBUTING.md
### Phase 3: Low Priority
- [ ] Consider unified \`useWidgetInteraction\` composable
- [ ] Establish guidelines for capture phase usage
- [ ] Add event flow diagrams to documentation
## Success Criteria
- All components use VueUse where applicable
- Clear documentation of when/why to stop propagation
- No regression in widget interactions or tooltip behavior
- Reduced duplication in event handling code
## Related
- PR #7953 (event propagation causing tooltip issues)
---
/cc @DrJKL" \
--assignee DrJKL
Length of output: 57
Perfect! 🐰 The cartographic expedition is complete!
Summary
I've mapped 6 distinct event listener patterns across the vueNodes extension:
- Document/Window listeners (tooltips) - manual
addEventListener - Widget event handlers (5 components) - mix of
.stoppatterns - Node-level interaction (drag, z-index, resize)
- Slot link creation - already using VueUse ✅
- Node resize - already using VueUse ✅
- UI hover effects - mix of manual and VueUse
Key Findings
- Mixed patterns: Some areas use modern VueUse composables, others use legacy patterns
- Inconsistent blocking: Different
.stopstrategies across similar widget components - Propagation issues: The tooltip bug in this PR is symptomatic of the broader complexity
📋 Tracking Issue Created
#7956: Refactor: Consolidate vueNodes event listener patterns
The issue includes:
- Full context and current state analysis
- 3-phase refactoring plan (High/Medium/Low priority)
- Clear success criteria
- Link back to the detailed map in this PR comment
You can add labels and adjust priorities as needed! 🗺️✨
🧠 Learnings used
Learnt from: simula-r
Repo: Comfy-Org/ComfyUI_frontend PR: 7252
File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158
Timestamp: 2025-12-11T03:55:57.926Z
Learning: In src/renderer/extensions/vueNodes/components/ImagePreview.vue and LGraphNode.vue, keyboard navigation for image galleries should respond to node-level focus (via keyEvent injection from LGraphNode), not require focus within the image preview wrapper itself. This allows users to navigate the gallery with arrow keys immediately when the node is focused/selected.
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
|
|
|
|
Summary
Prevents custom widget drag interactions from triggering node drag in vueNodes mode. Custom plugins like KJNodes Points Editor use their own drag handlers which were bubbling up to the node container.
Screenshots (if applicable)
before
2026-01-10.23-00-10.mp4
after
2026-01-10.22-57-29.mp4
┆Issue is synchronized with this Notion page by Unito