mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-07 14:09:59 +00:00
Fix/vue nodes tooltips (#5856)
## 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 <jake.schroeder@isophex.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="lg-node-header p-4 rounded-t-2xl w-full cursor-move"
|
||||
class="lg-node-header p-4 rounded-t-2xl cursor-move"
|
||||
:style="headerStyle"
|
||||
:data-testid="`node-header-${nodeData?.id || ''}`"
|
||||
@dblclick="handleDoubleClick"
|
||||
|
||||
@@ -1,11 +1,77 @@
|
||||
import type { TooltipDirectivePassThroughOptions } from 'primevue'
|
||||
import { type MaybeRef, type Ref, computed, unref } from 'vue'
|
||||
import { type MaybeRef, type Ref, computed, ref, unref } from 'vue'
|
||||
|
||||
import type { SafeWidgetData } from '@/composables/graph/useGraphNodeManager'
|
||||
import { st } from '@/i18n'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { useNodeDefStore } from '@/stores/nodeDefStore'
|
||||
import { normalizeI18nKey } from '@/utils/formatUtil'
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
|
||||
/**
|
||||
* Hide all visible tooltips by dispatching mouseleave events
|
||||
*
|
||||
*
|
||||
* IMPORTANT: this escape is needed for many reason due to primevue's directive tooltip system.
|
||||
* We cannot use PT to conditonally render the tooltips because the entire PT object only run
|
||||
* once during the intialization of the directive not every mount/unmount.
|
||||
* Once the directive is constructed its no longer reactive in the traditional sense.
|
||||
* We have to use something non destructive like mouseevents to dismiss the tooltip.
|
||||
*
|
||||
* TODO: use a better tooltip component like RekaUI for vue nodes specifically.
|
||||
*/
|
||||
|
||||
const tooltipsTemporarilyDisabled = ref(false)
|
||||
|
||||
const hideTooltipsGlobally = () => {
|
||||
// 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'
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user