Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 72 additions & 6 deletions packages/hooks/src/useLongPress/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,79 @@ describe('useLongPress', () => {
});

test(`should not work when target don't support addEventListener method`, () => {
Object.defineProperty(mockTarget, 'addEventListener', {
get() {
return false;
},
});
const customTarget = {
addEventListener: false,
removeEventListener: vi.fn(),
};

setup(() => {}, mockTarget);
setup(() => {}, customTarget as any);
expect(Object.keys(events)).toHaveLength(0);
});

test('should ignore right-click (button 2)', () => {
setup(mockCallback, mockTarget, {
onClick: mockClickCallback,
onLongPressEnd: mockLongPressEndCallback,
});
expect(mockTarget.addEventListener).toBeCalled();
// Simulate right-click
events['mousedown'](new MouseEvent('mousedown', { button: 2 }));
vi.advanceTimersByTime(350);
events['mouseup'](new MouseEvent('mouseup', { button: 2 }));
expect(mockCallback).toBeCalledTimes(0);
expect(mockLongPressEndCallback).toBeCalledTimes(0);
expect(mockClickCallback).toBeCalledTimes(0);
});

test('should ignore middle-click (button 1)', () => {
setup(mockCallback, mockTarget, {
onClick: mockClickCallback,
onLongPressEnd: mockLongPressEndCallback,
});
expect(mockTarget.addEventListener).toBeCalled();
// Simulate middle-click
events['mousedown'](new MouseEvent('mousedown', { button: 1 }));
vi.advanceTimersByTime(350);
events['mouseup'](new MouseEvent('mouseup', { button: 1 }));
expect(mockCallback).toBeCalledTimes(0);
expect(mockLongPressEndCallback).toBeCalledTimes(0);
expect(mockClickCallback).toBeCalledTimes(0);
});

test('should prevent context menu when long press is triggered', () => {
setup(mockCallback, mockTarget, {
onClick: mockClickCallback,
onLongPressEnd: mockLongPressEndCallback,
});
expect(mockTarget.addEventListener).toBeCalled();
expect(events['contextmenu']).toBeDefined();

// Trigger long press
events['mousedown'](new MouseEvent('mousedown', { button: 0 }));
vi.advanceTimersByTime(350);

// Now context menu event should be prevented
const mockEvent = { preventDefault: vi.fn() };
events['contextmenu'](mockEvent);
expect(mockEvent.preventDefault).toBeCalledTimes(1);

events['mouseup'](new MouseEvent('mouseup', { button: 0 }));
});

test('should not prevent context menu when long press is not triggered', () => {
setup(mockCallback, mockTarget, {
onClick: mockClickCallback,
onLongPressEnd: mockLongPressEndCallback,
});
expect(mockTarget.addEventListener).toBeCalled();

// Don't trigger long press - just a quick click
events['mousedown'](new MouseEvent('mousedown', { button: 0 }));
events['mouseup'](new MouseEvent('mouseup', { button: 0 }));

// Context menu event should not be prevented
const mockEvent = { preventDefault: vi.fn() };
events['contextmenu'](mockEvent);
expect(mockEvent.preventDefault).toBeCalledTimes(0);
});
});
16 changes: 16 additions & 0 deletions packages/hooks/src/useLongPress/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ function useLongPress(
return;
}

// Only handle left mouse button (button 0)
// Ignore right-click (button 2) and middle-click (button 1)
// If button is undefined (e.g., in tests), default to left button
if (event?.button !== undefined && event.button !== 0) {
return;
}

mousePressed.current = true;

if (hasMoveThreshold) {
Expand Down Expand Up @@ -166,11 +173,19 @@ function useLongPress(
}
};

const onContextMenu = (event: Event) => {
// Prevent context menu if long press was triggered
if (isTriggeredRef.current) {
event.preventDefault();
}
};

targetElement.addEventListener('mousedown', onMouseDown as EventListener);
targetElement.addEventListener('mouseup', onMouseUp as EventListener);
targetElement.addEventListener('mouseleave', onMouseLeave as EventListener);
targetElement.addEventListener('touchstart', onTouchStart as EventListener);
targetElement.addEventListener('touchend', onTouchEnd as EventListener);
targetElement.addEventListener('contextmenu', onContextMenu as EventListener);

if (hasMoveThreshold) {
targetElement.addEventListener('mousemove', onMove as EventListener);
Expand All @@ -188,6 +203,7 @@ function useLongPress(
targetElement.removeEventListener('mouseleave', onMouseLeave as EventListener);
targetElement.removeEventListener('touchstart', onTouchStart as EventListener);
targetElement.removeEventListener('touchend', onTouchEnd as EventListener);
targetElement.removeEventListener('contextmenu', onContextMenu as EventListener);

if (hasMoveThreshold) {
targetElement.removeEventListener('mousemove', onMove as EventListener);
Expand Down
Loading