diff --git a/packages/web/src/components/ui/ContextMenuRenderer.tsx b/packages/web/src/components/ui/ContextMenuRenderer.tsx index fb9e3152..db4d49fd 100644 --- a/packages/web/src/components/ui/ContextMenuRenderer.tsx +++ b/packages/web/src/components/ui/ContextMenuRenderer.tsx @@ -560,6 +560,8 @@ function useGlobalLongPress(isMobile: boolean) { timer = setTimeout(() => { timer = null; fired = true; + // Clear any native text selection that started during the hold + window.getSelection()?.removeAllRanges(); // Dispatch synthetic contextmenu on the original target. // React's event delegation picks it up and fires onContextMenu handlers. const syntheticEvent = new MouseEvent('contextmenu', { diff --git a/packages/web/src/styles/globals.css b/packages/web/src/styles/globals.css index d8245658..ef26feea 100644 --- a/packages/web/src/styles/globals.css +++ b/packages/web/src/styles/globals.css @@ -99,6 +99,15 @@ text-rendering: optimizeLegibility; } + /* Suppress native long-press callout on mobile (iOS "Copy/Lookup" popup). + Our global useLongPress handler provides context menus instead. + Text can still be copied via context menu "Copy Text" option. */ + @media (max-width: 767px) { + * { + -webkit-touch-callout: none; + } + } + /* Thin scrollbar */ ::-webkit-scrollbar { width: 8px;