diff --git a/docs/content/docs/1.getting-started/3.migration/1.v4.md b/docs/content/docs/1.getting-started/3.migration/1.v4.md index b7a9c58e15..9e2db6e09e 100644 --- a/docs/content/docs/1.getting-started/3.migration/1.v4.md +++ b/docs/content/docs/1.getting-started/3.migration/1.v4.md @@ -352,3 +352,24 @@ For more details on AI SDK v5 changes, review the **official AI SDK v5 migration ::tip{to="https://github.com/nuxt/ui/pull/4698" target="_blank"} View all changes from AI SDK v4 to v5 **in the upgrade PR** for a detailed migration reference. :: + +### Updated `modelModifiers` for `UInput` and `UTextarea` + +The `modelModifiers` shape used by `UInput` and `UTextarea` has changed in v4: + +- The `nullify` modifier was renamed to `nullable` (it converts empty/blank values to `null`). +- A new `optional` modifier was added (it converts empty/blank values to `undefined`). + +Examples: + +```diff +- ++ +``` + +```diff +- ++ +``` + +Use `nullable` when you want empty values as `null`, and `optional` when you prefer `undefined` for absent values. diff --git a/src/runtime/components/Input.vue b/src/runtime/components/Input.vue index 43d57ae382..35bcbc1706 100644 --- a/src/runtime/components/Input.vue +++ b/src/runtime/components/Input.vue @@ -4,6 +4,7 @@ import type { AppConfig } from '@nuxt/schema' import theme from '#build/ui/input' import type { UseComponentIconsProps } from '../composables/useComponentIcons' import type { AvatarProps } from '../types' +import type { ModelModifiers } from '../types/input' import type { AcceptableValue } from '../types/utils' import type { ComponentConfig } from '../types/tv' @@ -41,13 +42,7 @@ export interface InputProps extends highlight?: boolean modelValue?: T defaultValue?: T - modelModifiers?: { - string?: boolean - number?: boolean - trim?: boolean - lazy?: boolean - nullify?: boolean - } + modelModifiers?: ModelModifiers class?: any ui?: Input['slots'] } @@ -113,7 +108,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.input || {}) const inputRef = ref(null) // Custom function to handle the v-model properties -function updateInput(value: string | null) { +function updateInput(value: string | null | undefined) { if (props.modelModifiers?.trim) { value = value?.trim() ?? null } @@ -122,10 +117,14 @@ function updateInput(value: string | null) { value = looseToNumber(value) } - if (props.modelModifiers?.nullify) { + if (props.modelModifiers?.nullable) { value ||= null } + if (props.modelModifiers?.optional) { + value ||= undefined + } + modelValue.value = value as T emitFormInput() } diff --git a/src/runtime/components/InputNumber.vue b/src/runtime/components/InputNumber.vue index ec790ff163..4fc119a2c9 100644 --- a/src/runtime/components/InputNumber.vue +++ b/src/runtime/components/InputNumber.vue @@ -3,6 +3,7 @@ import type { NumberFieldRootProps } from 'reka-ui' import type { AppConfig } from '@nuxt/schema' import theme from '#build/ui/input-number' import type { ButtonProps, IconProps } from '../types' +import type { ModelModifiers } from '../types/input' import type { ComponentConfig } from '../types/tv' type InputNumber = ComponentConfig @@ -53,6 +54,9 @@ export interface InputNumberProps extends Pick /** * The locale to use for formatting and parsing numbers. * @defaultValue UApp.locale.code @@ -77,7 +81,7 @@ export interface InputNumberSlots {