Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit 4c3fe99

Browse files
committed
Added a proper invalidation system for input
1 parent 8d2e3ac commit 4c3fe99

File tree

1 file changed

+21
-13
lines changed

1 file changed

+21
-13
lines changed

ui-components/Input.vue

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
<template>
2-
<div :class="base()">
2+
<div :class="inputStyle.base()">
33
<input
44
:id="$props.id"
55
:type="$props.type"
66
:placeholder="$props.label"
77
:disabled="$props.disabled"
8-
:class="input()"
8+
:class="inputStyle.input()"
99
:value="$props.value || $props.modelValue"
1010
@input="emitUpdate"
11-
:pattern="pattern"
1211
/>
13-
<label :for="$props.id" :class="label()">
12+
<label :for="$props.id" :class="inputStyle.label()">
1413
{{ $props.label }}
1514
</label>
16-
<small :class="small()">
15+
<small v-if="$props.helper" :class="inputStyle.small()">
1716
<span>{{ $props.helper }}</span>
1817
</small>
1918
</div>
@@ -24,18 +23,23 @@ import { tv, type VariantProps } from 'tailwind-variants'
2423
const inputTV = tv({
2524
slots: {
2625
base: 'relative flex flex-col',
27-
input: 'peer relative w-full outline-none transition-all disabled:cursor-not-allowed',
26+
input: 'peer relative w-full placeholder-transparent outline-none transition-all disabled:cursor-not-allowed',
2827
label: 'absolute z-[1] transition-all',
2928
small: 'flex w-full justify-between transition-all'
3029
},
3130
variants: {
3231
variant: {
3332
default: {
34-
label:
35-
'bg-body-light text-primary-500 peer-invalid:text-red-500 peer-focus:text-primary-800 peer-disabled:text-stone-400',
33+
label: 'bg-body-light text-primary-500 peer-focus:text-primary-600 peer-disabled:text-stone-400',
3634
input:
37-
'rounded border-2 border-primary-500 text-primary-950 placeholder-transparent invalid:border-red-500 focus:border-primary-700 disabled:border-stone-400 disabled:bg-transparent',
38-
small: 'text-primary-500 peer-invalid:text-red-500 peer-focus:text-primary-800 peer-disabled:text-stone-400'
35+
'rounded border-2 border-primary-500 text-primary-950 focus:border-primary-600 disabled:border-stone-400 disabled:bg-transparent',
36+
small: 'text-primary-500 peer-focus:text-primary-600 peer-disabled:text-stone-400'
37+
}
38+
},
39+
invalid: {
40+
true: {
41+
label: 'text-red-500 peer-focus:text-red-600',
42+
input: ' border-red-500 text-primary-950 focus:border-red-600'
3943
}
4044
},
4145
size: {
@@ -82,6 +86,7 @@ type Props = {
8286
value?: string | number | null
8387
modelValue?: string | number | null
8488
disabled?: boolean
89+
invalid?: boolean
8590
pattern?: string
8691
type?: 'text' | 'password' | 'number'
8792
@@ -106,8 +111,11 @@ const props = withDefaults(defineProps<Props>(), {
106111
type: 'text'
107112
})
108113
109-
const { base, input, small, label } = inputTV({
110-
size: props.size,
111-
variant: props.variant
114+
const inputStyle = computed(() => {
115+
return inputTV({
116+
size: props.size,
117+
variant: props.variant,
118+
invalid: props.invalid
119+
})
112120
})
113121
</script>

0 commit comments

Comments
 (0)