123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- import {
- type MaybeComputedElementRef,
- type MaybeElement,
- onKeyStroke,
- useElementBounding,
- useWindowSize,
- } from '@vueuse/core'
- import { ref, onUnmounted, type Ref } from 'vue'
- import { EnumTextDirection } from '#shared/graphql/types.ts'
- import { useLocaleStore } from '#shared/stores/locale.ts'
- export const useResizeWidthHandle = (
- resizeCallback: (positionX: number) => void,
- handleRef: MaybeComputedElementRef<MaybeElement>,
- keyStrokeCallback: (e: KeyboardEvent, adjustment: number) => void,
- options?: {
- calculateFromRight?: boolean
- },
- ) => {
- const isResizingHorizontal = ref(false)
- const locale = useLocaleStore()
- const { width } = useElementBounding(
- handleRef as MaybeComputedElementRef<MaybeElement>,
- )
- const { width: screenWidth } = useWindowSize()
- const resize = (event: MouseEvent | TouchEvent) => {
- // Position the cursor as close to the handle center as possible.
- let positionX = Math.round(width.value / 2)
- if (event instanceof MouseEvent) {
- positionX += event.pageX
- } else if (event.targetTouches[0]) {
- positionX += event.targetTouches[0].pageX
- }
- // In case of RTL locale, subtract the reported position from the current screen width.
- if (
- locale.localeData?.dir === EnumTextDirection.Rtl &&
- !options?.calculateFromRight // If the option is set, do not calculate from the right.
- )
- positionX = screenWidth.value - positionX
- // In case of LTR locale and resizer is used from right side of the window, subtract the reported position from the current screen width.
- if (
- locale.localeData?.dir === EnumTextDirection.Ltr &&
- options?.calculateFromRight
- )
- positionX = screenWidth.value - positionX
- resizeCallback(positionX)
- }
- const endResizing = () => {
- // eslint-disable-next-line no-use-before-define
- removeListeners()
- isResizingHorizontal.value = false
- }
- const removeListeners = () => {
- document.removeEventListener('touchmove', resize)
- document.removeEventListener('touchend', endResizing)
- document.removeEventListener('mousemove', resize)
- document.removeEventListener('mouseup', endResizing)
- }
- const addEventListeners = () => {
- document.addEventListener('touchend', endResizing)
- document.addEventListener('touchmove', resize)
- document.addEventListener('mouseup', endResizing)
- document.addEventListener('mousemove', resize)
- }
- const startResizing = (e: MouseEvent) => {
- // Do not react on double click event.
- if (e.detail > 1) return
- e.preventDefault()
- isResizingHorizontal.value = true
- addEventListeners()
- }
- onUnmounted(() => {
- removeListeners()
- })
- // a11y keyboard navigation horizontal resize
- onKeyStroke(
- 'ArrowLeft',
- (e: KeyboardEvent) => {
- if (options?.calculateFromRight) {
- keyStrokeCallback(e, locale.localeData?.dir === 'rtl' ? -5 : 5)
- } else {
- keyStrokeCallback(e, locale.localeData?.dir === 'rtl' ? 5 : -5)
- }
- },
- { target: handleRef as Ref<EventTarget> },
- )
- onKeyStroke(
- 'ArrowRight',
- (e: KeyboardEvent) => {
- if (options?.calculateFromRight) {
- keyStrokeCallback(e, locale.localeData?.dir === 'rtl' ? 5 : -5)
- } else {
- keyStrokeCallback(e, locale.localeData?.dir === 'rtl' ? -5 : 5)
- }
- },
- { target: handleRef as Ref<EventTarget> },
- )
- return {
- isResizingHorizontal,
- startResizing,
- }
- }
|