Files
ComfyUI_frontend/src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue
Johnpaul Chiwetelu b9cb335255 [fix] Add fraction digits props to number input widget (#7033)
Add min-fraction-digits and max-fraction-digits props to InputNumber
component to allow typing decimal values. Without these props, users
could not manually type values like "0.8" even though the increment
buttons worked correctly.

This aligns the input-only variant with the slider variant which
already had these props configured.

fix https://github.com/Comfy-Org/ComfyUI_frontend/issues/7016
## Screenshots (if applicable)



https://github.com/user-attachments/assets/fa205023-13c4-45ac-874b-b241808cf56d



┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7033-fix-Add-fraction-digits-props-to-number-input-widget-2b96d73d36508124ac65e466802bbb0c)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-11-29 15:10:04 -07:00

120 lines
3.3 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 = defineModel<number>({ default: 0 })
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:
'[&>input]:bg-transparent [&>input]:border-0 [&>input]:truncate [&>input]:min-w-[4ch]'
},
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>
</WidgetLayoutField>
</template>
<style scoped>
:deep(.p-inputnumber-input) {
height: 1.625rem;
margin: 1px 0;
box-shadow: none;
}
</style>