/** * Web gesture recognizer (MT side). * * Upstream `@lynx-js/web-core` has **no** gesture arena — `__SetGestureDetector` * is undefined there. So on web we reimplement the recognizer here and invoke * the gesture's `'main thread'` worklet callbacks (`onBegin`/`onStart`/ * `onUpdate`/`onEnd`) — exactly the ones the native arena would. The callbacks * then do their thing (visual via `setStyleProperties`, emit via * `runOnBackground`), both of which already work on web. * * Event source: **native pointer listeners attached directly on the element**. * web-core's elements are real DOM nodes (`document.createElement('x-view')`), * so `el.addEventListener('pointerdown'|'pointermove'|'pointerup'| * 'pointercancel', …)` gives real `clientX/Y` coordinates. `setPointerCapture` * keeps move/up flowing to the element even when the pointer leaves its bounds * (needed for drag) — but it is taken LAZILY, only once a drag/pinch actually * commits (`capturePointer` at Pan onStart / pair formation), never on * `pointerdown`; capturing on down would steal a descendant's terminal events * (see #764 / `onDown`). Pointer (not touch/mouse) events ⇒ mouse, * touch and pen all work with no double-fire. (The earlier Tap-only slice routed * through web-core's own event system, which has no coords for `pointer*`; this * supersedes it.) * * Supported: **Tap**, **LongPress**, **Pan**, **Fling**, **Pinch**, **Rotation**, * plus arena relations **waitFor** and **simultaneous** (what `Gesture.Race` / * `Exclusive` / `Simultaneous` compile to) — see the "Arena relations" section * below. `continueWith` has no consumers and is logged-and-ignored. Relations * gate `onStart` only; `onBegin`/`onEnd` always fire for every gesture (e.g. * `Pressable`'s `Simultaneous(Tap, LongPress)` resets its visual in * `LongPress.onEnd`). This is a same-element web approximation of the native * arena — cross-element relations are ignored, and iOS/Android quirks * (e.g. iOS's premature Tap.onEnd) are deliberately not replicated. * * Pinch/Rotation pair the first two concurrent pointers: `onStart` fires when * the second lands (scale 1 / rotation 0), `onUpdate` on either's move, and a * dedicated `onEnd` with final values when either lifts — the universal * end-of-press onEnd pass then skips them (exactly one onEnd per press; when no * pair ever formed the universal pass covers them as before). Payloads follow * the legacy `usePinch`/`useRotation` hooks: pinch `params.scale` = * currentDistance/baseDistance; rotation `params.rotation` = cumulative signed * **radians** (unwrapped across ±π, unlike the hooks) + `params.velocity` in * rad/ms; both carry `focalX/focalY` (page coords of the midpoint, mirrored * into pageX/pageY, with client coords in x/y). The native arena's * Pinch/Rotation handlers are unfinished (#418) — this payload is the contract * native should converge on. No mid-press re-pairing with a third finger. * * Fling is discrete: recognized at the primary pointer's `pointerup` from the * velocity over a trailing ~100ms sample window — `onStart` fires on a match * (with `params.velocityX/velocityY` in px/ms), then the universal `onEnd` pass * runs as for every gesture. No `onUpdate`. Velocity unit is **px/ms** (0.3 * px/ms = 300 px/s), matching how consumers compute drag velocity manually. * * Pointer tracking is **per-pointerId** (a `Map`), so a second finger no longer * clobbers the active press: the press is driven by the *primary* pointer (the * first one down); a secondary contact marks the press multi-touch (which * disqualifies Tap and cancels pending LongPress timers, mirroring the native * recognizers failing on a second touch) and otherwise just tracks alongside — * the foundation for two-finger Pinch/Rotation. A secondary lift never ends the * press; only the primary's `pointerup`/`pointercancel` does. Deferred: pointer * promotion (continuing a pan on the surviving finger when the primary lifts). * * Native is unaffected — this module is only reached when `__SetGestureDetector` * is absent (the web path in `ops-apply.ts`). */ /** Wire shape of the relation lists carried by OP.SET_GESTURE_DETECTOR. */ export interface WebRelationMap { waitFor?: number[]; simultaneous?: number[]; continueWith?: number[]; } /** * Register one gesture on an element (web path). The first gesture on an element * attaches the shared pointer listeners; gestures that need to keep the browser * from claiming the interaction set an axis-aware `touch-action` (see * `applyTouchAction`). */ export declare function registerWebGesture(el: MainThreadElement, elementWvid: number, gestureId: number, type: number, config: { callbacks: { name: string; callback: Record; }[]; config?: Record; }, relationMap?: WebRelationMap): void; /** Remove one gesture; tear down listeners when the element has none left. */ export declare function unregisterWebGesture(elementWvid: number, gestureId: number): void; /** Hot-reload / test reset hook. */ export declare function resetWebGestures(): void;