UNPKG

bootstrap-vue-3

Version:

Early (but lovely) implementation of Vue 3, Bootstrap 5 and Typescript

174 lines (148 loc) 4.43 kB
import type {AriaInvalid, Size} from '../types' import { computed, type ExtractPropTypes, nextTick, onActivated, onMounted, type PropType, ref, toRef, watch, } from 'vue' import useId from './useId' import {resolveAriaInvalid} from '../utils' export const COMMON_INPUT_PROPS = { ariaInvalid: { type: [Boolean, String] as PropType<AriaInvalid>, default: undefined, }, autocomplete: {type: String, required: false}, autofocus: {type: Boolean, default: false}, disabled: {type: Boolean, default: false}, form: {type: String, required: false}, formatter: {type: Function, required: false}, id: {type: String, required: false}, lazy: {type: Boolean, default: false}, lazyFormatter: {type: Boolean, default: false}, list: {type: String, required: false}, modelValue: {type: [String, Number] as PropType<string | number>, default: ''}, name: {type: String, required: false}, number: {type: Boolean, default: false}, placeholder: {type: String, required: false}, plaintext: {type: Boolean, default: false}, readonly: {type: Boolean, default: false}, required: {type: Boolean, default: false}, size: {type: String as PropType<Size>, required: false}, state: {type: Boolean as PropType<boolean | null | undefined>, default: null}, trim: {type: Boolean, default: false}, } type InputProps = ExtractPropTypes<typeof COMMON_INPUT_PROPS> type InputEmitType = ( event: 'update:modelValue' | 'change' | 'blur' | 'input', ...args: any[] ) => void /** * @param props * @param emit * @returns */ export default (props: Readonly<InputProps>, emit: InputEmitType) => { const input = ref<HTMLInputElement>() let inputValue: string | null = null let neverFormatted = true const computedId = useId(toRef(props, 'id'), 'input') const _formatValue = (value: unknown, evt: any, force = false) => { value = String(value) if (typeof props.formatter === 'function' && (!props.lazyFormatter || force)) { neverFormatted = false return props.formatter(value, evt) } return value } const _getModelValue = (value: any) => { if (props.trim) return value.trim() if (props.number) return Number.parseFloat(value) return value } const handleAutofocus = () => { nextTick(() => { if (props.autofocus) input.value?.focus() }) } onMounted(handleAutofocus) onMounted(() => { if (input.value) { input.value.value = props.modelValue as string } }) onActivated(handleAutofocus) const computedAriaInvalid = computed(() => resolveAriaInvalid(props.ariaInvalid, props.state ?? undefined) ) const onInput = (evt: Event) => { const {value} = evt.target as HTMLInputElement const formattedValue = _formatValue(value, evt) if (formattedValue === false || evt.defaultPrevented) { evt.preventDefault() return } if (props.lazy) return const nextModel = _getModelValue(formattedValue) if (props.modelValue !== nextModel) { inputValue = value emit('update:modelValue', nextModel) } emit('input', formattedValue) } const onChange = (evt: Event) => { const {value} = evt.target as HTMLInputElement const formattedValue = _formatValue(value, evt) if (formattedValue === false || evt.defaultPrevented) { evt.preventDefault() return } if (!props.lazy) return inputValue = value emit('update:modelValue', formattedValue) const nextModel = _getModelValue(formattedValue) if (props.modelValue !== nextModel) { emit('change', formattedValue) } } const onBlur = (evt: FocusEvent) => { emit('blur', evt) if (!props.lazy && !props.lazyFormatter) return const {value} = evt.target as HTMLInputElement const formattedValue = _formatValue(value, evt, true) inputValue = value emit('update:modelValue', formattedValue) } const focus = () => { if (!props.disabled) input.value?.focus() } const blur = () => { if (!props.disabled) { input.value?.blur() } } watch( () => props.modelValue, (newValue) => { if (!input.value) return input.value.value = inputValue && neverFormatted ? inputValue : (newValue as string) inputValue = null neverFormatted = true } ) return { input, computedId, computedAriaInvalid, onInput, onChange, onBlur, focus, blur, } }