mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-24 00:34:09 +00:00
145 lines
3.6 KiB
Vue
145 lines
3.6 KiB
Vue
<template>
|
|
<div
|
|
class="dom-widget"
|
|
:title="tooltip"
|
|
ref="widgetElement"
|
|
:style="style"
|
|
v-show="widgetState.visible"
|
|
>
|
|
<component
|
|
v-if="isComponentWidget(widget)"
|
|
:is="widget.component"
|
|
:modelValue="widget.value"
|
|
@update:modelValue="emit('update:widgetValue', $event)"
|
|
:widget="widget"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useEventListener } from '@vueuse/core'
|
|
import { CSSProperties, computed, onMounted, ref, watch } from 'vue'
|
|
|
|
import { useAbsolutePosition } from '@/composables/element/useAbsolutePosition'
|
|
import { useDomClipping } from '@/composables/element/useDomClipping'
|
|
import {
|
|
type BaseDOMWidget,
|
|
isComponentWidget,
|
|
isDOMWidget
|
|
} from '@/scripts/domWidget'
|
|
import { DomWidgetState } from '@/stores/domWidgetStore'
|
|
import { useCanvasStore } from '@/stores/graphStore'
|
|
import { useSettingStore } from '@/stores/settingStore'
|
|
|
|
const { widget, widgetState } = defineProps<{
|
|
widget: BaseDOMWidget<string | object>
|
|
widgetState: DomWidgetState
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'update:widgetValue', value: string | object): void
|
|
}>()
|
|
|
|
const widgetElement = ref<HTMLElement | undefined>()
|
|
|
|
const { style: positionStyle, updatePositionWithTransform } =
|
|
useAbsolutePosition()
|
|
const { style: clippingStyle, updateClipPath } = useDomClipping()
|
|
const style = computed<CSSProperties>(() => ({
|
|
...positionStyle.value,
|
|
...(enableDomClipping.value ? clippingStyle.value : {}),
|
|
zIndex: widgetState.zIndex,
|
|
pointerEvents: widgetState.readonly ? 'none' : 'auto'
|
|
}))
|
|
|
|
const canvasStore = useCanvasStore()
|
|
const settingStore = useSettingStore()
|
|
const enableDomClipping = computed(() =>
|
|
settingStore.get('Comfy.DOMClippingEnabled')
|
|
)
|
|
|
|
const updateDomClipping = () => {
|
|
const lgCanvas = canvasStore.canvas
|
|
if (!lgCanvas || !widgetElement.value) return
|
|
|
|
const selectedNode = Object.values(lgCanvas.selected_nodes ?? {})[0]
|
|
if (!selectedNode) return
|
|
|
|
const node = widget.node
|
|
const isSelected = selectedNode === node
|
|
const renderArea = selectedNode?.renderArea
|
|
const offset = lgCanvas.ds.offset
|
|
const scale = lgCanvas.ds.scale
|
|
const selectedAreaConfig = renderArea
|
|
? {
|
|
x: renderArea[0],
|
|
y: renderArea[1],
|
|
width: renderArea[2],
|
|
height: renderArea[3],
|
|
scale,
|
|
offset: [offset[0], offset[1]] as [number, number]
|
|
}
|
|
: undefined
|
|
|
|
updateClipPath(
|
|
widgetElement.value,
|
|
lgCanvas.canvas,
|
|
isSelected,
|
|
selectedAreaConfig
|
|
)
|
|
}
|
|
|
|
watch(
|
|
() => widgetState,
|
|
(newState) => {
|
|
updatePositionWithTransform(newState)
|
|
if (enableDomClipping.value) {
|
|
updateDomClipping()
|
|
}
|
|
},
|
|
{ deep: true }
|
|
)
|
|
|
|
watch(
|
|
() => widgetState.visible,
|
|
(newVisible, oldVisible) => {
|
|
if (!newVisible && oldVisible) {
|
|
widget.options.onHide?.(widget)
|
|
}
|
|
}
|
|
)
|
|
|
|
if (isDOMWidget(widget)) {
|
|
if (widget.element.blur) {
|
|
useEventListener(document, 'mousedown', (event) => {
|
|
if (!widget.element.contains(event.target as HTMLElement)) {
|
|
widget.element.blur()
|
|
}
|
|
})
|
|
}
|
|
|
|
for (const evt of widget.options.selectOn ?? ['focus', 'click']) {
|
|
useEventListener(widget.element, evt, () => {
|
|
const lgCanvas = canvasStore.canvas
|
|
lgCanvas?.selectNode(widget.node)
|
|
lgCanvas?.bringToFront(widget.node)
|
|
})
|
|
}
|
|
}
|
|
|
|
const inputSpec = widget.node.constructor.nodeData
|
|
const tooltip = inputSpec?.inputs?.[widget.name]?.tooltip
|
|
|
|
onMounted(() => {
|
|
if (isDOMWidget(widget) && widgetElement.value) {
|
|
widgetElement.value.appendChild(widget.element)
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.dom-widget > * {
|
|
@apply h-full w-full;
|
|
}
|
|
</style>
|