|
1 |
| -import { twMerge } from 'tailwind-merge' |
2 | 1 | import { computed, type Ref } from 'vue'
|
3 | 2 |
|
4 |
| -import { |
5 |
| - type InputSize, |
6 |
| - type ValidationStatus, |
7 |
| - validationStatusMap, |
8 |
| -} from '../types' |
| 3 | +import { type InputSize, type ValidationStatus, validationStatusMap } from '../types' |
9 | 4 |
|
10 |
| -// LABEL |
11 |
| -const baseLabelClasses = 'block mb-2 text-sm font-medium' |
| 5 | +import { useMergeClasses } from '@/composables/useMergeClasses' |
12 | 6 |
|
13 |
| -// INPUT |
14 |
| -const defaultInputClasses = 'block flex-grow w-full p-0 bg-transparent text-inherit ring-offset-0 ring-0 border-0 focus:ring-offset-0 focus:ring-0 focus:border-0' |
| 7 | +const defaultWrapperClasses = '' |
| 8 | +const defaultLabelClasses = 'block mb-2 text-sm font-medium' |
| 9 | +const defaultInputWrapperClasses = 'relative flex items-center has-[input:focus]:ring-offset-0 has-[input:focus]:ring-1 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg has-[input:focus]:ring-blue-500 has-[input:focus]:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:has-[input:focus]:ring-blue-500 dark:has-[input:focus]:border-blue-500' |
| 10 | +const defaultInputClasses = 'block flex-grow w-full p-0 bg-transparent text-inherit ring-offset-0 ring-0 border-0 focus:ring-offset-0 focus:ring-0 focus:border-0 dark:placeholder-gray-400' |
| 11 | +const defaultHelperClasses = 'mt-2 text-sm text-gray-500 dark:text-gray-400' |
15 | 12 |
|
16 |
| -// BLOCK |
17 |
| -const defaultBlockClasses = 'has-[input:focus]:ring-offset-0 has-[input:focus]:ring-1 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg has-[input:focus]:ring-blue-500 has-[input:focus]:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:has-[input:focus]:ring-blue-500 dark:has-[input:focus]:border-blue-500' |
| 13 | +const disabledInputWrapperClasses = 'bg-gray-100' |
| 14 | +const disabledInputClasses = 'cursor-not-allowed' |
18 | 15 |
|
19 |
| -const disabledInputClasses = 'cursor-not-allowed bg-gray-100' |
20 | 16 | const inputSizeClasses: Record<InputSize, string> = {
|
21 |
| - lg: 'p-4', |
22 |
| - md: 'p-2.5 text-sm', |
23 | 17 | sm: 'p-2 text-sm',
|
| 18 | + md: 'p-2.5 text-sm', |
| 19 | + lg: 'p-4', |
24 | 20 | }
|
25 | 21 |
|
26 |
| -const successInputClasses = 'bg-green-50 border-green-500 dark:border-green-500 text-green-900 dark:text-green-400 placeholder-green-700 dark:placeholder-green-500 has-[input:focus]:ring-green-500 has-[input:focus]:border-green-500' |
27 |
| -const errorInputClasses = 'bg-red-50 border-red-500 text-red-900 placeholder-red-700 has-[input:focus]:ring-red-500 has-[input:focus]:border-red-500 dark:text-red-500 dark:placeholder-red-500 dark:border-red-500' |
| 22 | +const errorInputWrapperClasses = 'bg-red-50 border-red-500 text-red-900 placeholder-red-700 has-[input:focus]:ring-red-500 has-[input:focus]:border-red-500 dark:text-red-500 dark:placeholder-red-500 dark:border-red-500' |
| 23 | +const errorTextClasses = 'text-red-700 dark:text-red-500' |
| 24 | +const successInputWrapperClasses = 'bg-green-50 border-green-500 dark:border-green-500 text-green-900 dark:text-green-400 placeholder-green-700 dark:placeholder-green-500 has-[input:focus]:ring-green-500 has-[input:focus]:border-green-500 ' |
| 25 | +const successTextClasses = 'text-green-700 dark:text-green-500' |
| 26 | +const errorInputClasses = 'text-red-900 placeholder-red-700 dark:placeholder-red-500' |
| 27 | +const successInputClasses = 'text-green-900 dark:text-green-400 placeholder-green-700 dark:placeholder-green-500' |
28 | 28 |
|
29 | 29 | export type UseInputClassesProps = {
|
30 |
| - size: Ref<InputSize> |
| 30 | + class: Ref<string | Record<string, boolean>> |
31 | 31 | disabled: Ref<boolean>
|
| 32 | + inputClass: Ref<string | Record<string, boolean>> |
| 33 | + labelClass: Ref<string | Record<string, boolean>> |
| 34 | + size: Ref<InputSize> |
32 | 35 | validationStatus: Ref<ValidationStatus | undefined>
|
| 36 | + wrapperClass: Ref<string | Record<string, boolean>> |
33 | 37 | }
|
34 | 38 |
|
35 | 39 | export function useInputClasses (props: UseInputClassesProps): {
|
36 |
| - inputBlockClasses: Ref<string> |
37 |
| - inputClasses: Ref<string> |
38 |
| - labelClasses: Ref<string> |
| 40 | + helperMessageClass: Ref<string> |
| 41 | + inputClass: Ref<string> |
| 42 | + inputWrapperClass: Ref<string> |
| 43 | + labelClass: Ref<string> |
| 44 | + validationMessageClass: Ref<string> |
| 45 | + wrapperClass: Ref<string> |
39 | 46 | } {
|
40 |
| - const inputBlockClasses = computed(() => { |
41 |
| - const vs = props.validationStatus.value |
| 47 | + const wrapperClass = computed(() => useMergeClasses([ |
| 48 | + defaultWrapperClasses, |
| 49 | + props.wrapperClass.value, |
| 50 | + ])) |
42 | 51 |
|
43 |
| - const classByStatus = vs === validationStatusMap.Success |
44 |
| - ? successInputClasses |
45 |
| - : vs === validationStatusMap.Error |
46 |
| - ? errorInputClasses |
47 |
| - : '' |
| 52 | + const labelClass = computed(() => useMergeClasses([ |
| 53 | + defaultLabelClasses, |
| 54 | + props.labelClass.value, |
| 55 | + props.validationStatus.value === validationStatusMap.Success |
| 56 | + ? successTextClasses |
| 57 | + : props.validationStatus.value === validationStatusMap.Error ? errorTextClasses : '', |
| 58 | + ])) |
48 | 59 |
|
49 |
| - return twMerge( |
50 |
| - defaultBlockClasses, |
51 |
| - classByStatus, |
52 |
| - props.disabled.value ? disabledInputClasses : '', |
53 |
| - ) |
54 |
| - }) |
| 60 | + const inputWrapperClass = computed(() => useMergeClasses([ |
| 61 | + defaultInputWrapperClasses, |
| 62 | + props.class.value, |
| 63 | + props.validationStatus.value === validationStatusMap.Success |
| 64 | + ? successInputWrapperClasses |
| 65 | + : props.validationStatus.value === validationStatusMap.Error ? errorInputWrapperClasses : '', |
| 66 | + props.disabled.value ? disabledInputWrapperClasses : '', |
| 67 | + ])) |
55 | 68 |
|
56 |
| - const inputClasses = computed(() => { |
57 |
| - return twMerge(defaultInputClasses, inputSizeClasses[props.size.value]) |
58 |
| - }) |
| 69 | + const inputClass = computed(() => useMergeClasses([ |
| 70 | + defaultInputClasses, |
| 71 | + inputSizeClasses[props.size.value], |
| 72 | + props.validationStatus.value === validationStatusMap.Success |
| 73 | + ? successInputClasses |
| 74 | + : props.validationStatus.value === validationStatusMap.Error ? errorInputClasses : '', |
| 75 | + props.inputClass.value, |
| 76 | + props.disabled.value ? disabledInputClasses : '', |
| 77 | + ])) |
59 | 78 |
|
60 |
| - const labelClasses = computed(() => { |
61 |
| - const vs = props.validationStatus.value |
62 |
| - const classByStatus = vs === validationStatusMap.Success |
63 |
| - ? 'text-green-700 dark:text-green-500' |
64 |
| - : vs === validationStatusMap.Error |
65 |
| - ? 'text-red-700 dark:text-red-500' |
66 |
| - : 'text-gray-900 dark:text-white' |
| 79 | + const validationMessageClass = computed(() => useMergeClasses([ |
| 80 | + defaultHelperClasses, |
| 81 | + props.validationStatus.value === validationStatusMap.Success |
| 82 | + ? successTextClasses |
| 83 | + : props.validationStatus.value === validationStatusMap.Error ? errorTextClasses : '', |
| 84 | + ])) |
67 | 85 |
|
68 |
| - return twMerge(baseLabelClasses, classByStatus) |
69 |
| - }) |
| 86 | + const helperMessageClass = computed(() => useMergeClasses([ |
| 87 | + defaultHelperClasses, |
| 88 | + ])) |
70 | 89 |
|
71 | 90 | return {
|
72 |
| - inputBlockClasses, |
73 |
| - inputClasses, |
74 |
| - labelClasses, |
| 91 | + helperMessageClass, |
| 92 | + inputClass, |
| 93 | + inputWrapperClass, |
| 94 | + labelClass, |
| 95 | + validationMessageClass, |
| 96 | + wrapperClass, |
75 | 97 | }
|
76 | 98 | }
|
0 commit comments