import {
computed, type ComputedRef, defineComponent, type PropType, ref, type Ref, watch, onMounted,
} from 'vue'
import { copyTooltip } from '../../helpers'
import './styles.scss'
import '../../styles/styles.scss'
import EyeHide from './assets/eye-hide'
import EyeShow from './assets/eye-show'
import BlackTooltip from '../tooltips/BlackTooltip.vue'
/**
* Поле ввода данных. Дает возможность указать значение с помощью клавиатуры. Предназначен для короткого однострочного содержимого.
*
*
*/
export default defineComponent({
props: {
/**
* Помечает поле обязательным \
* Так же добавляет звездочку (`*`) рядом с названием поля
*/
isRequired: {
type: Boolean,
default: false,
},
/**
* Помечает поле заблокированным \
* Так же скрывает ошибки, отображаемые снизу поля
*/
isDisabled: {
type: Boolean,
default: false,
},
/**
* Делает поле числовым типом
*/
isForNumber: {
type: Boolean,
default: false,
},
/**
* Делает поле подходящим для использования паролей \
* Добавляет кнопку показа/скрытия текста в поле
*/
isForPassword: {
type: Boolean,
default: false,
},
/**
* Позволяет копировать текст поля при клике по нему
*/
isWithCopy: {
type: Boolean,
default: false,
},
/**
* Позволяет отображать `tooltip` (подсказку) рядом с полем \
* Подсказка отображается только тогда, когда текст в поле выходит за его рамки
*/
isShowTooltip: {
type: Boolean,
default: false,
},
/**
* Сброс значения
*/
isResettable: {
type: Boolean,
default: false,
},
/**
* Название поля, отображающееся сверху него
*/
label: {
type: String,
default: '',
},
/**
* Позволяет установить максимальную длину символов в тексте поля
*/
maxLength: {
type: Number,
},
/**
* Полупрозрачный текст, отображающийся, когда значение поля пустое
*/
placeholder: {
type: String,
default: '',
},
/**
* Описание поля, отображающееся под полем
*/
description: {
type: String,
default: '',
},
/**
* Отображение пользовательского элемента слева
*/
leftSlot: {
type: Function as PropType<() => JSX.Element>,
default: undefined,
},
/**
* Отображение пользовательского элемента справа
*/
rightSlot: {
type: Function as PropType<() => JSX.Element>,
default: undefined,
},
/**
* Значение поля
*/
modelValue: {
type: String,
default: '',
},
/**
* Ошибки поля \
* Можно передать массив строк, для отображения нескольких ошибок, либо передать строку, для отображения одной ошибки
*/
errors: {
type: [Array, String] as PropType,
default: () => [],
},
/**
* Хук, запускающийся после ввода символа в поле \
* Принимает в себя событие `DOM` хука `onInput`
*
* ! Внимание: при его определении, необходимо вручную менять значение поля, потому что пропс `onValueChange` не используется
*/
onInput: {
type: Function as PropType<(e: Event) => void>,
},
/**
* Хук, запускающийся после активации фокуса в поле \
* Принимает в себя событие `DOM` хука `onFocusin`
*/
onFocusIn: {
type: Function as PropType<(e: Event) => void>,
default: () => {
// do nothing
},
},
/**
* Хук, запускающийся после деактивации фокуса в поле \
* Принимает в себя событие `DOM` хука `onFocusout`
*/
onFocusOut: {
type: Function as PropType<(e: Event) => void>,
default: () => {
// do nothing
},
},
/**
* `Callback` для изменения значения в поле \
* Принимает в себя новое значение, введенное в поле
*/
onValueChange: {
type: Function as PropType<(v: string) => void>,
},
/**
* `Callback` для слежения и мутации значения в инпуте
* Принимает текущее значение, введенное в поле
*/
mask: {
type: Function as PropType<(v: string) => string>,
},
},
setup(props) {
const isPassword: Ref = ref(props.isForPassword)
const isFieldValueMoreThanFieldWidth = ref(false)
const modelValue = ref(props.modelValue)
const element = ref(null) as unknown as Ref
const type: ComputedRef = computed(() => {
if (isPassword.value) return 'password'
if (props.isForNumber) return 'number'
return 'text'
})
const changeIsPassword = (value: boolean) => {
isPassword.value = value
}
const inputHandler = (e: Event) => {
const element = (e.target as HTMLInputElement)
const text = element.value
if (props.mask) element.value = text
modelValue.value = props.mask ? props.mask(text) : text
}
const copy = (text: string, event: MouseEvent) => {
if (!props.isWithCopy) return
copyTooltip(text, event.clientX + 10, event.clientY - 30)
}
const onFocusIn = (e: FocusEvent) => {
props.onFocusIn(e)
setTimeout(() => {
const $input = e.target as HTMLInputElement
$input.selectionStart = $input.value.length
$input.scrollLeft = $input?.scrollWidth
}, 100)
}
const checkInputSize = () => {
isFieldValueMoreThanFieldWidth.value = element.value?.scrollWidth > element.value?.clientWidth
}
const onFocusOut = (e: FocusEvent) => {
props.onFocusOut(e)
checkInputSize()
}
watch(() => props.modelValue, (value) => {
modelValue.value = value
})
watch(modelValue, (value) => {
if (props.mask) modelValue.value = props.mask(value)
if (props.onValueChange) props.onValueChange(modelValue.value)
})
onMounted(checkInputSize)
return (): JSX.Element => {
const inputElement = () => (
)
return (