fix(Input/Textarea): handle generic types

Resolves nuxt/ui-pro#887
This commit is contained in:
Benjamin Canac
2025-05-13 17:18:06 +02:00
parent 67da90a2f6
commit 3c8d6cd01d
2 changed files with 14 additions and 14 deletions

View File

@@ -4,7 +4,7 @@ import type { AppConfig } from '@nuxt/schema'
import theme from '#build/ui/input' import theme from '#build/ui/input'
import type { UseComponentIconsProps } from '../composables/useComponentIcons' import type { UseComponentIconsProps } from '../composables/useComponentIcons'
import type { AvatarProps } from '../types' import type { AvatarProps } from '../types'
import type { ComponentConfig } from '../types/utils' import type { AcceptableValue, ComponentConfig } from '../types/utils'
type Input = ComponentConfig<typeof theme, AppConfig, 'input'> type Input = ComponentConfig<typeof theme, AppConfig, 'input'>
@@ -42,8 +42,8 @@ export interface InputProps extends UseComponentIconsProps {
ui?: Input['slots'] ui?: Input['slots']
} }
export interface InputEmits { export interface InputEmits<T extends AcceptableValue = AcceptableValue> {
(e: 'update:modelValue', payload: string | number): void (e: 'update:modelValue', payload: T): void
(e: 'blur', event: FocusEvent): void (e: 'blur', event: FocusEvent): void
(e: 'change', event: Event): void (e: 'change', event: Event): void
} }
@@ -55,7 +55,7 @@ export interface InputSlots {
} }
</script> </script>
<script setup lang="ts"> <script setup lang="ts" generic="T extends AcceptableValue">
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { Primitive } from 'reka-ui' import { Primitive } from 'reka-ui'
import { useAppConfig } from '#imports' import { useAppConfig } from '#imports'
@@ -74,10 +74,10 @@ const props = withDefaults(defineProps<InputProps>(), {
autocomplete: 'off', autocomplete: 'off',
autofocusDelay: 0 autofocusDelay: 0
}) })
const emits = defineEmits<InputEmits>() const emits = defineEmits<InputEmits<T>>()
const slots = defineSlots<InputSlots>() const slots = defineSlots<InputSlots>()
const [modelValue, modelModifiers] = defineModel<string | number | null>() const [modelValue, modelModifiers] = defineModel<T>()
const appConfig = useAppConfig() as Input['AppConfig'] const appConfig = useAppConfig() as Input['AppConfig']
const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled, emitFormFocus, ariaAttrs } = useFormField<InputProps>(props, { deferInputValidation: true }) const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled, emitFormFocus, ariaAttrs } = useFormField<InputProps>(props, { deferInputValidation: true })
@@ -114,7 +114,7 @@ function updateInput(value: string | null) {
value ||= null value ||= null
} }
modelValue.value = value modelValue.value = value as T
emitFormInput() emitFormInput()
} }

View File

@@ -3,7 +3,7 @@ import type { AppConfig } from '@nuxt/schema'
import theme from '#build/ui/textarea' import theme from '#build/ui/textarea'
import type { UseComponentIconsProps } from '../composables/useComponentIcons' import type { UseComponentIconsProps } from '../composables/useComponentIcons'
import type { AvatarProps } from '../types' import type { AvatarProps } from '../types'
import type { ComponentConfig } from '../types/utils' import type { AcceptableValue, ComponentConfig } from '../types/utils'
type Textarea = ComponentConfig<typeof theme, AppConfig, 'textarea'> type Textarea = ComponentConfig<typeof theme, AppConfig, 'textarea'>
@@ -43,8 +43,8 @@ export interface TextareaProps extends UseComponentIconsProps {
ui?: Textarea['slots'] ui?: Textarea['slots']
} }
export interface TextareaEmits { export interface TextareaEmits<T extends AcceptableValue = AcceptableValue> {
(e: 'update:modelValue', payload: string | number): void (e: 'update:modelValue', payload: T): void
(e: 'blur', event: FocusEvent): void (e: 'blur', event: FocusEvent): void
(e: 'change', event: Event): void (e: 'change', event: Event): void
} }
@@ -56,7 +56,7 @@ export interface TextareaSlots {
} }
</script> </script>
<script setup lang="ts"> <script setup lang="ts" generic="T extends AcceptableValue">
import { ref, computed, onMounted, nextTick, watch } from 'vue' import { ref, computed, onMounted, nextTick, watch } from 'vue'
import { Primitive } from 'reka-ui' import { Primitive } from 'reka-ui'
import { useAppConfig } from '#imports' import { useAppConfig } from '#imports'
@@ -73,10 +73,10 @@ const props = withDefaults(defineProps<TextareaProps>(), {
autofocusDelay: 0, autofocusDelay: 0,
autoresizeDelay: 0 autoresizeDelay: 0
}) })
const emits = defineEmits<TextareaEmits<T>>()
const slots = defineSlots<TextareaSlots>() const slots = defineSlots<TextareaSlots>()
const emits = defineEmits<TextareaEmits>()
const [modelValue, modelModifiers] = defineModel<string | number | null>() const [modelValue, modelModifiers] = defineModel<T>()
const appConfig = useAppConfig() as Textarea['AppConfig'] const appConfig = useAppConfig() as Textarea['AppConfig']
const { emitFormFocus, emitFormBlur, emitFormInput, emitFormChange, size, color, id, name, highlight, disabled, ariaAttrs } = useFormField<TextareaProps>(props, { deferInputValidation: true }) const { emitFormFocus, emitFormBlur, emitFormInput, emitFormChange, size, color, id, name, highlight, disabled, ariaAttrs } = useFormField<TextareaProps>(props, { deferInputValidation: true })
@@ -109,7 +109,7 @@ function updateInput(value: string | null) {
value ||= null value ||= null
} }
modelValue.value = value modelValue.value = value as T
emitFormInput() emitFormInput()
} }