fix: get rid of the context menu for touch screen or stylus device when selecting text, closes #2579 (#2614)

This commit is contained in:
Huang Xin
2025-12-04 13:04:06 +08:00
committed by GitHub
parent 9606e315d4
commit a1487fd60c
2 changed files with 23 additions and 7 deletions
@@ -163,10 +163,12 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
handleScroll,
handleTouchStart,
handleTouchEnd,
handlePointerdown,
handlePointerup,
handleSelectionchange,
handleShowPopup,
handleUpToPopup,
handleContextmenu,
} = useTextSelector(bookKey, setSelection, handleDismissPopup);
const onLoad = (event: Event) => {
@@ -189,6 +191,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
detail.doc?.addEventListener('touchstart', handleTouchStart);
detail.doc?.addEventListener('touchmove', handleTouchmove);
detail.doc?.addEventListener('touchend', handleTouchEnd);
detail.doc?.addEventListener('pointerdown', handlePointerdown);
detail.doc?.addEventListener('pointerup', (ev: PointerEvent) =>
handlePointerup(doc, index, ev),
);
@@ -222,13 +225,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
}
// Disable the default context menu on mobile devices (selection handles suffice)
if (appService?.isMobile) {
detail.doc?.addEventListener('contextmenu', (event: Event) => {
event.preventDefault();
event.stopPropagation();
return false;
});
}
detail.doc?.addEventListener('contextmenu', handleContextmenu);
};
const onDrawAnnotation = (event: Event) => {
@@ -26,6 +26,7 @@ export const useTextSelector = (
const isTextSelected = useRef(false);
const isTouchStarted = useRef(false);
const selectionPosition = useRef<number | null>(null);
const lastPointerType = useRef<string>('mouse');
const [textSelected, setTextSelected] = useState(false);
const isValidSelection = (sel: Selection) => {
@@ -111,6 +112,9 @@ export const useTextSelector = (
}
return false;
};
const handlePointerdown = (e: PointerEvent) => {
lastPointerType.current = e.pointerType;
};
const handlePointerup = (doc: Document, index: number, ev: PointerEvent) => {
// Available on iOS and Desktop, fired at touchend or mouseup
// Note that on Android, pointerup event is fired after an additional touch event
@@ -162,6 +166,19 @@ export const useTextSelector = (
isUpToPopup.current = true;
};
const handleContextmenu = (event: Event) => {
if (appService?.isMobile) {
event.preventDefault();
event.stopPropagation();
return false;
} else if (lastPointerType.current === 'touch' || lastPointerType.current === 'pen') {
event.preventDefault();
event.stopPropagation();
return false;
}
return;
};
useEffect(() => {
if (isTextSelected.current && !selectionPosition.current) {
selectionPosition.current = view?.renderer?.start || null;
@@ -202,9 +219,11 @@ export const useTextSelector = (
handleScroll,
handleTouchStart,
handleTouchEnd,
handlePointerdown,
handlePointerup,
handleSelectionchange,
handleShowPopup,
handleUpToPopup,
handleContextmenu,
};
};