mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
- Updated useLongPress.ts to pass click coordinates to onLongPress callback - Modified SessionList.tsx to use menuAnchorPoint state instead of menuAnchorRef - Updated SessionActionMenu.tsx to position menu based on anchorPoint coordinates - Enhanced SessionHeader.tsx to calculate anchorPoint from button position and added stopPropagation to fix toggle issue The menu now appears at the exact touch/click position instead of being centered or aligned to the button edge.
120 lines
3.6 KiB
TypeScript
120 lines
3.6 KiB
TypeScript
import type React from 'react'
|
|
import { useCallback, useRef } from 'react'
|
|
|
|
type UseLongPressOptions = {
|
|
onLongPress: (point: { x: number; y: number }) => void
|
|
onClick?: () => void
|
|
threshold?: number
|
|
disabled?: boolean
|
|
}
|
|
|
|
type UseLongPressHandlers = {
|
|
onMouseDown: React.MouseEventHandler
|
|
onMouseUp: React.MouseEventHandler
|
|
onMouseLeave: React.MouseEventHandler
|
|
onTouchStart: React.TouchEventHandler
|
|
onTouchEnd: React.TouchEventHandler
|
|
onTouchMove: React.TouchEventHandler
|
|
onContextMenu: React.MouseEventHandler
|
|
onKeyDown: React.KeyboardEventHandler
|
|
}
|
|
|
|
export function useLongPress(options: UseLongPressOptions): UseLongPressHandlers {
|
|
const { onLongPress, onClick, threshold = 500, disabled = false } = options
|
|
|
|
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
const isLongPressRef = useRef(false)
|
|
const touchMoved = useRef(false)
|
|
const pressPointRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 })
|
|
|
|
const clearTimer = useCallback(() => {
|
|
if (timerRef.current) {
|
|
clearTimeout(timerRef.current)
|
|
timerRef.current = null
|
|
}
|
|
}, [])
|
|
|
|
const startTimer = useCallback((clientX: number, clientY: number) => {
|
|
if (disabled) return
|
|
|
|
clearTimer()
|
|
isLongPressRef.current = false
|
|
touchMoved.current = false
|
|
pressPointRef.current = { x: clientX, y: clientY }
|
|
|
|
timerRef.current = setTimeout(() => {
|
|
isLongPressRef.current = true
|
|
onLongPress(pressPointRef.current)
|
|
}, threshold)
|
|
}, [disabled, clearTimer, onLongPress, threshold])
|
|
|
|
const handleEnd = useCallback((shouldTriggerClick: boolean) => {
|
|
clearTimer()
|
|
|
|
if (shouldTriggerClick && !isLongPressRef.current && !touchMoved.current && onClick) {
|
|
onClick()
|
|
}
|
|
|
|
isLongPressRef.current = false
|
|
touchMoved.current = false
|
|
}, [clearTimer, onClick])
|
|
|
|
const onMouseDown = useCallback<React.MouseEventHandler>((e) => {
|
|
if (e.button !== 0) return
|
|
startTimer(e.clientX, e.clientY)
|
|
}, [startTimer])
|
|
|
|
const onMouseUp = useCallback<React.MouseEventHandler>(() => {
|
|
handleEnd(!isLongPressRef.current)
|
|
}, [handleEnd])
|
|
|
|
const onMouseLeave = useCallback<React.MouseEventHandler>(() => {
|
|
handleEnd(false)
|
|
}, [handleEnd])
|
|
|
|
const onTouchStart = useCallback<React.TouchEventHandler>((e) => {
|
|
const touch = e.touches[0]
|
|
startTimer(touch.clientX, touch.clientY)
|
|
}, [startTimer])
|
|
|
|
const onTouchEnd = useCallback<React.TouchEventHandler>((e) => {
|
|
if (isLongPressRef.current) {
|
|
e.preventDefault()
|
|
}
|
|
handleEnd(!isLongPressRef.current)
|
|
}, [handleEnd])
|
|
|
|
const onTouchMove = useCallback<React.TouchEventHandler>(() => {
|
|
touchMoved.current = true
|
|
clearTimer()
|
|
}, [clearTimer])
|
|
|
|
const onContextMenu = useCallback<React.MouseEventHandler>((e) => {
|
|
if (!disabled) {
|
|
e.preventDefault()
|
|
clearTimer()
|
|
isLongPressRef.current = true
|
|
onLongPress({ x: e.clientX, y: e.clientY })
|
|
}
|
|
}, [disabled, clearTimer, onLongPress])
|
|
|
|
const onKeyDown = useCallback<React.KeyboardEventHandler>((e) => {
|
|
if (disabled) return
|
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
e.preventDefault()
|
|
onClick?.()
|
|
}
|
|
}, [disabled, onClick])
|
|
|
|
return {
|
|
onMouseDown,
|
|
onMouseUp,
|
|
onMouseLeave,
|
|
onTouchStart,
|
|
onTouchEnd,
|
|
onTouchMove,
|
|
onContextMenu,
|
|
onKeyDown
|
|
}
|
|
}
|