chore: added changeset

This commit is contained in:
Sergey Kurdin 2025-06-15 11:58:01 -04:00
parent e55f757e99
commit c099e419ba
6 changed files with 173 additions and 36 deletions

View File

@ -0,0 +1,5 @@
---
'pastebar-app-ui': patch
---
Added long press on clip to activate clips organize

View File

@ -1,27 +0,0 @@
export function useLongPress() {
return function (callback) {
let timeout
function start(e) {
if (e.type === 'mousedown' && e.button !== 0) {
return
}
timeout = setTimeout(() => {
callback()
}, 1500)
}
function clear() {
timeout && clearTimeout(timeout)
}
return {
onMouseDown: start,
onTouchStart: start,
onMouseUp: clear,
onMouseLeave: clear,
onTouchMove: clear,
onTouchEnd: clear,
}
}
}

View File

@ -0,0 +1,150 @@
import { useCallback, useRef } from 'react'
interface LongPressOptions {
delay?: number
threshold?: number
cancelOnMove?: boolean
preventDefault?: boolean
}
interface LongPressHandlers {
onMouseDown: (e: React.MouseEvent) => void
onMouseUp: (e: React.MouseEvent) => void
onMouseLeave: (e: React.MouseEvent) => void
onMouseMove?: (e: React.MouseEvent) => void
onTouchStart: (e: React.TouchEvent) => void
onTouchEnd: (e: React.TouchEvent) => void
onTouchMove: (e: React.TouchEvent) => void
onTouchCancel: (e: React.TouchEvent) => void
onContextMenu?: (e: React.MouseEvent) => void
}
export function useLongPress(
callback: () => void,
options: LongPressOptions = {}
): LongPressHandlers {
const {
delay = 600,
threshold = 10,
cancelOnMove = true,
preventDefault = true
} = options
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const startPositionRef = useRef<{ x: number; y: number } | null>(null)
const isLongPressTriggeredRef = useRef(false)
const isTouchRef = useRef(false)
const clear = useCallback(() => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current)
timeoutRef.current = null
}
startPositionRef.current = null
isLongPressTriggeredRef.current = false
isTouchRef.current = false
}, [])
const start = useCallback(
(e: React.MouseEvent | React.TouchEvent) => {
// Prevent multiple simultaneous long press handlers
if (timeoutRef.current) {
clear()
}
// Only handle left mouse button for mouse events
if ('button' in e && e.button !== 0) {
return
}
// Determine if this is a touch event
isTouchRef.current = 'touches' in e
// Get the starting position
const touch = 'touches' in e ? e.touches[0] : e
startPositionRef.current = {
x: touch.clientX,
y: touch.clientY
}
if (preventDefault) {
e.preventDefault()
}
// Set up the long press timer
timeoutRef.current = setTimeout(() => {
isLongPressTriggeredRef.current = true
callback()
clear()
}, delay)
},
[callback, clear, delay, preventDefault]
)
const move = useCallback(
(e: React.MouseEvent | React.TouchEvent) => {
if (!cancelOnMove || !startPositionRef.current || !timeoutRef.current) {
return
}
// Get current position
const touch = 'touches' in e ? e.touches[0] : e
const currentX = touch.clientX
const currentY = touch.clientY
// Calculate distance moved
const deltaX = Math.abs(currentX - startPositionRef.current.x)
const deltaY = Math.abs(currentY - startPositionRef.current.y)
// Cancel if moved beyond threshold
if (deltaX > threshold || deltaY > threshold) {
clear()
}
},
[cancelOnMove, clear, threshold]
)
const end = useCallback(
(e: React.MouseEvent | React.TouchEvent) => {
// Prevent default only if long press was triggered
if (isLongPressTriggeredRef.current && preventDefault) {
e.preventDefault()
}
clear()
},
[clear, preventDefault]
)
const cancel = useCallback(() => {
clear()
}, [clear])
// Prevent context menu on long press
const handleContextMenu = useCallback(
(e: React.MouseEvent) => {
if (isLongPressTriggeredRef.current || timeoutRef.current) {
e.preventDefault()
}
},
[]
)
return {
onMouseDown: start as (e: React.MouseEvent) => void,
onMouseUp: end as (e: React.MouseEvent) => void,
onMouseLeave: cancel,
onMouseMove: cancelOnMove ? (move as (e: React.MouseEvent) => void) : undefined,
onTouchStart: start as (e: React.TouchEvent) => void,
onTouchEnd: end as (e: React.TouchEvent) => void,
onTouchMove: move as (e: React.TouchEvent) => void,
onTouchCancel: cancel,
onContextMenu: preventDefault ? handleContextMenu : undefined
}
}
// Higher-order function version for backward compatibility
export function useLongPressHOF() {
return function (callback: () => void, options?: LongPressOptions) {
return useLongPress(callback, options)
}
}

View File

@ -209,7 +209,7 @@ export const ClipboardHistoryIconMenu = ({
<Button
variant="light"
id="history-menu-button_tour"
className="w-10 text-gray-400 hover:text-gray-500 hover:dark:text-gray-400 dark:text-gray-500 bg-transparent p-1 relative hover:bg-gray-100/70 dark:bg-gray-900 dark:hover:bg-gray-700/70"
className="w-10 text-gray-400 hover:text-gray-500 hover:dark:text-gray-400 dark:text-gray-500 bg-transparent p-1 relative hover:bg-gray-100/70 dark:hover:bg-gray-700/70"
>
<HistoryIcon
className="w-5 max-w-[22px] min-w-[16px] stroke-[1.3px]"

View File

@ -24,6 +24,7 @@ import {
isKeyAltPressed,
settingsStoreAtom,
showClipFindKeyPressed,
showClipsMoveOnBoardId,
showLargeViewClipId,
showLinkedClipId,
} from '~/store'
@ -363,7 +364,20 @@ export function ClipCard({
const isSearch = useSignal(false)
const searchTerm = useSignal('')
const { updateItemById } = useUpdateItemById()
// const onLongPress = useLongPress()
const longPressHandlers = useLongPress(
() => {
if (isClipEdit || isShowDetails || isPinnedBoard) {
return
}
showClipsMoveOnBoardId.value = clip.parentId
},
{
delay: 1000,
threshold: 10,
cancelOnMove: true,
preventDefault: true,
}
)
const [copiedItem, setCopiedItem, _, copyInProgressItemId] = useCopyClipItem({})
const [pastedItem, pastingCountDown, setPastedItem] = usePasteClipItem({})
@ -665,12 +679,7 @@ export function ClipCard({
>
<CardHeaderWithRef
title={titleText}
// {...onLongPress(() => {
// if (isClipEdit || isShowDetails || isPinnedBoard) {
// return
// }
// showClipsMoveOnBoardId.value = clip.parentId
// })}
{...longPressHandlers}
onClickCapture={e => {
if (e.shiftKey) {
e.preventDefault()

View File

@ -110,7 +110,7 @@ export const MenuIconMenu = ({
<Button
variant="light"
id="menu-icon-menu-button_tour"
className="w-10 text-gray-400 hover:text-gray-500 hover:dark:text-gray-400 dark:text-gray-500 bg-transparent p-1 relative hover:bg-gray-100/70 dark:bg-gray-900 dark:hover:bg-gray-700/70"
className="w-10 text-gray-400 hover:text-gray-500 hover:dark:text-gray-400 dark:text-gray-500 bg-transparent p-1 relative hover:bg-gray-100/70 dark:hover:bg-gray-700/70"
>
<MenuSquare className="stroke-[1.3px]" size={22} />
{selectedItemIds.length > 1 && (