@@ -4,12 +4,13 @@ import theme from '#build/ui/textarea'
44import type { UseComponentIconsProps } from ' ../composables/useComponentIcons'
55import type { AvatarProps } from ' ../types'
66import type { ComponentConfig } from ' ../types/utils'
7+ import { useVModel } from ' @vueuse/core'
78
89type Textarea = ComponentConfig <typeof theme , AppConfig , ' textarea' >
910
1011type TextareaValue = string | number | null
1112
12- export interface TextareaProps extends UseComponentIconsProps {
13+ export interface TextareaProps < T extends AcceptableValue > extends UseComponentIconsProps {
1314 /**
1415 * The element or component this component should render as.
1516 * @defaultValue 'div'
@@ -41,8 +42,11 @@ export interface TextareaProps extends UseComponentIconsProps {
4142 maxrows? : number
4243 /** Highlight the ring color like a focus state. */
4344 highlight? : boolean
45+ modelValue? : T
46+ defaultValue? : T
4447 modelModifiers? : {
4548 string? : boolean
49+ number? : boolean
4650 trim? : boolean
4751 lazy? : boolean
4852 nullify? : boolean
@@ -66,7 +70,7 @@ export interface TextareaSlots {
6670
6771<script setup lang="ts" generic =" T extends TextareaValue " >
6872import { ref , computed , onMounted , nextTick , watch } from ' vue'
69- import { Primitive } from ' reka-ui'
73+ import { Primitive , type AcceptableValue } from ' reka-ui'
7074import { useAppConfig } from ' #imports'
7175import { useComponentIcons } from ' ../composables/useComponentIcons'
7276import { useFormField } from ' ../composables/useFormField'
@@ -77,7 +81,7 @@ import UAvatar from './Avatar.vue'
7781
7882defineOptions ({ inheritAttrs: false })
7983
80- const props = withDefaults (defineProps <TextareaProps >(), {
84+ const props = withDefaults (defineProps <TextareaProps < T > >(), {
8185 rows: 3 ,
8286 maxrows: 0 ,
8387 autofocusDelay: 0 ,
@@ -86,12 +90,11 @@ const props = withDefaults(defineProps<TextareaProps>(), {
8690const emits = defineEmits <TextareaEmits <T >>()
8791const slots = defineSlots <TextareaSlots >()
8892
89- // eslint-disable-next-line vue/no-dupe-keys
90- const [modelValue, modelModifiers] = defineModel <T >()
93+ const modelValue = useVModel <TextareaProps <T >, ' modelValue' , ' update:modelValue' >(props , ' modelValue' , emits , { defaultValue: props .defaultValue })
9194
9295const appConfig = useAppConfig () as Textarea [' AppConfig' ]
9396
94- const { emitFormFocus, emitFormBlur, emitFormInput, emitFormChange, size, color, id, name, highlight, disabled, ariaAttrs } = useFormField <TextareaProps >(props , { deferInputValidation: true })
97+ const { emitFormFocus, emitFormBlur, emitFormInput, emitFormChange, size, color, id, name, highlight, disabled, ariaAttrs } = useFormField <TextareaProps < T > >(props , { deferInputValidation: true })
9598const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons (props )
9699
97100const ui = computed (() => tv ({ extend: tv (theme ), ... (appConfig .ui ?.textarea || {}) })({
@@ -109,15 +112,15 @@ const textareaRef = ref<HTMLTextAreaElement | null>(null)
109112
110113// Custom function to handle the v-model properties
111114function updateInput(value : string | null ) {
112- if (modelModifiers .trim ) {
115+ if (props . modelModifiers ? .trim ) {
113116 value = value ?.trim () ?? null
114117 }
115118
116- if (modelModifiers .number ) {
119+ if (props . modelModifiers ? .number ) {
117120 value = looseToNumber (value )
118121 }
119122
120- if (modelModifiers .nullify ) {
123+ if (props . modelModifiers ? .nullify ) {
121124 value || = null
122125 }
123126
@@ -128,20 +131,20 @@ function updateInput(value: string | null) {
128131function onInput(event : Event ) {
129132 autoResize ()
130133
131- if (! modelModifiers .lazy ) {
134+ if (! props . modelModifiers ? .lazy ) {
132135 updateInput ((event .target as HTMLInputElement ).value )
133136 }
134137}
135138
136139function onChange(event : Event ) {
137140 const value = (event .target as HTMLInputElement ).value
138141
139- if (modelModifiers .lazy ) {
142+ if (props . modelModifiers ? .lazy ) {
140143 updateInput (value )
141144 }
142145
143146 // Update trimmed textarea so that it has same behavior as native textarea https://github.com/vuejs/core/blob/5ea8a8a4fab4e19a71e123e4d27d051f5e927172/packages/runtime-dom/src/directives/vModel.ts#L63
144- if (modelModifiers .trim ) {
147+ if (props . modelModifiers ? .trim ) {
145148 (event .target as HTMLInputElement ).value = value .trim ()
146149 }
147150
0 commit comments