From c47cedcec26072b5467e56b16e584dc3df38a11b Mon Sep 17 00:00:00 2001 From: Simula_r <18093452+simula-r@users.noreply.github.com> Date: Mon, 29 Sep 2025 22:18:14 -0700 Subject: [PATCH] Fix/vue nodes tooltips (#5856) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Make vue node tooltips support color modes and hide when user drags node or zooms in or out. IMPORTANT: this approach is non ideal. But for sake of time its a valid escape hatch. The reason for this approach is because of how primevue exposes tooltips via a directive and the inability to modify its state / conditionally render it directly. Instead we must get the actual tooltip element from the dom and trigger a mouseleave event. Follow up PR would be refactoring the entire useNodeTooltip.ts composable and tooltip system from primevue to something like RekaUI which is a much more declarative approach. To start we could just refactor Vue nodes themselves to RekaUI tooltips and then later migrate the other instances. ## Changes - **What**: hide tooltips on drag and zoom. Use color themes ## Review Focus Tooltip hover states after dragging. Fixes: - https://www.notion.so/comfy-org/Bug-Fix-tooltip-appearing-when-clicking-and-dragging-Vue-node-header-2796d73d365081f692fdde30c51580e1?source=copy_link - https://www.notion.so/comfy-org/Bug-Fix-chevron-color-customization-in-tooltip-pseudo-element-27b6d73d3650814abc25fc0eefda1648?source=copy_link - https://www.notion.so/comfy-org/Bug-Bug-Tooltip-positioning-breaks-with-zoom-due-to-missing-appendTo-prop-27b6d73d36508186858bd1cb4336ec03?source=copy_link ## Screenshots (if applicable) https://github.com/user-attachments/assets/06c70f6c-bf64-4b6d-8e6f-739995549940 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5856-Fix-vue-nodes-tooltips-27e6d73d36508177a77bf7f2f27344f4) by [Unito](https://www.unito.io) --------- Co-authored-by: Jake Schroeder --- .../vueNodes/components/NodeHeader.vue | 2 +- .../vueNodes/composables/useNodeTooltips.ts | 94 +++++++++++++++++-- 2 files changed, 89 insertions(+), 7 deletions(-) diff --git a/src/renderer/extensions/vueNodes/components/NodeHeader.vue b/src/renderer/extensions/vueNodes/components/NodeHeader.vue index 4f84ff5319..7f97bf1330 100644 --- a/src/renderer/extensions/vueNodes/components/NodeHeader.vue +++ b/src/renderer/extensions/vueNodes/components/NodeHeader.vue @@ -4,7 +4,7 @@
{ + // Get all visible tooltip elements + const tooltips = document.querySelectorAll('.p-tooltip') + + // Early return if no tooltips are visible + if (tooltips.length === 0) return + + tooltips.forEach((tooltipEl) => { + const tooltipId = tooltipEl.id + if (!tooltipId) return + + // Find the target element that owns this tooltip + const targetElements = document.querySelectorAll('[data-pd-tooltip="true"]') + for (const targetEl of targetElements) { + if ((targetEl as any).$_ptooltipId === tooltipId) { + ;(targetEl as HTMLElement).dispatchEvent( + new MouseEvent('mouseleave', { bubbles: true }) + ) + break + } + } + }) + + // Disable tooltips temporarily after hiding (for drag operations) + tooltipsTemporarilyDisabled.value = true +} + +/** + * Re-enable tooltips after pointer interaction ends + */ +const handlePointerUp = () => { + tooltipsTemporarilyDisabled.value = false +} + +// Global tooltip hiding system +const globalTooltipState = { listenersSetup: false } + +function setupGlobalTooltipHiding() { + if (globalTooltipState.listenersSetup) return + + document.addEventListener('pointerdown', hideTooltipsGlobally) + document.addEventListener('pointerup', handlePointerUp) + window.addEventListener('wheel', hideTooltipsGlobally, { + capture: true, //Need this to bypass the event layer from Litegraph + passive: true + }) + + globalTooltipState.listenersSetup = true +} /** * Composable for managing Vue node tooltips @@ -18,6 +84,9 @@ export function useNodeTooltips( const nodeDefStore = useNodeDefStore() const settingsStore = useSettingStore() + // Setup global pointerdown listener once + setupGlobalTooltipHiding() + // Check if tooltips are globally enabled const tooltipsEnabled = computed(() => settingsStore.get('Comfy.EnableTooltips') @@ -76,6 +145,7 @@ export function useNodeTooltips( /** * Create tooltip configuration object for v-tooltip directive + * Components wrap this in computed() for reactivity */ const createTooltipConfig = (text: string) => { const tooltipDelay = settingsStore.get('LiteGraph.Node.TooltipDelay') @@ -84,21 +154,33 @@ export function useNodeTooltips( const config: { value: string showDelay: number + hideDelay: number disabled: boolean appendTo?: HTMLElement pt?: TooltipDirectivePassThroughOptions } = { value: tooltipText, showDelay: tooltipDelay as number, - disabled: !tooltipsEnabled.value || !tooltipText, + hideDelay: 0, // Immediate hiding + disabled: + !tooltipsEnabled.value || + !tooltipText || + tooltipsTemporarilyDisabled.value, // this reactive value works but only on next mount, + // so if the tooltip is already visible changing this will not hide it pt: { text: { class: - 'bg-pure-white dark-theme:bg-charcoal-800 border dark-theme:border-slate-300 rounded-md px-4 py-2 text-charcoal-700 dark-theme:text-pure-white text-sm font-normal leading-tight max-w-75 shadow-none' + 'border-sand-100 bg-pure-white dark-theme:bg-charcoal-800 border dark-theme:border-slate-300 rounded-md px-4 py-2 text-charcoal-700 dark-theme:text-pure-white text-sm font-normal leading-tight max-w-75 shadow-none' }, - arrow: { - class: 'before:border-slate-300' - } + arrow: ({ context }) => ({ + class: cn( + context?.top && 'border-t-sand-100 dark-theme:border-t-slate-300', + context?.bottom && + 'border-b-sand-100 dark-theme:border-b-slate-300', + context?.left && 'border-l-sand-100 dark-theme:border-l-slate-300', + context?.right && 'border-r-sand-100 dark-theme:border-r-slate-300' + ) + }) } }