From 5f34700553fa257f313cf6a9ccae33433d15ca8d Mon Sep 17 00:00:00 2001
From: Linus Rath <139418639+rathlinus@users.noreply.github.com>
Date: Wed, 28 Oct 2026 09:48:43 +0100
Subject: [PATCH] fix: stop the React warning about isPressed on every Contacts
visit
---
.../__tests__/contact-list-item.test.tsx | 22 ++++++++++++++++++-
.../__tests__/contacts-sidebar.test.tsx | 14 ++++++++++++
components/contacts/contact-list-item.tsx | 2 +-
components/contacts/contacts-sidebar.tsx | 2 +-
hooks/use-long-press.ts | 11 ++++++++--
5 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/components/contacts/__tests__/contact-list-item.test.tsx b/components/contacts/__tests__/contact-list-item.test.tsx
index d45560265..5f658ac52 100644
--- a/components/contacts/__tests__/contact-list-item.test.tsx
+++ b/components/contacts/__tests__/contact-list-item.test.tsx
@@ -1,4 +1,4 @@
-import { render, screen, fireEvent } from '@testing-library/react';
+import { render, screen, fireEvent, act } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';
import { ContactListItem } from '../contact-list-item';
import type { ContactCard } from '@/lib/jmap/types';
@@ -82,4 +82,24 @@ describe('ContactListItem', () => {
const { container } = render();
expect(container.querySelector('[data-testid="avatar"]') || container.querySelector('.rounded-full')).toBeNull();
});
+
+ it('opens the row menu on long-press without leaking the press state onto the row', () => {
+ const errors = vi.spyOn(console, 'error').mockImplementation(() => {});
+ vi.useFakeTimers();
+ try {
+ const onLongPress = vi.fn();
+ const { container } = render();
+ const row = container.firstElementChild!;
+ const touchStart = new Event('touchstart', { bubbles: true });
+ Object.defineProperty(touchStart, 'touches', { value: [{ clientX: 5, clientY: 5 }] });
+ act(() => { row.dispatchEvent(touchStart); });
+ act(() => { vi.advanceTimersByTime(600); });
+ expect(onLongPress).toHaveBeenCalledWith(row);
+ const unknownProp = errors.mock.calls.some((args) => args.some((a) => String(a).includes('isPressed')));
+ expect(unknownProp).toBe(false);
+ } finally {
+ vi.useRealTimers();
+ errors.mockRestore();
+ }
+ });
});
diff --git a/components/contacts/__tests__/contacts-sidebar.test.tsx b/components/contacts/__tests__/contacts-sidebar.test.tsx
index 30b3f73a2..c9939eb04 100644
--- a/components/contacts/__tests__/contacts-sidebar.test.tsx
+++ b/components/contacts/__tests__/contacts-sidebar.test.tsx
@@ -38,6 +38,20 @@ function renderSidebar(onComposeGroup = vi.fn()) {
return onComposeGroup;
}
+// First in the file: React warns about an unknown DOM prop only once per run.
+describe('ContactsSidebar — row props', () => {
+ it('keeps the long-press state off the row element', () => {
+ const errors = vi.spyOn(console, 'error').mockImplementation(() => {});
+ try {
+ renderSidebar();
+ const unknownProp = errors.mock.calls.some((args) => args.some((a) => String(a).includes('isPressed')));
+ expect(unknownProp).toBe(false);
+ } finally {
+ errors.mockRestore();
+ }
+ });
+});
+
describe('ContactsSidebar — compose to group', () => {
beforeEach(() => vi.clearAllMocks());
diff --git a/components/contacts/contact-list-item.tsx b/components/contacts/contact-list-item.tsx
index 28e90ad8e..08a95ab67 100644
--- a/components/contacts/contact-list-item.tsx
+++ b/components/contacts/contact-list-item.tsx
@@ -67,7 +67,7 @@ export function ContactListItem({ contact, isSelected, isChecked, hasSelection,
return (
({ onTouchStart, onTouchEnd, onTouchMove, onTouchCancel }),
+ [onTouchStart, onTouchEnd, onTouchMove, onTouchCancel]
+ );
+
+ return { onTouchStart, onTouchEnd, onTouchMove, onTouchCancel, isPressed, handlers };
}