import { onBeforeUnmount, onMounted, watch, type ComputedRef, type Ref, } from 'vue' /** * Трекер движения для всплывающих окон/тултипов. * @param element Элемент, за которым будет закреплено позиционирование тултипа. * @param tooltip Тултип. ВНИМАНИЕ! У данного элемента будут перезаписаны стили позиционирования! * @param isActive Ref/ComputedRef, отвечающий за активность трекинга. * @param isTop Прикрепляет тултип к верхней границе элемента. (По умолчанию false) * @param isRight Прикрепляет тултип к правой границе элемента. (По умолчанию false. Используйте, если тултип имеет кастомную ширину) * @param isUsingElementWidth Устанавливает для тултипа ширину элемента. (По умолчанию true) */ export default function useMotionTracker(element: Ref, tooltip: Ref, isActive: Ref|ComputedRef, isTop = false, isRight = false, isUsingElementWidth = true): void { const updatePosition = () => { if (!isActive.value || !element.value?.getBoundingClientRect || !tooltip.value?.setAttribute) return const rect = element.value.getBoundingClientRect() const y = isTop ? `bottom: calc(100vh - ${rect.top}) !important;` : `top: ${rect.top + rect.height}px !important;` const x = isRight ? `right: calc(100vw - ${rect.right}px) !important;` : `left: ${rect.left}px !important;` tooltip.value.setAttribute('style', `position: fixed !important; z-index: 31; ${y} ${x}${isUsingElementWidth ? ` width: ${rect.width}px !important;` : ''}`) } let updatePositionWithDelayTimeout: number|undefined const updatePositionWithDelay = () => { clearTimeout(updatePositionWithDelayTimeout) updatePositionWithDelayTimeout = setTimeout(() => { updatePosition() }, 200) as unknown as number } const setTracker = () => { window.addEventListener('wheel', updatePositionWithDelay) window.addEventListener('touchend', updatePositionWithDelay) window.addEventListener('pointerup', updatePositionWithDelay) window.addEventListener('resize', updatePositionWithDelay) } const removeTracker = () => { clearTimeout(updatePositionWithDelayTimeout) window.removeEventListener('wheel', updatePositionWithDelay) window.removeEventListener('touchend', updatePositionWithDelay) window.removeEventListener('pointerup', updatePositionWithDelay) window.removeEventListener('resize', updatePositionWithDelay) } const checkIsOpen = () => { if (isActive.value) { updatePosition() setTracker() } else removeTracker() } watch(isActive, checkIsOpen) onMounted(checkIsOpen) onBeforeUnmount(removeTracker) }