diff --git a/src/runtime/components/Input.vue b/src/runtime/components/Input.vue index dfa0c1d1b3..3d91fcac55 100644 --- a/src/runtime/components/Input.vue +++ b/src/runtime/components/Input.vue @@ -136,12 +136,15 @@ function updateInput(value: string | null | undefined) { value = looseToNumber(value) } - if (props.modelModifiers?.nullable) { - value ||= null + // Only empty values are mapped, `0` is a value on its own with the `number` modifier + const isEmpty = value === '' || value === null || value === undefined + + if (props.modelModifiers?.nullable && isEmpty) { + value = null } - if (props.modelModifiers?.optional && !props.modelModifiers?.nullable && value !== null) { - value ||= undefined + if (props.modelModifiers?.optional && !props.modelModifiers?.nullable && value !== null && isEmpty) { + value = undefined } modelValue.value = value as ApplyModifiers diff --git a/src/runtime/components/Textarea.vue b/src/runtime/components/Textarea.vue index 3d8db04bfa..93d35fc259 100644 --- a/src/runtime/components/Textarea.vue +++ b/src/runtime/components/Textarea.vue @@ -134,12 +134,15 @@ function updateInput(value: string | null | undefined) { value = looseToNumber(value) } - if (props.modelModifiers?.nullable) { - value ||= null + // Only empty values are mapped, `0` is a value on its own with the `number` modifier + const isEmpty = value === '' || value === null || value === undefined + + if (props.modelModifiers?.nullable && isEmpty) { + value = null } - if (props.modelModifiers?.optional && !props.modelModifiers?.nullable && value !== null) { - value ||= undefined + if (props.modelModifiers?.optional && !props.modelModifiers?.nullable && value !== null && isEmpty) { + value = undefined } modelValue.value = value as ApplyModifiers diff --git a/test/components/Input.spec.ts b/test/components/Input.spec.ts index 38f18abdf4..adbfffbd1a 100644 --- a/test/components/Input.spec.ts +++ b/test/components/Input.spec.ts @@ -56,7 +56,12 @@ describe('Input', () => { ['with .number modifier', { props: { modelModifiers: { number: true } } }, { input: '42', expected: 42 }], ['with .lazy modifier', { props: { modelModifiers: { lazy: true } } }, { input: 'input', expected: 'input' }], ['with .nullable modifier', { props: { modelModifiers: { nullable: true } } }, { input: '', expected: null }], - ['with .optional modifier', { props: { modelModifiers: { optional: true } } }, { input: '', expected: undefined }] + ['with .optional modifier', { props: { modelModifiers: { optional: true } } }, { input: '', expected: undefined }], + ['with .number and .nullable modifiers', { props: { modelModifiers: { number: true, nullable: true } } }, { input: '0', expected: 0 }], + ['with .number and .optional modifiers', { props: { modelModifiers: { number: true, optional: true } } }, { input: '0', expected: 0 }], + ['with .number and .nullable modifiers on an empty value', { props: { modelModifiers: { number: true, nullable: true } } }, { input: '', expected: null }], + ['with .number and .optional modifiers on an empty value', { props: { modelModifiers: { number: true, optional: true } } }, { input: '', expected: undefined }], + ['with number type and .nullable modifier', { props: { type: 'number', modelModifiers: { nullable: true } } }, { input: '0', expected: 0 }] ], '%s works', async (_nameOrHtml, options, spec) => { diff --git a/test/components/Textarea.spec.ts b/test/components/Textarea.spec.ts index 5e3d89b1ba..61b9ec67a1 100644 --- a/test/components/Textarea.spec.ts +++ b/test/components/Textarea.spec.ts @@ -69,7 +69,11 @@ describe('Textarea', () => { ['with .number modifier', { props: { modelModifiers: { number: true } } }, { input: '42', expected: 42 }], ['with .lazy modifier', { props: { modelModifiers: { lazy: true } } }, { input: 'input', expected: 'input' }], ['with .nullable modifier', { props: { modelModifiers: { nullable: true } } }, { input: '', expected: null }], - ['with .optional modifier', { props: { modelModifiers: { optional: true } } }, { input: '', expected: undefined }] + ['with .optional modifier', { props: { modelModifiers: { optional: true } } }, { input: '', expected: undefined }], + ['with .number and .nullable modifiers', { props: { modelModifiers: { number: true, nullable: true } } }, { input: '0', expected: 0 }], + ['with .number and .optional modifiers', { props: { modelModifiers: { number: true, optional: true } } }, { input: '0', expected: 0 }], + ['with .number and .nullable modifiers on an empty value', { props: { modelModifiers: { number: true, nullable: true } } }, { input: '', expected: null }], + ['with .number and .optional modifiers on an empty value', { props: { modelModifiers: { number: true, optional: true } } }, { input: '', expected: undefined }] ], '%s works', async (_, options, spec) => {