@indielayer/ui
Version:
Indielayer UI Components with Tailwind CSS build for Vue 3
181 lines (150 loc) • 4.69 kB
text/typescript
import type { MaybeRef, PropType } from 'vue'
import { computed, inject, onMounted, onUnmounted, ref, watch } from 'vue'
import { injectFormGroupKey, injectFormKey } from './keys'
export interface XFormInputMethods {
focus: () => void;
validate: (val: any) => boolean;
setError: (val: string) => void;
}
export const useInputtable = (props: any, { focus, emit, withListeners = true }: { focus: () => void; emit: any; withListeners?: boolean; }) => {
const isFirstValidation = ref(true)
const errorInternal = ref(props.error)
const hideFooterInternal = ref(props.hideFooter)
const name = props.name ? props.name : (Math.random() + 1).toString(36).substring(7)
const nameInternal = ref(name)
watch(() => props.error, (val) => { errorInternal.value = val })
watch(() => props.name, (val) => { if (val) nameInternal.value = val })
const formGroup = inject(injectFormGroupKey, {
registerInputGroup: () => {},
unregisterInputGroup: () => {},
setValue: () => {},
isInsideFormGroup: false,
value: undefined,
})
if (formGroup.isInsideFormGroup) {
hideFooterInternal.value = true
}
const form = inject(injectFormKey, {
registerInput: () => {},
unregisterInput: () => {},
isInsideForm: false,
})
const reset = () => {
errorInternal.value = ''
isFirstValidation.value = true
emit('update:modelValue', '')
}
const setError = (val: string) => {
errorInternal.value = val
}
const validate = (val?: any): boolean => {
val = val || props.modelValue
isFirstValidation.value = false
for (let i = 0; i < props.rules.length; i++) {
const item = props.rules[i]
let isValid = true
// Direct Function
if (typeof item === 'function') {
const rule = item
isValid = rule(val)
} else if (Array.isArray(item) && item.length === 2) {
// Rule array [function, options]
const { 0: rule, 1: options } = item
isValid = rule(val, options)
} else {
// Rule object { fn, options }
const rule = item.fn
const { options } = item
isValid = rule(val, options)
}
if (isValid !== true) {
errorInternal.value = isValid
return false
}
}
errorInternal.value = ''
return true
}
const isFocused = ref(false)
type InputListeners = {
focus: (event: Event) => void;
blur: (event: Event) => void;
input: (event: Event) => void;
change: (event: Event) => void;
}
const inputListeners: MaybeRef<InputListeners> = withListeners ? computed<InputListeners>(() => {
return {
focus: (event: Event) => { isFocused.value = true; emit('focus', event) },
blur: (event: Event) => { isFocused.value = false; emit('blur', event) },
input: (event: Event) => {
if (props.validateOnInput && !isFirstValidation.value) validate((event.target as HTMLInputElement).value)
emit('update:modelValue', (event.target as HTMLInputElement).value)
emit('input', event)
},
change: (event: Event) => emit('change', event),
}
}) : {
focus: () => {},
blur: () => {},
input: () => {},
change: () => {},
}
onMounted(() => {
if (formGroup.isInsideFormGroup) {
formGroup.registerInputGroup(nameInternal.value, focus)
} else {
if (!props.skipFormRegistry)
form.registerInput(nameInternal.value, focus, validate, setError)
}
})
onUnmounted(() => {
if (formGroup.isInsideFormGroup) {
formGroup.unregisterInputGroup(nameInternal.value)
} else {
if (!props.skipFormRegistry)
form.unregisterInput(nameInternal.value)
}
})
return {
isFirstValidation,
errorInternal,
hideFooterInternal,
isFocused,
isInsideForm: props.skipFormRegistry ? false : form.isInsideForm,
isInsideFormGroup: formGroup.isInsideFormGroup,
inputListeners,
formGroup,
reset,
validate,
setError,
}
}
useInputtable.emits = (withListeners = true): string[] => {
return withListeners ?
['update:modelValue', 'blur', 'focus', 'input', 'change'] :
['update:modelValue']
}
useInputtable.props = () => ({
modelValue: {
type: [String, Number, Boolean, Object, Array] as PropType<string | number | boolean | object | any[] | undefined>,
default: undefined,
},
id: String,
name: String,
readonly: Boolean,
required: Boolean,
validateOnInput: {
type: Boolean,
default: true,
},
label: String,
helper: String,
error: String,
hideFooter: Boolean,
rules: {
type: Array,
default: () => [],
},
tooltip: String,
skipFormRegistry: Boolean,
} as const)