@@ -46,29 +43,26 @@
diff --git a/src/components/FwbInput/composables/useInputClasses.ts b/src/components/FwbInput/composables/useInputClasses.ts
index daec06af..aa244d65 100644
--- a/src/components/FwbInput/composables/useInputClasses.ts
+++ b/src/components/FwbInput/composables/useInputClasses.ts
@@ -1,76 +1,98 @@
-import { twMerge } from 'tailwind-merge'
import { computed, type Ref } from 'vue'
-import {
- type InputSize,
- type ValidationStatus,
- validationStatusMap,
-} from '../types'
+import { type InputSize, type ValidationStatus, validationStatusMap } from '../types'
-// LABEL
-const baseLabelClasses = 'block mb-2 text-sm font-medium'
+import { useMergeClasses } from '@/composables/useMergeClasses'
-// INPUT
-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'
+const defaultWrapperClasses = ''
+const defaultLabelClasses = 'block mb-2 text-sm font-medium'
+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'
+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'
+const defaultHelperClasses = 'mt-2 text-sm text-gray-500 dark:text-gray-400'
-// BLOCK
-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'
+const disabledInputWrapperClasses = 'bg-gray-100'
+const disabledInputClasses = 'cursor-not-allowed'
-const disabledInputClasses = 'cursor-not-allowed bg-gray-100'
const inputSizeClasses: Record
= {
- lg: 'p-4',
- md: 'p-2.5 text-sm',
sm: 'p-2 text-sm',
+ md: 'p-2.5 text-sm',
+ lg: 'p-4',
}
-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'
-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'
+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'
+const errorTextClasses = 'text-red-700 dark:text-red-500'
+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 '
+const successTextClasses = 'text-green-700 dark:text-green-500'
+const errorInputClasses = 'text-red-900 placeholder-red-700 dark:placeholder-red-500'
+const successInputClasses = 'text-green-900 dark:text-green-400 placeholder-green-700 dark:placeholder-green-500'
export type UseInputClassesProps = {
- size: Ref
+ class: Ref>
disabled: Ref
+ inputClass: Ref>
+ labelClass: Ref>
+ size: Ref
validationStatus: Ref
+ wrapperClass: Ref>
}
export function useInputClasses (props: UseInputClassesProps): {
- inputBlockClasses: Ref
- inputClasses: Ref
- labelClasses: Ref
+ helperMessageClass: Ref
+ inputClass: Ref
+ inputWrapperClass: Ref
+ labelClass: Ref
+ validationMessageClass: Ref
+ wrapperClass: Ref
} {
- const inputBlockClasses = computed(() => {
- const vs = props.validationStatus.value
+ const wrapperClass = computed(() => useMergeClasses([
+ defaultWrapperClasses,
+ props.wrapperClass.value,
+ ]))
- const classByStatus = vs === validationStatusMap.Success
- ? successInputClasses
- : vs === validationStatusMap.Error
- ? errorInputClasses
- : ''
+ const labelClass = computed(() => useMergeClasses([
+ defaultLabelClasses,
+ props.labelClass.value,
+ props.validationStatus.value === validationStatusMap.Success
+ ? successTextClasses
+ : props.validationStatus.value === validationStatusMap.Error ? errorTextClasses : '',
+ ]))
- return twMerge(
- defaultBlockClasses,
- classByStatus,
- props.disabled.value ? disabledInputClasses : '',
- )
- })
+ const inputWrapperClass = computed(() => useMergeClasses([
+ defaultInputWrapperClasses,
+ props.class.value,
+ props.validationStatus.value === validationStatusMap.Success
+ ? successInputWrapperClasses
+ : props.validationStatus.value === validationStatusMap.Error ? errorInputWrapperClasses : '',
+ props.disabled.value ? disabledInputWrapperClasses : '',
+ ]))
- const inputClasses = computed(() => {
- return twMerge(defaultInputClasses, inputSizeClasses[props.size.value])
- })
+ const inputClass = computed(() => useMergeClasses([
+ defaultInputClasses,
+ inputSizeClasses[props.size.value],
+ props.validationStatus.value === validationStatusMap.Success
+ ? successInputClasses
+ : props.validationStatus.value === validationStatusMap.Error ? errorInputClasses : '',
+ props.inputClass.value,
+ props.disabled.value ? disabledInputClasses : '',
+ ]))
- const labelClasses = computed(() => {
- const vs = props.validationStatus.value
- const classByStatus = vs === validationStatusMap.Success
- ? 'text-green-700 dark:text-green-500'
- : vs === validationStatusMap.Error
- ? 'text-red-700 dark:text-red-500'
- : 'text-gray-900 dark:text-white'
+ const validationMessageClass = computed(() => useMergeClasses([
+ defaultHelperClasses,
+ props.validationStatus.value === validationStatusMap.Success
+ ? successTextClasses
+ : props.validationStatus.value === validationStatusMap.Error ? errorTextClasses : '',
+ ]))
- return twMerge(baseLabelClasses, classByStatus)
- })
+ const helperMessageClass = computed(() => useMergeClasses([
+ defaultHelperClasses,
+ ]))
return {
- inputBlockClasses,
- inputClasses,
- labelClasses,
+ helperMessageClass,
+ inputClass,
+ inputWrapperClass,
+ labelClass,
+ validationMessageClass,
+ wrapperClass,
}
}
diff --git a/src/components/FwbInput/types.ts b/src/components/FwbInput/types.ts
index f752f235..157c6151 100644
--- a/src/components/FwbInput/types.ts
+++ b/src/components/FwbInput/types.ts
@@ -6,8 +6,8 @@ export type InputType = 'button' | 'checkbox' | 'color' | 'date' | 'datetime-loc
export type CommonAutoFill = 'on' | 'off' | 'email' | 'tel' | 'name' | 'username' | 'current-password' | 'country' | 'postal-code' | 'language' | 'bday'
export const validationStatusMap = {
- Success: 'success',
Error: 'error',
+ Success: 'success',
} as const
export type ValidationStatus = typeof validationStatusMap[keyof typeof validationStatusMap]
diff --git a/src/composables/useMergeClasses.ts b/src/composables/useMergeClasses.ts
index 8ca24660..ac6176ad 100644
--- a/src/composables/useMergeClasses.ts
+++ b/src/composables/useMergeClasses.ts
@@ -1,4 +1,29 @@
import { twMerge } from 'tailwind-merge'
-export const useMergeClasses = (componentClasses: string | string[]): string =>
- twMerge(componentClasses)
+import type { ClassInput } from '@/types/global'
+
+function normalizeClasses (input: ClassInput): string {
+ if (typeof input === 'string') {
+ return input.trim()
+ }
+
+ if (Array.isArray(input)) {
+ return input
+ .map(normalizeClasses)
+ .join(' ')
+ .trim()
+ }
+
+ if (typeof input === 'object' && input !== null) {
+ return Object.entries(input)
+ .filter(([_, value]) => value)
+ .map(([key]) => key)
+ .join(' ')
+ }
+
+ return ''
+}
+
+export const useMergeClasses = (componentClasses: ClassInput): string => {
+ return twMerge(normalizeClasses(componentClasses))
+}
diff --git a/src/types/global.ts b/src/types/global.ts
new file mode 100644
index 00000000..c35720fc
--- /dev/null
+++ b/src/types/global.ts
@@ -0,0 +1,5 @@
+import type { Ref } from 'vue'
+
+export type ClassInput = string | Record | Array>
+
+export type ClassRef = Ref