* fix(reader): require a still-hold before instant-highlight on touch Instant Highlight (the highlighter quick action) engaged on every pointer-down over text, calling preventDefault, which swallowed the single tap / swipe that turns the page on Android. Tapping the side margins still worked only because they are not selectable text; the synthetic-click fallback was also dead on Android (native touchend calls handlePointerUp with no event). Gate engagement behind a 300ms still hold for touch/pen: a tap releases first and a swipe moves first, so both fall through to pagination, and only a deliberate still hold starts drag-to-highlight. Mouse input keeps engaging immediately (click vs. press-drag is already unambiguous). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(agent): update agent memories Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2.8 KiB
name, description, metadata
| name | description | metadata | ||||||
|---|---|---|---|---|---|---|---|---|
| instant-highlight-tap-paginate | Instant Highlight quick action swallowed tap/swipe-to-paginate on Android; fixed with a 300ms still-hold gate |
|
After the 2026-06-19 update, Android users reported tap-to-paginate failing in
paginated mode: tapping TEXT didn't turn the page, only tapping the empty side
MARGINS worked. Trigger = Instant Highlight quick action enabled (3rd toolbar
icon / highlighter; setting = enableAnnotationQuickActions && annotationQuickAction === 'highlight').
Root cause: useTextSelector.handlePointerDown called ev.preventDefault() +
startInstantAnnotating() on EVERY pointer-down over selectable text. The
preventDefault suppressed the native click that drives tap-to-paginate (iframe
handleClick → iframe-single-click → usePagination). Margins worked only because
handleInstantAnnotationPointerDown→isSelectableContent returns false there.
The synthetic-mousedown fallback in handlePointerUp is dead on Android because the
native-touch touchend calls handlePointerUp(doc, index) with NO ev (Annotator.tsx
handleNativeTouch), and if (isInstantAnnotating.current && ev) skips.
Fix (PR/commit on dev): gate instant-highlight engagement behind a still hold
for touch/pen — INSTANT_HOLD_MS = 300, INSTANT_HOLD_MOVE_PX = 10 in useTextSelector.ts.
armInstantHold(touch/pen) records the press, starts a 300ms timer, does NOT preventDefault. A tap releases first (handlePointerUp/handlePointerCancel→cancelInstantHold) → native click → paginate. A swipe moves first (maybeCancelInstantHoldOnMove, called in BOTHhandlePointerMoveandhandleNativeTouchMove, compares window-coordpointerPosvsinstantHoldStartWindow) → native swipe → paginate. Only a still hold fires the timer →startInstantAnnotating.- Mouse path unchanged (immediate
preventDefault+ start) — click vs. press-drag is already unambiguous; matches the existing "mouse shouldn't be time-gated" stance. - Refactor:
startInstantAnnotating(target, startPoint)/stopInstantAnnotating()no longer takeev; the downtargetis stored ininstantAnnotationTargetso the exact element getsuser-selectrestored (pointerup target may differ after the finger moves).
Two parallel instant-highlight mechanisms share the same enable flag: (1) the
useInstantAnnotation live drag-to-highlight (this fix), and (2) the
quick-action-on-selection deferred path (beginGesture/deferredQuickActionRef/
pointerDownTimeRef in Annotator.tsx) which ALREADY long-press-gates touch on
iOS/desktop but not Android. Test: useTextSelector-instantHold.test.ts. See
keyboard-selection-adjust-4728 for the adjacent isPointerDown/handleSelectionchange logic.