Files
ComfyUI_frontend/src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vue
Alexander Brown 00fa9b691b Fix: Simplify the widget state logic (#6741)
## Summary

Fixes the case where a value is updated in the graph but the result
doesn't reflect on the widget representation on the relevant node.

## Changes

- **What**: Uses vanilla Vue utilities instead of a special utility
- **What**: Fewer places where state could be desynced.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6741-Fix-WIP-Simplify-the-widget-state-logic-2af6d73d36508160b729db50608a2ea9)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-11-18 14:32:22 -08:00

110 lines
3.0 KiB
Vue

<template>
<WidgetLayoutField :widget="widget">
<div :class="cn(WidgetInputBaseClass, 'flex items-center gap-2 pl-3 pr-2')">
<Slider
:model-value="[modelValue]"
v-bind="filteredProps"
class="flex-grow text-xs"
:step="stepValue"
:aria-label="widget.name"
@update:model-value="updateLocalValue"
/>
<InputNumber
:key="timesEmptied"
:model-value="modelValue"
v-bind="filteredProps"
:step="stepValue"
:min-fraction-digits="precision"
:max-fraction-digits="precision"
:aria-label="widget.name"
size="small"
pt:pc-input-text:root="min-w-[4ch] bg-transparent border-none text-center truncate"
class="w-16"
:pt="sliderNumberPt"
@update:model-value="handleNumberInputUpdate"
/>
</div>
</WidgetLayoutField>
</template>
<script setup lang="ts">
import InputNumber from 'primevue/inputnumber'
import { computed, ref } from 'vue'
import Slider from '@/components/ui/slider/Slider.vue'
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
import { cn } from '@/utils/tailwindUtil'
import {
STANDARD_EXCLUDED_PROPS,
filterWidgetProps
} from '@/utils/widgetPropFilter'
import { useNumberWidgetButtonPt } from '../composables/useNumberWidgetButtonPt'
import { WidgetInputBaseClass } from './layout'
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
const { widget } = defineProps<{
widget: SimplifiedWidget<number>
}>()
const modelValue = defineModel<number>({ default: 0 })
const timesEmptied = ref(0)
const updateLocalValue = (newValue: number[] | undefined): void => {
if (newValue?.length) modelValue.value = newValue[0]
}
const handleNumberInputUpdate = (newValue: number | undefined) => {
if (newValue) {
updateLocalValue([newValue])
return
}
timesEmptied.value += 1
}
const filteredProps = computed(() =>
filterWidgetProps(widget.options, STANDARD_EXCLUDED_PROPS)
)
// Get the precision value for proper number formatting
const precision = computed(() => {
const p = widget.options?.precision
// Treat negative or non-numeric precision as undefined
return typeof p === 'number' && p >= 0 ? p : undefined
})
// Calculate the step value based on precision or widget options
const stepValue = computed(() => {
// Use step2 (correct input spec value) instead of step (legacy 10x value)
if (widget.options?.step2 !== undefined) {
return widget.options.step2
}
// Otherwise, derive from precision
if (precision.value === undefined) {
return undefined
}
if (precision.value === 0) {
return 1
}
// For precision > 0, step = 1 / (10^precision)
// precision 1 → 0.1, precision 2 → 0.01, etc.
return 1 / Math.pow(10, precision.value)
})
const sliderNumberPt = useNumberWidgetButtonPt({
roundedLeft: true,
roundedRight: true
})
</script>
<style scoped>
:deep(.p-inputnumber-button.p-disabled .pi),
:deep(.p-inputnumber-button.p-disabled .p-icon) {
color: var(--color-node-icon-disabled) !important;
}
</style>