diff --git a/docs/components/select.md b/docs/components/select.md index 5a362ce6..425a0840 100644 --- a/docs/components/select.md +++ b/docs/components/select.md @@ -1,8 +1,10 @@ # Vue Select - Flowbite @@ -132,3 +134,75 @@ const countries = [ ] ``` + +## Slot - Helper + + +```vue + + + +``` + +## Slot - Validation + +- Set validation status via `validationStatus` prop, which accepts `'success'` or `'error'`. +- Add validation message via `validationMessage` slot. + + +```vue + + + +``` diff --git a/docs/components/select/examples/FwbSelectExampleHelper.vue b/docs/components/select/examples/FwbSelectExampleHelper.vue new file mode 100644 index 00000000..e0269646 --- /dev/null +++ b/docs/components/select/examples/FwbSelectExampleHelper.vue @@ -0,0 +1,31 @@ + + + diff --git a/docs/components/select/examples/FwbSelectExampleValidation.vue b/docs/components/select/examples/FwbSelectExampleValidation.vue new file mode 100644 index 00000000..fcc8dfba --- /dev/null +++ b/docs/components/select/examples/FwbSelectExampleValidation.vue @@ -0,0 +1,33 @@ + + + diff --git a/src/components/FwbSelect/FwbSelect.vue b/src/components/FwbSelect/FwbSelect.vue index a78e5f19..17ec3983 100644 --- a/src/components/FwbSelect/FwbSelect.vue +++ b/src/components/FwbSelect/FwbSelect.vue @@ -1,40 +1,55 @@ diff --git a/src/components/FwbSelect/composables/useSelectClasses.ts b/src/components/FwbSelect/composables/useSelectClasses.ts index e69de29b..c9766b8a 100644 --- a/src/components/FwbSelect/composables/useSelectClasses.ts +++ b/src/components/FwbSelect/composables/useSelectClasses.ts @@ -0,0 +1,76 @@ +import { computed, type Ref } from 'vue' +import { twMerge } from 'tailwind-merge' +import { + type InputSize, + type ValidationStatus, + validationStatusMap, +} from '../types' + +// LABEL +const baseLabelClasses = 'block mb-2 text-sm font-medium' + +// INPUT +const defaultSelectClasses = 'w-full text-gray-900 bg-gray-50 focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500' +const disabledSelectClasses = 'cursor-not-allowed bg-gray-100' +const underlineSelectClasses = 'bg-transparent dark:bg-transparent border-b-2 border-gray-200 appearance-none dark:border-gray-700 focus:outline-none focus:ring-0 focus:border-gray-200 peer' +const selectSizeClasses: Record = { + lg: 'p-4', + md: 'p-2.5 text-sm', + sm: 'p-2 text-sm', +} + +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 focus:ring-green-500 focus:border-green-500' +const errorInputClasses = 'bg-red-50 border-red-500 text-red-900 placeholder-red-700 focus:ring-red-500 focus:border-red-500 dark:text-red-500 dark:placeholder-red-500 dark:border-red-500' + +export type UseSelectClassesProps = { + size: Ref, + disabled: Ref + underline: Ref, + validationStatus: Ref +} + +export function useSelectClasses (props: UseSelectClassesProps): { + selectClasses: Ref + labelClasses: Ref +} { + const selectClasses = computed(() => { + const vs = props.validationStatus.value + + const classByStatus = vs === validationStatusMap.Success + ? successInputClasses + : vs === validationStatusMap.Error + ? errorInputClasses + : '' + + const underlineByStatus = vs === validationStatusMap.Success + ? 'focus:border-green-500' + : vs === validationStatusMap.Error + ? 'focus:border-red-500' + : '' + + return twMerge( + defaultSelectClasses, + classByStatus, + selectSizeClasses[props.size.value], + props.disabled.value && disabledSelectClasses, + props.underline.value ? underlineSelectClasses : 'border border-gray-300 rounded-lg', + props.underline.value && underlineByStatus, + ) + }) + + 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' + + return twMerge(baseLabelClasses, classByStatus) + }) + + return { + selectClasses, + labelClasses, + } +} diff --git a/src/components/FwbSelect/types.ts b/src/components/FwbSelect/types.ts index 4d655c91..f25bafca 100644 --- a/src/components/FwbSelect/types.ts +++ b/src/components/FwbSelect/types.ts @@ -1,4 +1,13 @@ +export type InputSize = 'sm' | 'md' | 'lg' + export type OptionsType = { name: string, value: string, } + +export const validationStatusMap = { + Success: 'success', + Error: 'error', +} as const + +export type ValidationStatus = typeof validationStatusMap[keyof typeof validationStatusMap]