Files
ComfyUI_frontend/src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue
2025-12-13 09:48:04 -08:00

126 lines
3.4 KiB
Vue

<script setup lang="ts">
import InputNumber from 'primevue/inputnumber'
import { computed } from 'vue'
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
import { cn } from '@/utils/tailwindUtil'
import {
INPUT_EXCLUDED_PROPS,
filterWidgetProps
} from '@/utils/widgetPropFilter'
import { WidgetInputBaseClass } from './layout'
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
const props = defineProps<{
widget: SimplifiedWidget<number>
}>()
const modelValue = props.widget.value()
const filteredProps = computed(() =>
filterWidgetProps(props.widget.options, INPUT_EXCLUDED_PROPS)
)
// Get the precision value for proper number formatting
const precision = computed(() => {
const p = props.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 (props.widget.options?.step2 !== undefined) {
return Number(props.widget.options.step2)
}
// Otherwise, derive from precision
if (precision.value !== undefined) {
if (precision.value === 0) {
return 1
}
// For precision > 0, step = 1 / (10^precision)
// precision 1 → 0.1, precision 2 → 0.01, etc.
return Number((1 / Math.pow(10, precision.value)).toFixed(precision.value))
}
// Default to 'any' for unrestricted stepping
return 0
})
// Disable grouping separators by default unless explicitly enabled by the node author
const useGrouping = computed(() => {
return props.widget.options?.useGrouping === true
})
// Check if increment/decrement buttons should be disabled due to precision limits
const buttonsDisabled = computed(() => {
const currentValue = modelValue.value ?? 0
return (
!Number.isFinite(currentValue) ||
Math.abs(currentValue) > Number.MAX_SAFE_INTEGER
)
})
const buttonTooltip = computed(() => {
if (buttonsDisabled.value) {
return 'Increment/decrement disabled: value exceeds JavaScript precision limit (±2^53)'
}
return null
})
</script>
<template>
<WidgetLayoutField :widget>
<InputNumber
v-model="modelValue"
v-tooltip="buttonTooltip"
v-bind="filteredProps"
fluid
button-layout="horizontal"
size="small"
variant="outlined"
:step="stepValue"
:min-fraction-digits="precision"
:max-fraction-digits="precision"
:use-grouping="useGrouping"
:class="cn(WidgetInputBaseClass, 'grow text-xs')"
:aria-label="widget.name"
:show-buttons="!buttonsDisabled"
:pt="{
root: {
class: cn(
'[&>input]:bg-transparent [&>input]:border-0',
'[&>input]:truncate [&>input]:min-w-[4ch]',
$slots.default && '[&>input]:pr-7'
)
},
decrementButton: {
class: 'w-8 border-0'
},
incrementButton: {
class: 'w-8 border-0'
}
}"
>
<template #incrementicon>
<span class="pi pi-plus text-sm" />
</template>
<template #decrementicon>
<span class="pi pi-minus text-sm" />
</template>
</InputNumber>
<div class="absolute top-5 right-8 h-4 w-7 -translate-y-4/5">
<slot />
</div>
</WidgetLayoutField>
</template>
<style scoped>
:deep(.p-inputnumber-input) {
height: 1.625rem;
margin: 1px 0;
box-shadow: none;
}
</style>