From 0ae25ecab71b63072973ccfa9445c864d8063063 Mon Sep 17 00:00:00 2001 From: iris Date: Mon, 3 Aug 2026 16:35:26 +0200 Subject: [PATCH] client: fall back to touch events for long-press (Pointer Events not on old WebKit) Fixes half of #70 - the long-tap/count-picker interaction. Pointer Events (onPointerDown/Up/Cancel) only shipped in Safari 13/iOS 13. The same class of old-enough-WebKit kiosk device #66/#68 are already about doesn't fire them at all, so the long-press timer never starts there even though plain clicks (universally supported) keep working - which matches the report exactly: add-one-by-tapping works on the tablet, the long-press count picker doesn't, and both work fine on a laptop's modern browser. Added onTouchStart/onTouchEnd/onTouchCancel alongside the existing pointer handlers, wired to the same start/cancel functions - safe on browsers that fire both pointer and touch events for one touch, since starting/cancelling the timer is already idempotent. Not touching the second half of the report (negative amounts for cart-only drinks) - genuinely ambiguous relayed text with several plausible readings that imply different UI, asked mara for clarification on the issue instead of guessing. pnpm --filter client typecheck and build both clean. --- client/src/tablet/Sale.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/client/src/tablet/Sale.tsx b/client/src/tablet/Sale.tsx index bcda05f..7bd0fab 100644 --- a/client/src/tablet/Sale.tsx +++ b/client/src/tablet/Sale.tsx @@ -86,6 +86,16 @@ export function Sale({ config, onChangeBar }: Props) { cartUuidRef.current = null; } + // Pointer Events (onPointerDown/Up/Cancel below) only shipped in Safari + // 13/iOS 13 — the exact kind of old-enough-WebKit kiosk device #66/#68 + // are already about never fires them at all, so the long-press timer + // this drives never starts on that class of device even though plain + // clicks (universally supported) keep working, which is why "add one" + // works on the tablet but the long-press count picker doesn't. The + // touch handlers alongside the pointer ones are the broad-support + // fallback; both driving the same start/cancel functions is safe + // because a device that fires both (most modern browsers do, for a + // single touch) just restarts/re-cancels the same idempotent timer. function startLongPress(d: Drink) { longPressFired.current = false; cancelLongPress(); @@ -160,6 +170,9 @@ export function Sale({ config, onChangeBar }: Props) { onPointerUp={cancelLongPress} onPointerLeave={cancelLongPress} onPointerCancel={cancelLongPress} + onTouchStart={() => startLongPress(d)} + onTouchEnd={cancelLongPress} + onTouchCancel={cancelLongPress} onContextMenu={e => e.preventDefault()} onClick={() => handleDrinkClick(d)} >