import '../../styles/styles.scss'
import {
defineComponent, onMounted, onUnmounted, type PropType, ref, type Ref,
} from 'vue'
/**
* Многострочное поле ввода данных
*
*
*/
export default defineComponent({
props: {
/**
* Позволяет автоматически изменять высоту компонента, если контент в нем не помещается
*/
autoresize: {
type: Boolean,
default: false,
},
/**
* Помечает поле заблокированным \
* Так же скрывает ошибки, отображаемые снизу поля
*/
isDisabled: {
type: Boolean,
default: false,
},
/**
* Помечает поле обязательным \
* Так же добавляет звездочку (`*`) рядом с названием поля
*/
isRequired: {
type: Boolean,
default: false,
},
/**
* Название поля, отображающееся сверху него
*/
label: {
type: String,
default: '',
},
/**
* Полупрозрачный текст, отображающийся, когда значение поля пустое
*/
placeholder: {
type: String,
default: '',
},
/**
* Описание поля, отображающееся под полем
*/
description: {
type: String,
default: '',
},
/**
* Отключает возможность изменения размера компонента
*/
disableResize: {
type: Boolean,
default: false,
},
/**
* Значение поля
*/
modelValue: {
type: String,
default: '',
},
/**
* Ошибки поля \
* Можно передать массив строк, для отображения нескольких ошибок, либо передать строку, для отображения одной ошибки
*/
errors: {
type: [Array, String] as PropType,
default: () => [],
},
/**
* Хук, запускающийся после ввода символа в поле \
* Принимает в себя событие `DOM` хука `onInput`
*
* ! Внимание: при его определении, необходимо вручную менять значение поля, потому что пропс `onValueChange` не используется
*/
onInput: {
type: Function as PropType<(e: Event) => void>,
},
/**
* Хук, запускающийся после деактивации фокуса в поле \
* Принимает в себя событие `DOM` хука `onFocusout`
*/
onFocusOut: {
type: Function as PropType<(e: Event) => void>,
default: () => {
// do nothing
},
},
/**
* `Callback` для изменения значения в поле \
* Принимает в себя новое значение, введенное в поле
*/
onValueChange: {
type: Function as PropType<(v: string) => void>,
},
},
setup(props) {
let isResizing = false
const isWithScroll = ref(false)
let startResizeX = 0
let startResizeY = 0
let startResizeWidth = 0
let startResizeHeight = 0
const element: Ref = ref(undefined)
const resizerElement: Ref = ref(undefined)
const checkScroll = () => {
if (!element.value) return
isWithScroll.value = element.value.scrollHeight > element.value.clientHeight
}
const doResize = () => {
if (element.value && props.autoresize) {
if (element.value.scrollHeight > element.value.clientHeight) element.value.style.height = `${element.value.scrollHeight + 10}px`
}
}
const inputHandler = (e: Event) => {
if (props.onValueChange) {
props.onValueChange((e.target as HTMLInputElement).value)
}
doResize()
}
const onInput = (e: Event) => {
if (props.onInput) props.onInput(e)
else inputHandler(e)
checkScroll()
}
const resizeStart = (e: MouseEvent) => {
e.preventDefault()
if (!element.value) return
isResizing = true
startResizeX = e.clientX
startResizeY = e.clientY
startResizeWidth = element.value.offsetWidth
startResizeHeight = element.value.offsetHeight
}
const resize = (e: MouseEvent) => {
if (!isResizing || !element.value) return
const deltaX = e.clientX - startResizeX
const deltaY = e.clientY - startResizeY
element.value.style.width = `${startResizeWidth + deltaX}px`
element.value.style.height = `${startResizeHeight + deltaY}px`
checkScroll()
}
const resizeEnd = () => {
isResizing = false
}
onMounted(() => {
doResize()
checkScroll()
window.addEventListener('resize', checkScroll)
window.addEventListener('mousemove', resize)
window.addEventListener('mouseup', resizeEnd) // На случай, если курсор мыши вышел из области `resizerElement`
})
onUnmounted(() => {
window.removeEventListener('resize', checkScroll)
window.removeEventListener('mousemove', resize)
window.removeEventListener('mouseup', resizeEnd)
})
return (): JSX.Element => (
)
},
})