@mindees/core 0.22.7 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"recognizers.d.ts","names":[],"sources":["../../src/gesture/recognizers.ts"],"mappings":";;AAiBA;;;;;;;;;;AAMsB;AAWtB;;UAjBiB,aAAA;EAAA,SACN,SAAA;EAAA,SACA,CAAA;EAAA,SACA,CAAA;EAgBG;EAAA,SAdH,CAAA;EAAA,SACA,WAAA;AAAA;AAcV;AAAA,iBAHe,gBAAA,CAAiB,IAAA;EAC/B,GAAA;EACA,QAAA,IAAY,EAAA,cAAgB,EAAA;AAAA;AAO6B;AAAA,iBAA3C,gBAAA,CAAiB,CAAA,YAAa,aAAa;;UAgB1C,eAAA;EACf,aAAA,CAAc,CAAA;EACd,aAAA,CAAc,CAAA;EACd,WAAA,CAAY,CAAA;EACZ,eAAA,CAAgB,CAAA;AAAA;;UAID,UAAA,KAAe,MAAA;EAAA,SACrB,QAAA,EAAU,eAAA;EAAA,SACV,KAAA,EAAO,CAAA;EANU;EAQ1B,KAAA;AAAA;;UAoDe,QAAA;EAAA,SACN,YAAA;EAAA,SACA,YAAA;EAAA,SACA,SAAA;EAAA,SACA,SAAA;EAAA,SACA,CAAA;EAAA,SACA,CAAA;AAAA;AAAA,UAGM,QAAA;EAAA,SACN,MAAA;EAAA,SACA,YAAA;EAAA,SACA,YAAA;EAAA,SACA,SAAA;EAAA,SACA,SAAA;EAAA,SACA,CAAA;EAAA,SACA,CAAA;AAAA;;iBAIK,GAAA,CAAI,MAAA;EAClB,OAAA,IAAW,CAAA,EAAG,QAAA;EACd,QAAA,IAAY,CAAA,EAAG,QAAA;EACf,KAAA,IAAS,CAAA,EAAG,QAAA;IAAa,SAAA;EAAA;EACzB,WAAA;EACA,IAAA;AAAA,IACE,UAAA,CAAW,QAAA;AAAA,UAiIE,QAAA;EAAA,SACN,MAAM;AAAA;;iBAID,GAAA,CAAI,MAAA;EAClB,KAAA;EACA,WAAA;EACA,aAAA;AAAA,IACE,UAAU,CAAC,QAAA;;iBAoDC,SAAA,CAAU,MAAA;EACxB,OAAA;EACA,WAAA;EACA,KAAA;EACA,aAAA;EACA,WAAA;AAAA,IACE,UAAU,CAAC,QAAA;AAAA,UA0DE,UAAA;EAAA,SACN,KAAA;EAAA,SACA,QAAA;EAAA,SACA,MAAA;EAAA,SACA,MAAA;AAAA;AAAA,UAEM,UAAA;EAAA,SACN,MAAA;EAAA,SACA,KAAA;EAAA,SACA,MAAA;EAAA,SACA,MAAA;AAAA;;iBAIK,KAAA,CAAM,MAAA;EACpB,OAAA,IAAW,CAAA,EAAG,UAAA;EACd,QAAA,IAAY,CAAA,EAAG,UAAA;EACf,KAAA,IAAS,CAAA,EAAG,UAAA;AAAA,IACV,UAAA,CAAW,UAAA;AAAA,KAuHH,cAAA;AAAA,UACK,UAAA;EAAA,SACN,SAAA,EAAW,cAAc;EAAA,SACzB,SAAA;EAAA,SACA,SAAA;EAAA,SACA,CAAA;EAAA,SACA,CAAA;AAAA;;iBAIK,KAAA,CAAM,MAAA;EACpB,OAAA,IAAW,CAAA,EAAG,UAAA;EACd,SAAA,WAAoB,cAAA;EACpB,WAAA;EACA,WAAA;AAAA,IACE,UAAA,CAAW,QAAA;;;;;;;AA5QQ;iBA2UP,eAAA,CAAgB,WAAA,WAAsB,UAAA,YAAsB,UAAU"}
1
+ {"version":3,"file":"recognizers.d.ts","names":[],"sources":["../../src/gesture/recognizers.ts"],"mappings":";;AAiBA;;;;;;;;;;AAMsB;AAWtB;;UAjBiB,aAAA;EAAA,SACN,SAAA;EAAA,SACA,CAAA;EAAA,SACA,CAAA;EAgBG;EAAA,SAdH,CAAA;EAAA,SACA,WAAA;AAAA;AAcV;AAAA,iBAHe,gBAAA,CAAiB,IAAA;EAC/B,GAAA;EACA,QAAA,IAAY,EAAA,cAAgB,EAAA;AAAA;AAO6B;AAAA,iBAA3C,gBAAA,CAAiB,CAAA,YAAa,aAAa;;UAgB1C,eAAA;EACf,aAAA,CAAc,CAAA;EACd,aAAA,CAAc,CAAA;EACd,WAAA,CAAY,CAAA;EACZ,eAAA,CAAgB,CAAA;AAAA;;UAID,UAAA,KAAe,MAAA;EAAA,SACrB,QAAA,EAAU,eAAA;EAAA,SACV,KAAA,EAAO,CAAA;EANU;EAQ1B,KAAA;AAAA;;UAoDe,QAAA;EAAA,SACN,YAAA;EAAA,SACA,YAAA;EAAA,SACA,SAAA;EAAA,SACA,SAAA;EAAA,SACA,CAAA;EAAA,SACA,CAAA;AAAA;AAAA,UAGM,QAAA;EAAA,SACN,MAAA;EAAA,SACA,YAAA;EAAA,SACA,YAAA;EAAA,SACA,SAAA;EAAA,SACA,SAAA;EAAA,SACA,CAAA;EAAA,SACA,CAAA;AAAA;;iBAIK,GAAA,CAAI,MAAA;EAClB,OAAA,IAAW,CAAA,EAAG,QAAA;EACd,QAAA,IAAY,CAAA,EAAG,QAAA;EACf,KAAA,IAAS,CAAA,EAAG,QAAA;IAAa,SAAA;EAAA;EACzB,WAAA;EACA,IAAA;AAAA,IACE,UAAA,CAAW,QAAA;AAAA,UAiIE,QAAA;EAAA,SACN,MAAM;AAAA;;iBAID,GAAA,CAAI,MAAA;EAClB,KAAA;EACA,WAAA;EACA,aAAA;AAAA,IACE,UAAU,CAAC,QAAA;;iBAoDC,SAAA,CAAU,MAAA;EACxB,OAAA;EACA,WAAA;EACA,KAAA;EACA,aAAA;EACA,WAAA;AAAA,IACE,UAAU,CAAC,QAAA;AAAA,UA0DE,UAAA;EAAA,SACN,KAAA;EAAA,SACA,QAAA;EAAA,SACA,MAAA;EAAA,SACA,MAAA;AAAA;AAAA,UAEM,UAAA;EAAA,SACN,MAAA;EAAA,SACA,KAAA;EAAA,SACA,MAAA;EAAA,SACA,MAAA;AAAA;;iBAIK,KAAA,CAAM,MAAA;EACpB,OAAA,IAAW,CAAA,EAAG,UAAA;EACd,QAAA,IAAY,CAAA,EAAG,UAAA;EACf,KAAA,IAAS,CAAA,EAAG,UAAA;AAAA,IACV,UAAA,CAAW,UAAA;AAAA,KAuHH,cAAA;AAAA,UACK,UAAA;EAAA,SACN,SAAA,EAAW,cAAc;EAAA,SACzB,SAAA;EAAA,SACA,SAAA;EAAA,SACA,CAAA;EAAA,SACA,CAAA;AAAA;;iBAIK,KAAA,CAAM,MAAA;EACpB,OAAA,IAAW,CAAA,EAAG,UAAA;EACd,SAAA,WAAoB,cAAA;EACpB,WAAA;EACA,WAAA;AAAA,IACE,UAAA,CAAW,QAAA;;;;;;;AA5QQ;iBAkVP,eAAA,CAAgB,WAAA,WAAsB,UAAA,YAAsB,UAAU"}
@@ -430,10 +430,14 @@ function swipe(config) {
430
430
  active$.set(false);
431
431
  };
432
432
  const dominant = (p) => {
433
- const dx = p.x - p.startX;
434
- const dy = p.y - p.startY;
435
- if (Math.abs(dx) >= Math.abs(dy)) return dx >= 0 ? "right" : "left";
436
- return dy >= 0 ? "down" : "up";
433
+ let ax = p.vx;
434
+ let ay = p.vy;
435
+ if (ax === 0 && ay === 0) {
436
+ ax = p.x - p.startX;
437
+ ay = p.y - p.startY;
438
+ }
439
+ if (Math.abs(ax) >= Math.abs(ay)) return ax >= 0 ? "right" : "left";
440
+ return ay >= 0 ? "down" : "up";
437
441
  };
438
442
  return {
439
443
  state: { active: () => active$() },
@@ -1 +1 @@
1
- {"version":3,"file":"recognizers.js","names":[],"sources":["../../src/gesture/recognizers.ts"],"sourcesContent":["/**\n * Gesture recognizers — RN Gesture Handler / Flutter GestureDetector parity, built on the reactive\n * core. Each factory returns a {@link Recognizer}: a bag of pointer-event handlers to spread onto a\n * host element, plus REACTIVE state (signals) you read in a `style` accessor or feed to the\n * animation engine. The only platform-aware code is {@link normalizePointer}; everything else is\n * pure payload → signal, so it runs on web (Pointer Events), native (the command-backend payload),\n * and tests (synthetic events), and SSRs safely (no `document` access).\n *\n * Attach two recognizers to ONE element via {@link composeGestures} — the renderer binds a single\n * listener per event name, so spreading two `onPointerMove`s would drop one; compose merges them.\n *\n * @module\n */\n\nimport { batch, signal } from '../reactive'\n\n/** A normalized pointer sample (platform differences absorbed by {@link normalizePointer}). */\nexport interface PointerSample {\n readonly pointerId: number\n readonly x: number\n readonly y: number\n /** Timestamp in ms. */\n readonly t: number\n readonly pointerType?: string\n}\n\n// --- injectable clock (deterministic longPress tests; mirrors the animation FrameSource pattern) ---\nlet nowMs = (): number => Date.now()\nlet scheduleTimer = (fn: () => void, ms: number): (() => void) => {\n const id = setTimeout(fn, ms)\n return () => clearTimeout(id)\n}\n\n/** @internal Test-only: inject a deterministic clock + timer. */\nexport function _setGestureClock(opts: {\n now?: () => number\n schedule?: (fn: () => void, ms: number) => () => void\n}): void {\n if (opts.now) nowMs = opts.now\n if (opts.schedule) scheduleTimer = opts.schedule\n}\n\n/** Normalize a host pointer event to a {@link PointerSample}. Web `PointerEvent` or a native payload. */\nexport function normalizePointer(e: unknown): PointerSample {\n const ev = (e ?? {}) as Record<string, unknown>\n const web = 'clientX' in ev // distinguishes a DOM PointerEvent from a native JSON payload\n const num = (v: unknown, d = 0): number => (typeof v === 'number' && Number.isFinite(v) ? v : d)\n return {\n pointerId: num(ev.pointerId, 1),\n x: web ? num(ev.clientX) : num(ev.x),\n y: web ? num(ev.clientY) : num(ev.y),\n t: num(web ? ev.timeStamp : ev.timestamp, nowMs()),\n ...(typeof (web ? ev.pointerType : ev.type) === 'string'\n ? { pointerType: (web ? ev.pointerType : ev.type) as string }\n : {}),\n }\n}\n\n/** Handlers to spread onto a host element. */\nexport interface GestureHandlers {\n onPointerDown(e: unknown): void\n onPointerMove(e: unknown): void\n onPointerUp(e: unknown): void\n onPointerCancel(e: unknown): void\n}\n\n/** A recognizer: handlers to attach, reactive `state`, and a `reset()` for cleanup. */\nexport interface Recognizer<S = Record<string, () => number | boolean>> {\n readonly handlers: GestureHandlers\n readonly state: S\n /** Clear pointers, timers, and reset state to rest (call from `onCleanup`). */\n reset(): void\n}\n\ninterface Tracked {\n startX: number\n startY: number\n startT: number\n x: number\n y: number\n lastX: number\n lastY: number\n lastT: number\n vx: number // EWMA velocity, px/ms\n vy: number\n}\n\nconst VEL_ALPHA = 0.6\nconst dist = (ax: number, ay: number, bx: number, by: number): number =>\n Math.hypot(ax - bx, ay - by)\n\n/** Update a tracked pointer + its EWMA velocity from a new sample. */\nfunction track(p: Tracked, s: PointerSample): void {\n const dtMs = s.t - p.lastT\n if (dtMs > 0) {\n p.vx = VEL_ALPHA * ((s.x - p.lastX) / dtMs) + (1 - VEL_ALPHA) * p.vx\n p.vy = VEL_ALPHA * ((s.y - p.lastY) / dtMs) + (1 - VEL_ALPHA) * p.vy\n }\n p.lastX = s.x\n p.lastY = s.y\n p.lastT = s.t\n p.x = s.x\n p.y = s.y\n}\n\nfunction newTracked(s: PointerSample): Tracked {\n return {\n startX: s.x,\n startY: s.y,\n startT: s.t,\n x: s.x,\n y: s.y,\n lastX: s.x,\n lastY: s.y,\n lastT: s.t,\n vx: 0,\n vy: 0,\n }\n}\n\n// --- Pan (drag) -----------------------------------------------------------------------------------\n\n/** A continuous pan/drag update (translations relative to gesture start; velocity in px/ms). */\nexport interface PanEvent {\n readonly translationX: number\n readonly translationY: number\n readonly velocityX: number\n readonly velocityY: number\n readonly x: number\n readonly y: number\n}\n\nexport interface PanState {\n readonly active: () => boolean\n readonly translationX: () => number\n readonly translationY: () => number\n readonly velocityX: () => number\n readonly velocityY: () => number\n readonly x: () => number\n readonly y: () => number\n}\n\n/** Recognize a drag. Becomes active once the pointer moves past `minDistance` (slop). */\nexport function pan(config: {\n onBegin?: (e: PanEvent) => void\n onUpdate?: (e: PanEvent) => void\n onEnd?: (e: PanEvent & { completed: boolean }) => void\n minDistance?: number\n axis?: 'both' | 'x' | 'y'\n}): Recognizer<PanState> {\n const minDistance = config.minDistance ?? 10\n const axis = config.axis ?? 'both'\n const pointers = new Map<number, Tracked>()\n let id: number | null = null // the claimed pointer\n let active = false\n const active$ = signal(false)\n const tx$ = signal(0)\n const ty$ = signal(0)\n const vx$ = signal(0)\n const vy$ = signal(0)\n const x$ = signal(0)\n const y$ = signal(0)\n\n const filt = (dx: number, dy: number): [number, number] =>\n axis === 'x' ? [dx, 0] : axis === 'y' ? [0, dy] : [dx, dy]\n\n const eventFor = (p: Tracked): PanEvent => {\n const [tx, ty] = filt(p.x - p.startX, p.y - p.startY)\n const [vx, vy] = filt(p.vx, p.vy)\n return { translationX: tx, translationY: ty, velocityX: vx, velocityY: vy, x: p.x, y: p.y }\n }\n const writeFrom = (p: Tracked): void => {\n const e = eventFor(p)\n tx$.set(e.translationX)\n ty$.set(e.translationY)\n vx$.set(e.velocityX)\n vy$.set(e.velocityY)\n x$.set(e.x)\n y$.set(e.y)\n }\n\n // Snap the rich reactive state back to rest (active + translation + velocity + position). Used by\n // reset() and on the final pointer-up/cancel — so `state.translationX()` etc. don't stay stuck at the\n // last drag offset after release (consistent with tap/longPress, which reset on up).\n const restState = (): void => {\n batch(() => {\n active$.set(false)\n tx$.set(0)\n ty$.set(0)\n vx$.set(0)\n vy$.set(0)\n x$.set(0)\n y$.set(0)\n })\n }\n\n const reset = (): void => {\n pointers.clear()\n id = null\n active = false\n restState()\n }\n\n return {\n state: {\n active: () => active$(),\n translationX: () => tx$(),\n translationY: () => ty$(),\n velocityX: () => vx$(),\n velocityY: () => vy$(),\n x: () => x$(),\n y: () => y$(),\n },\n reset,\n handlers: {\n onPointerDown(e): void {\n const s = normalizePointer(e)\n pointers.set(s.pointerId, newTracked(s))\n if (id === null) id = s.pointerId\n },\n onPointerMove(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (!p) return\n track(p, s)\n if (s.pointerId !== id) return\n // Slop on the AXIS-FILTERED delta: an `axis: 'y'` pan must not activate on horizontal travel.\n const [sx, sy] = filt(p.x - p.startX, p.y - p.startY)\n const slop = Math.hypot(sx, sy)\n batch(() => {\n if (!active && slop >= minDistance) {\n active = true\n active$.set(true)\n writeFrom(p)\n config.onBegin?.(eventFor(p))\n } else if (active) {\n writeFrom(p)\n config.onUpdate?.(eventFor(p))\n }\n })\n },\n onPointerUp(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (p) track(p, s)\n if (s.pointerId === id && active && p) {\n config.onEnd?.({ ...eventFor(p), completed: true })\n }\n pointers.delete(s.pointerId)\n if (s.pointerId === id) {\n id = pointers.keys().next().value ?? null\n active = false\n // Last pointer up → snap state to rest; otherwise hand off to the remaining pointer.\n if (id === null) restState()\n else active$.set(false)\n }\n },\n onPointerCancel(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (s.pointerId === id && active && p) {\n config.onEnd?.({ ...eventFor(p), completed: false })\n }\n pointers.delete(s.pointerId)\n if (s.pointerId === id) {\n // Hand off to another still-down pointer (mirror onPointerUp) so it can re-claim the pan.\n id = pointers.keys().next().value ?? null\n active = false\n if (id === null) restState()\n else active$.set(false)\n }\n },\n },\n }\n}\n\n// --- Tap ------------------------------------------------------------------------------------------\n\nexport interface TapState {\n readonly active: () => boolean\n}\n\n/** Recognize a tap: down + up within `maxDistance` and `maxDurationMs`, no extra pointer. */\nexport function tap(config: {\n onTap?: () => void\n maxDistance?: number\n maxDurationMs?: number\n}): Recognizer<TapState> {\n const maxDistance = config.maxDistance ?? 10\n const maxDurationMs = config.maxDurationMs ?? 500\n let down: PointerSample | null = null\n let failed = false\n const active$ = signal(false)\n const reset = (): void => {\n down = null\n failed = false\n active$.set(false)\n }\n return {\n state: { active: () => active$() },\n reset,\n handlers: {\n onPointerDown(e): void {\n if (down !== null) {\n failed = true // a second pointer fails a tap\n return\n }\n down = normalizePointer(e)\n failed = false\n active$.set(true)\n },\n onPointerMove(e): void {\n if (!down || failed) return\n const s = normalizePointer(e)\n if (s.pointerId === down.pointerId && dist(s.x, s.y, down.x, down.y) > maxDistance) {\n failed = true\n active$.set(false)\n }\n },\n onPointerUp(e): void {\n const s = normalizePointer(e)\n if (down && !failed && s.pointerId === down.pointerId) {\n const within =\n dist(s.x, s.y, down.x, down.y) <= maxDistance && s.t - down.t <= maxDurationMs\n if (within) config.onTap?.()\n }\n if (!down || s.pointerId === down.pointerId) reset() // ignore a foreign pointer's cancel/up\n },\n onPointerCancel(e): void {\n const s = normalizePointer(e)\n if (!down || s.pointerId === down.pointerId) reset() // a foreign pointer must not kill our tap\n },\n },\n }\n}\n\n// --- Long press -----------------------------------------------------------------------------------\n\n/** Recognize a long press: pointer held past `minDurationMs` without moving past `maxDistance`. */\nexport function longPress(config: {\n onBegin?: () => void\n onLongPress?: () => void\n onEnd?: () => void\n minDurationMs?: number\n maxDistance?: number\n}): Recognizer<TapState> {\n const minDurationMs = config.minDurationMs ?? 500\n const maxDistance = config.maxDistance ?? 10\n let down: PointerSample | null = null\n let cancelTimer: (() => void) | null = null\n let fired = false\n const active$ = signal(false)\n const clear = (): void => {\n cancelTimer?.()\n cancelTimer = null\n }\n const reset = (): void => {\n clear()\n down = null\n fired = false\n active$.set(false)\n }\n /** End the press, firing onEnd iff the long-press had fired, then reset. */\n const finish = (): void => {\n if (fired) config.onEnd?.()\n reset()\n }\n return {\n state: { active: () => active$() },\n reset,\n handlers: {\n onPointerDown(e): void {\n if (down !== null) return\n down = normalizePointer(e)\n fired = false\n active$.set(true)\n config.onBegin?.()\n cancelTimer = scheduleTimer(() => {\n fired = true\n config.onLongPress?.()\n }, minDurationMs)\n },\n onPointerMove(e): void {\n if (!down) return\n const s = normalizePointer(e)\n if (s.pointerId === down.pointerId && dist(s.x, s.y, down.x, down.y) > maxDistance) {\n finish() // slop exceeded → end (onEnd iff it had fired), then fail\n }\n },\n onPointerUp(e): void {\n const s = normalizePointer(e)\n if (down && s.pointerId === down.pointerId) finish()\n },\n onPointerCancel(e): void {\n const s = normalizePointer(e)\n if (!down || s.pointerId === down.pointerId) finish()\n },\n },\n }\n}\n\n// --- Pinch (scale) --------------------------------------------------------------------------------\n\nexport interface PinchEvent {\n readonly scale: number\n readonly velocity: number\n readonly focalX: number\n readonly focalY: number\n}\nexport interface PinchState {\n readonly active: () => boolean\n readonly scale: () => number\n readonly focalX: () => number\n readonly focalY: () => number\n}\n\n/** Recognize a two-finger pinch. `scale` is current distance / start distance between the pinned pair. */\nexport function pinch(config: {\n onBegin?: (e: PinchEvent) => void\n onUpdate?: (e: PinchEvent) => void\n onEnd?: (e: PinchEvent) => void\n}): Recognizer<PinchState> {\n const pts = new Map<number, PointerSample>()\n let pair: [number, number] | null = null\n let startDist = 0\n let lastScale = 1\n let lastT = 0\n const active$ = signal(false)\n const scale$ = signal(1)\n const fx$ = signal(0)\n const fy$ = signal(0)\n\n const pairPts = (): [PointerSample, PointerSample] | null => {\n if (!pair) return null\n const a = pts.get(pair[0])\n const b = pts.get(pair[1])\n return a && b ? [a, b] : null\n }\n const eventNow = (a: PointerSample, b: PointerSample, t: number): PinchEvent => {\n const d = dist(a.x, a.y, b.x, b.y)\n const scale = startDist > 0 ? d / startDist : 1\n const dt = t - lastT\n const velocity = dt > 0 ? (scale - lastScale) / dt : 0\n lastScale = scale\n lastT = t\n return { scale, velocity, focalX: (a.x + b.x) / 2, focalY: (a.y + b.y) / 2 }\n }\n const reset = (): void => {\n pts.clear()\n pair = null\n startDist = 0\n lastScale = 1\n batch(() => {\n active$.set(false)\n scale$.set(1)\n fx$.set(0)\n fy$.set(0)\n })\n }\n const begin = (): void => {\n const pp = pairPts()\n if (!pp) return\n startDist = dist(pp[0].x, pp[0].y, pp[1].x, pp[1].y)\n lastScale = 1\n lastT = Math.max(pp[0].t, pp[1].t)\n const focalX = (pp[0].x + pp[1].x) / 2\n const focalY = (pp[0].y + pp[1].y) / 2\n batch(() => {\n active$.set(true)\n scale$.set(1)\n fx$.set(focalX) // seed focal so a style reading focalX/Y is correct from the first frame\n fy$.set(focalY)\n })\n config.onBegin?.({ scale: 1, velocity: 0, focalX, focalY })\n }\n /** A pointer left: if it was a pinned finger but ≥2 remain, re-pin survivors continuously; else end. */\n const onLift = (s: PointerSample): void => {\n pts.delete(s.pointerId)\n if (!active$() || !pair) return\n const wasPinned = s.pointerId === pair[0] || s.pointerId === pair[1]\n if (!wasPinned) return // a non-pinned finger lifted — pinch continues unaffected\n if (pts.size >= 2) {\n const ids = [...pts.keys()]\n pair = [ids[0] as number, ids[1] as number]\n const pp = pairPts()\n if (pp) {\n // Re-base so dist/startDist keeps equalling the CURRENT scale (no jump on the next move).\n const d = dist(pp[0].x, pp[0].y, pp[1].x, pp[1].y)\n startDist = d / Math.max(scale$(), 1e-4)\n lastScale = scale$()\n }\n return\n }\n config.onEnd?.({ scale: scale$(), velocity: 0, focalX: fx$(), focalY: fy$() })\n reset()\n }\n return {\n state: {\n active: () => active$(),\n scale: () => scale$(),\n focalX: () => fx$(),\n focalY: () => fy$(),\n },\n reset,\n handlers: {\n onPointerDown(e): void {\n const s = normalizePointer(e)\n pts.set(s.pointerId, s)\n if (!pair && pts.size >= 2) {\n const ids = [...pts.keys()]\n pair = [ids[0] as number, ids[1] as number]\n begin()\n }\n },\n onPointerMove(e): void {\n const s = normalizePointer(e)\n if (!pts.has(s.pointerId)) return\n pts.set(s.pointerId, s)\n const pp = pairPts()\n if (!active$() || !pp) return\n const ev = eventNow(pp[0], pp[1], s.t)\n batch(() => {\n scale$.set(ev.scale)\n fx$.set(ev.focalX)\n fy$.set(ev.focalY)\n })\n config.onUpdate?.(ev)\n },\n onPointerUp(e): void {\n onLift(normalizePointer(e))\n },\n onPointerCancel(e): void {\n onLift(normalizePointer(e))\n },\n },\n }\n}\n\n// --- Swipe ----------------------------------------------------------------------------------------\n\nexport type SwipeDirection = 'left' | 'right' | 'up' | 'down'\nexport interface SwipeEvent {\n readonly direction: SwipeDirection\n readonly velocityX: number\n readonly velocityY: number\n readonly x: number\n readonly y: number\n}\n\n/** Recognize a fast flick on pointer-up (velocity ≥ `minVelocity` px/ms over `minDistance`). */\nexport function swipe(config: {\n onSwipe?: (e: SwipeEvent) => void\n direction?: 'any' | SwipeDirection\n minVelocity?: number\n minDistance?: number\n}): Recognizer<TapState> {\n const want = config.direction ?? 'any'\n const minVelocity = config.minVelocity ?? 0.3\n const minDistance = config.minDistance ?? 30\n const pointers = new Map<number, Tracked>()\n const active$ = signal(false)\n const reset = (): void => {\n pointers.clear()\n active$.set(false)\n }\n const dominant = (p: Tracked): SwipeDirection => {\n const dx = p.x - p.startX\n const dy = p.y - p.startY\n if (Math.abs(dx) >= Math.abs(dy)) return dx >= 0 ? 'right' : 'left'\n return dy >= 0 ? 'down' : 'up'\n }\n return {\n state: { active: () => active$() },\n reset,\n handlers: {\n onPointerDown(e): void {\n const s = normalizePointer(e)\n pointers.set(s.pointerId, newTracked(s))\n active$.set(true)\n },\n onPointerMove(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (p) track(p, s)\n },\n onPointerUp(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (p) {\n track(p, s)\n const speed = Math.hypot(p.vx, p.vy)\n const moved = dist(p.x, p.y, p.startX, p.startY)\n const dir = dominant(p)\n if (speed >= minVelocity && moved >= minDistance && (want === 'any' || want === dir)) {\n config.onSwipe?.({ direction: dir, velocityX: p.vx, velocityY: p.vy, x: p.x, y: p.y })\n }\n }\n pointers.delete(s.pointerId) // per-pointer: another finger can still produce its own swipe\n if (pointers.size === 0) active$.set(false)\n },\n onPointerCancel(e): void {\n const s = normalizePointer(e)\n pointers.delete(s.pointerId)\n if (pointers.size === 0) active$.set(false)\n },\n },\n }\n}\n\n// --- Composition ----------------------------------------------------------------------------------\n\n/**\n * Merge several recognizers into ONE so they can attach to a single element — required because the\n * renderer binds a single listener per event name (spreading two `onPointerMove`s would drop one).\n * `simultaneous` (the default): every recognizer sees every event independently (e.g. pan + pinch\n * together). Per-recognizer slop already disambiguates tap-vs-pan; an explicit exclusive arena is a\n * follow-up.\n */\nexport function composeGestures(recognizers: readonly Recognizer<never>[]): Recognizer<never> {\n const fan =\n (key: keyof GestureHandlers) =>\n (e: unknown): void => {\n let firstError: unknown\n batch(() => {\n // Isolate each recognizer: one throwing must not skip the rest (e.g. leaving a sibling's\n // long-press timer armed). Collect the first error and rethrow after all have run.\n for (const r of recognizers) {\n try {\n r.handlers[key](e)\n } catch (err) {\n if (firstError === undefined) firstError = err\n }\n }\n })\n if (firstError !== undefined) throw firstError\n }\n return {\n state: {} as never,\n reset: () => {\n for (const r of recognizers) r.reset()\n },\n handlers: {\n onPointerDown: fan('onPointerDown'),\n onPointerMove: fan('onPointerMove'),\n onPointerUp: fan('onPointerUp'),\n onPointerCancel: fan('onPointerCancel'),\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"recognizers.js","names":[],"sources":["../../src/gesture/recognizers.ts"],"sourcesContent":["/**\n * Gesture recognizers — RN Gesture Handler / Flutter GestureDetector parity, built on the reactive\n * core. Each factory returns a {@link Recognizer}: a bag of pointer-event handlers to spread onto a\n * host element, plus REACTIVE state (signals) you read in a `style` accessor or feed to the\n * animation engine. The only platform-aware code is {@link normalizePointer}; everything else is\n * pure payload → signal, so it runs on web (Pointer Events), native (the command-backend payload),\n * and tests (synthetic events), and SSRs safely (no `document` access).\n *\n * Attach two recognizers to ONE element via {@link composeGestures} — the renderer binds a single\n * listener per event name, so spreading two `onPointerMove`s would drop one; compose merges them.\n *\n * @module\n */\n\nimport { batch, signal } from '../reactive'\n\n/** A normalized pointer sample (platform differences absorbed by {@link normalizePointer}). */\nexport interface PointerSample {\n readonly pointerId: number\n readonly x: number\n readonly y: number\n /** Timestamp in ms. */\n readonly t: number\n readonly pointerType?: string\n}\n\n// --- injectable clock (deterministic longPress tests; mirrors the animation FrameSource pattern) ---\nlet nowMs = (): number => Date.now()\nlet scheduleTimer = (fn: () => void, ms: number): (() => void) => {\n const id = setTimeout(fn, ms)\n return () => clearTimeout(id)\n}\n\n/** @internal Test-only: inject a deterministic clock + timer. */\nexport function _setGestureClock(opts: {\n now?: () => number\n schedule?: (fn: () => void, ms: number) => () => void\n}): void {\n if (opts.now) nowMs = opts.now\n if (opts.schedule) scheduleTimer = opts.schedule\n}\n\n/** Normalize a host pointer event to a {@link PointerSample}. Web `PointerEvent` or a native payload. */\nexport function normalizePointer(e: unknown): PointerSample {\n const ev = (e ?? {}) as Record<string, unknown>\n const web = 'clientX' in ev // distinguishes a DOM PointerEvent from a native JSON payload\n const num = (v: unknown, d = 0): number => (typeof v === 'number' && Number.isFinite(v) ? v : d)\n return {\n pointerId: num(ev.pointerId, 1),\n x: web ? num(ev.clientX) : num(ev.x),\n y: web ? num(ev.clientY) : num(ev.y),\n t: num(web ? ev.timeStamp : ev.timestamp, nowMs()),\n ...(typeof (web ? ev.pointerType : ev.type) === 'string'\n ? { pointerType: (web ? ev.pointerType : ev.type) as string }\n : {}),\n }\n}\n\n/** Handlers to spread onto a host element. */\nexport interface GestureHandlers {\n onPointerDown(e: unknown): void\n onPointerMove(e: unknown): void\n onPointerUp(e: unknown): void\n onPointerCancel(e: unknown): void\n}\n\n/** A recognizer: handlers to attach, reactive `state`, and a `reset()` for cleanup. */\nexport interface Recognizer<S = Record<string, () => number | boolean>> {\n readonly handlers: GestureHandlers\n readonly state: S\n /** Clear pointers, timers, and reset state to rest (call from `onCleanup`). */\n reset(): void\n}\n\ninterface Tracked {\n startX: number\n startY: number\n startT: number\n x: number\n y: number\n lastX: number\n lastY: number\n lastT: number\n vx: number // EWMA velocity, px/ms\n vy: number\n}\n\nconst VEL_ALPHA = 0.6\nconst dist = (ax: number, ay: number, bx: number, by: number): number =>\n Math.hypot(ax - bx, ay - by)\n\n/** Update a tracked pointer + its EWMA velocity from a new sample. */\nfunction track(p: Tracked, s: PointerSample): void {\n const dtMs = s.t - p.lastT\n if (dtMs > 0) {\n p.vx = VEL_ALPHA * ((s.x - p.lastX) / dtMs) + (1 - VEL_ALPHA) * p.vx\n p.vy = VEL_ALPHA * ((s.y - p.lastY) / dtMs) + (1 - VEL_ALPHA) * p.vy\n }\n p.lastX = s.x\n p.lastY = s.y\n p.lastT = s.t\n p.x = s.x\n p.y = s.y\n}\n\nfunction newTracked(s: PointerSample): Tracked {\n return {\n startX: s.x,\n startY: s.y,\n startT: s.t,\n x: s.x,\n y: s.y,\n lastX: s.x,\n lastY: s.y,\n lastT: s.t,\n vx: 0,\n vy: 0,\n }\n}\n\n// --- Pan (drag) -----------------------------------------------------------------------------------\n\n/** A continuous pan/drag update (translations relative to gesture start; velocity in px/ms). */\nexport interface PanEvent {\n readonly translationX: number\n readonly translationY: number\n readonly velocityX: number\n readonly velocityY: number\n readonly x: number\n readonly y: number\n}\n\nexport interface PanState {\n readonly active: () => boolean\n readonly translationX: () => number\n readonly translationY: () => number\n readonly velocityX: () => number\n readonly velocityY: () => number\n readonly x: () => number\n readonly y: () => number\n}\n\n/** Recognize a drag. Becomes active once the pointer moves past `minDistance` (slop). */\nexport function pan(config: {\n onBegin?: (e: PanEvent) => void\n onUpdate?: (e: PanEvent) => void\n onEnd?: (e: PanEvent & { completed: boolean }) => void\n minDistance?: number\n axis?: 'both' | 'x' | 'y'\n}): Recognizer<PanState> {\n const minDistance = config.minDistance ?? 10\n const axis = config.axis ?? 'both'\n const pointers = new Map<number, Tracked>()\n let id: number | null = null // the claimed pointer\n let active = false\n const active$ = signal(false)\n const tx$ = signal(0)\n const ty$ = signal(0)\n const vx$ = signal(0)\n const vy$ = signal(0)\n const x$ = signal(0)\n const y$ = signal(0)\n\n const filt = (dx: number, dy: number): [number, number] =>\n axis === 'x' ? [dx, 0] : axis === 'y' ? [0, dy] : [dx, dy]\n\n const eventFor = (p: Tracked): PanEvent => {\n const [tx, ty] = filt(p.x - p.startX, p.y - p.startY)\n const [vx, vy] = filt(p.vx, p.vy)\n return { translationX: tx, translationY: ty, velocityX: vx, velocityY: vy, x: p.x, y: p.y }\n }\n const writeFrom = (p: Tracked): void => {\n const e = eventFor(p)\n tx$.set(e.translationX)\n ty$.set(e.translationY)\n vx$.set(e.velocityX)\n vy$.set(e.velocityY)\n x$.set(e.x)\n y$.set(e.y)\n }\n\n // Snap the rich reactive state back to rest (active + translation + velocity + position). Used by\n // reset() and on the final pointer-up/cancel — so `state.translationX()` etc. don't stay stuck at the\n // last drag offset after release (consistent with tap/longPress, which reset on up).\n const restState = (): void => {\n batch(() => {\n active$.set(false)\n tx$.set(0)\n ty$.set(0)\n vx$.set(0)\n vy$.set(0)\n x$.set(0)\n y$.set(0)\n })\n }\n\n const reset = (): void => {\n pointers.clear()\n id = null\n active = false\n restState()\n }\n\n return {\n state: {\n active: () => active$(),\n translationX: () => tx$(),\n translationY: () => ty$(),\n velocityX: () => vx$(),\n velocityY: () => vy$(),\n x: () => x$(),\n y: () => y$(),\n },\n reset,\n handlers: {\n onPointerDown(e): void {\n const s = normalizePointer(e)\n pointers.set(s.pointerId, newTracked(s))\n if (id === null) id = s.pointerId\n },\n onPointerMove(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (!p) return\n track(p, s)\n if (s.pointerId !== id) return\n // Slop on the AXIS-FILTERED delta: an `axis: 'y'` pan must not activate on horizontal travel.\n const [sx, sy] = filt(p.x - p.startX, p.y - p.startY)\n const slop = Math.hypot(sx, sy)\n batch(() => {\n if (!active && slop >= minDistance) {\n active = true\n active$.set(true)\n writeFrom(p)\n config.onBegin?.(eventFor(p))\n } else if (active) {\n writeFrom(p)\n config.onUpdate?.(eventFor(p))\n }\n })\n },\n onPointerUp(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (p) track(p, s)\n if (s.pointerId === id && active && p) {\n config.onEnd?.({ ...eventFor(p), completed: true })\n }\n pointers.delete(s.pointerId)\n if (s.pointerId === id) {\n id = pointers.keys().next().value ?? null\n active = false\n // Last pointer up → snap state to rest; otherwise hand off to the remaining pointer.\n if (id === null) restState()\n else active$.set(false)\n }\n },\n onPointerCancel(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (s.pointerId === id && active && p) {\n config.onEnd?.({ ...eventFor(p), completed: false })\n }\n pointers.delete(s.pointerId)\n if (s.pointerId === id) {\n // Hand off to another still-down pointer (mirror onPointerUp) so it can re-claim the pan.\n id = pointers.keys().next().value ?? null\n active = false\n if (id === null) restState()\n else active$.set(false)\n }\n },\n },\n }\n}\n\n// --- Tap ------------------------------------------------------------------------------------------\n\nexport interface TapState {\n readonly active: () => boolean\n}\n\n/** Recognize a tap: down + up within `maxDistance` and `maxDurationMs`, no extra pointer. */\nexport function tap(config: {\n onTap?: () => void\n maxDistance?: number\n maxDurationMs?: number\n}): Recognizer<TapState> {\n const maxDistance = config.maxDistance ?? 10\n const maxDurationMs = config.maxDurationMs ?? 500\n let down: PointerSample | null = null\n let failed = false\n const active$ = signal(false)\n const reset = (): void => {\n down = null\n failed = false\n active$.set(false)\n }\n return {\n state: { active: () => active$() },\n reset,\n handlers: {\n onPointerDown(e): void {\n if (down !== null) {\n failed = true // a second pointer fails a tap\n return\n }\n down = normalizePointer(e)\n failed = false\n active$.set(true)\n },\n onPointerMove(e): void {\n if (!down || failed) return\n const s = normalizePointer(e)\n if (s.pointerId === down.pointerId && dist(s.x, s.y, down.x, down.y) > maxDistance) {\n failed = true\n active$.set(false)\n }\n },\n onPointerUp(e): void {\n const s = normalizePointer(e)\n if (down && !failed && s.pointerId === down.pointerId) {\n const within =\n dist(s.x, s.y, down.x, down.y) <= maxDistance && s.t - down.t <= maxDurationMs\n if (within) config.onTap?.()\n }\n if (!down || s.pointerId === down.pointerId) reset() // ignore a foreign pointer's cancel/up\n },\n onPointerCancel(e): void {\n const s = normalizePointer(e)\n if (!down || s.pointerId === down.pointerId) reset() // a foreign pointer must not kill our tap\n },\n },\n }\n}\n\n// --- Long press -----------------------------------------------------------------------------------\n\n/** Recognize a long press: pointer held past `minDurationMs` without moving past `maxDistance`. */\nexport function longPress(config: {\n onBegin?: () => void\n onLongPress?: () => void\n onEnd?: () => void\n minDurationMs?: number\n maxDistance?: number\n}): Recognizer<TapState> {\n const minDurationMs = config.minDurationMs ?? 500\n const maxDistance = config.maxDistance ?? 10\n let down: PointerSample | null = null\n let cancelTimer: (() => void) | null = null\n let fired = false\n const active$ = signal(false)\n const clear = (): void => {\n cancelTimer?.()\n cancelTimer = null\n }\n const reset = (): void => {\n clear()\n down = null\n fired = false\n active$.set(false)\n }\n /** End the press, firing onEnd iff the long-press had fired, then reset. */\n const finish = (): void => {\n if (fired) config.onEnd?.()\n reset()\n }\n return {\n state: { active: () => active$() },\n reset,\n handlers: {\n onPointerDown(e): void {\n if (down !== null) return\n down = normalizePointer(e)\n fired = false\n active$.set(true)\n config.onBegin?.()\n cancelTimer = scheduleTimer(() => {\n fired = true\n config.onLongPress?.()\n }, minDurationMs)\n },\n onPointerMove(e): void {\n if (!down) return\n const s = normalizePointer(e)\n if (s.pointerId === down.pointerId && dist(s.x, s.y, down.x, down.y) > maxDistance) {\n finish() // slop exceeded → end (onEnd iff it had fired), then fail\n }\n },\n onPointerUp(e): void {\n const s = normalizePointer(e)\n if (down && s.pointerId === down.pointerId) finish()\n },\n onPointerCancel(e): void {\n const s = normalizePointer(e)\n if (!down || s.pointerId === down.pointerId) finish()\n },\n },\n }\n}\n\n// --- Pinch (scale) --------------------------------------------------------------------------------\n\nexport interface PinchEvent {\n readonly scale: number\n readonly velocity: number\n readonly focalX: number\n readonly focalY: number\n}\nexport interface PinchState {\n readonly active: () => boolean\n readonly scale: () => number\n readonly focalX: () => number\n readonly focalY: () => number\n}\n\n/** Recognize a two-finger pinch. `scale` is current distance / start distance between the pinned pair. */\nexport function pinch(config: {\n onBegin?: (e: PinchEvent) => void\n onUpdate?: (e: PinchEvent) => void\n onEnd?: (e: PinchEvent) => void\n}): Recognizer<PinchState> {\n const pts = new Map<number, PointerSample>()\n let pair: [number, number] | null = null\n let startDist = 0\n let lastScale = 1\n let lastT = 0\n const active$ = signal(false)\n const scale$ = signal(1)\n const fx$ = signal(0)\n const fy$ = signal(0)\n\n const pairPts = (): [PointerSample, PointerSample] | null => {\n if (!pair) return null\n const a = pts.get(pair[0])\n const b = pts.get(pair[1])\n return a && b ? [a, b] : null\n }\n const eventNow = (a: PointerSample, b: PointerSample, t: number): PinchEvent => {\n const d = dist(a.x, a.y, b.x, b.y)\n const scale = startDist > 0 ? d / startDist : 1\n const dt = t - lastT\n const velocity = dt > 0 ? (scale - lastScale) / dt : 0\n lastScale = scale\n lastT = t\n return { scale, velocity, focalX: (a.x + b.x) / 2, focalY: (a.y + b.y) / 2 }\n }\n const reset = (): void => {\n pts.clear()\n pair = null\n startDist = 0\n lastScale = 1\n batch(() => {\n active$.set(false)\n scale$.set(1)\n fx$.set(0)\n fy$.set(0)\n })\n }\n const begin = (): void => {\n const pp = pairPts()\n if (!pp) return\n startDist = dist(pp[0].x, pp[0].y, pp[1].x, pp[1].y)\n lastScale = 1\n lastT = Math.max(pp[0].t, pp[1].t)\n const focalX = (pp[0].x + pp[1].x) / 2\n const focalY = (pp[0].y + pp[1].y) / 2\n batch(() => {\n active$.set(true)\n scale$.set(1)\n fx$.set(focalX) // seed focal so a style reading focalX/Y is correct from the first frame\n fy$.set(focalY)\n })\n config.onBegin?.({ scale: 1, velocity: 0, focalX, focalY })\n }\n /** A pointer left: if it was a pinned finger but ≥2 remain, re-pin survivors continuously; else end. */\n const onLift = (s: PointerSample): void => {\n pts.delete(s.pointerId)\n if (!active$() || !pair) return\n const wasPinned = s.pointerId === pair[0] || s.pointerId === pair[1]\n if (!wasPinned) return // a non-pinned finger lifted — pinch continues unaffected\n if (pts.size >= 2) {\n const ids = [...pts.keys()]\n pair = [ids[0] as number, ids[1] as number]\n const pp = pairPts()\n if (pp) {\n // Re-base so dist/startDist keeps equalling the CURRENT scale (no jump on the next move).\n const d = dist(pp[0].x, pp[0].y, pp[1].x, pp[1].y)\n startDist = d / Math.max(scale$(), 1e-4)\n lastScale = scale$()\n }\n return\n }\n config.onEnd?.({ scale: scale$(), velocity: 0, focalX: fx$(), focalY: fy$() })\n reset()\n }\n return {\n state: {\n active: () => active$(),\n scale: () => scale$(),\n focalX: () => fx$(),\n focalY: () => fy$(),\n },\n reset,\n handlers: {\n onPointerDown(e): void {\n const s = normalizePointer(e)\n pts.set(s.pointerId, s)\n if (!pair && pts.size >= 2) {\n const ids = [...pts.keys()]\n pair = [ids[0] as number, ids[1] as number]\n begin()\n }\n },\n onPointerMove(e): void {\n const s = normalizePointer(e)\n if (!pts.has(s.pointerId)) return\n pts.set(s.pointerId, s)\n const pp = pairPts()\n if (!active$() || !pp) return\n const ev = eventNow(pp[0], pp[1], s.t)\n batch(() => {\n scale$.set(ev.scale)\n fx$.set(ev.focalX)\n fy$.set(ev.focalY)\n })\n config.onUpdate?.(ev)\n },\n onPointerUp(e): void {\n onLift(normalizePointer(e))\n },\n onPointerCancel(e): void {\n onLift(normalizePointer(e))\n },\n },\n }\n}\n\n// --- Swipe ----------------------------------------------------------------------------------------\n\nexport type SwipeDirection = 'left' | 'right' | 'up' | 'down'\nexport interface SwipeEvent {\n readonly direction: SwipeDirection\n readonly velocityX: number\n readonly velocityY: number\n readonly x: number\n readonly y: number\n}\n\n/** Recognize a fast flick on pointer-up (velocity ≥ `minVelocity` px/ms over `minDistance`). */\nexport function swipe(config: {\n onSwipe?: (e: SwipeEvent) => void\n direction?: 'any' | SwipeDirection\n minVelocity?: number\n minDistance?: number\n}): Recognizer<TapState> {\n const want = config.direction ?? 'any'\n const minVelocity = config.minVelocity ?? 0.3\n const minDistance = config.minDistance ?? 30\n const pointers = new Map<number, Tracked>()\n const active$ = signal(false)\n const reset = (): void => {\n pointers.clear()\n active$.set(false)\n }\n const dominant = (p: Tracked): SwipeDirection => {\n // Direction from RELEASE VELOCITY (the flick intent) so it always agrees with the sign of the\n // reported velocityX/velocityY — a reversing flick (drag one way, fling back) reports the way it was\n // flung, not net travel. Fall back to net displacement only when release velocity is exactly zero.\n let ax = p.vx\n let ay = p.vy\n if (ax === 0 && ay === 0) {\n ax = p.x - p.startX\n ay = p.y - p.startY\n }\n if (Math.abs(ax) >= Math.abs(ay)) return ax >= 0 ? 'right' : 'left'\n return ay >= 0 ? 'down' : 'up'\n }\n return {\n state: { active: () => active$() },\n reset,\n handlers: {\n onPointerDown(e): void {\n const s = normalizePointer(e)\n pointers.set(s.pointerId, newTracked(s))\n active$.set(true)\n },\n onPointerMove(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (p) track(p, s)\n },\n onPointerUp(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (p) {\n track(p, s)\n const speed = Math.hypot(p.vx, p.vy)\n const moved = dist(p.x, p.y, p.startX, p.startY)\n const dir = dominant(p)\n if (speed >= minVelocity && moved >= minDistance && (want === 'any' || want === dir)) {\n config.onSwipe?.({ direction: dir, velocityX: p.vx, velocityY: p.vy, x: p.x, y: p.y })\n }\n }\n pointers.delete(s.pointerId) // per-pointer: another finger can still produce its own swipe\n if (pointers.size === 0) active$.set(false)\n },\n onPointerCancel(e): void {\n const s = normalizePointer(e)\n pointers.delete(s.pointerId)\n if (pointers.size === 0) active$.set(false)\n },\n },\n }\n}\n\n// --- Composition ----------------------------------------------------------------------------------\n\n/**\n * Merge several recognizers into ONE so they can attach to a single element — required because the\n * renderer binds a single listener per event name (spreading two `onPointerMove`s would drop one).\n * `simultaneous` (the default): every recognizer sees every event independently (e.g. pan + pinch\n * together). Per-recognizer slop already disambiguates tap-vs-pan; an explicit exclusive arena is a\n * follow-up.\n */\nexport function composeGestures(recognizers: readonly Recognizer<never>[]): Recognizer<never> {\n const fan =\n (key: keyof GestureHandlers) =>\n (e: unknown): void => {\n let firstError: unknown\n batch(() => {\n // Isolate each recognizer: one throwing must not skip the rest (e.g. leaving a sibling's\n // long-press timer armed). Collect the first error and rethrow after all have run.\n for (const r of recognizers) {\n try {\n r.handlers[key](e)\n } catch (err) {\n if (firstError === undefined) firstError = err\n }\n }\n })\n if (firstError !== undefined) throw firstError\n }\n return {\n state: {} as never,\n reset: () => {\n for (const r of recognizers) r.reset()\n },\n handlers: {\n onPointerDown: fan('onPointerDown'),\n onPointerMove: fan('onPointerMove'),\n onPointerUp: fan('onPointerUp'),\n onPointerCancel: fan('onPointerCancel'),\n },\n }\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@ import { ThreadPool, WorkerLike, WorkerPoolOptions, createInlineThreadPool, crea
14
14
  /** The npm package name. */
15
15
  declare const name = "@mindees/core";
16
16
  /** The package version. All `@mindees/*` packages share one locked version line. */
17
- declare const VERSION = "0.22.7";
17
+ declare const VERSION = "0.23.0";
18
18
  /**
19
19
  * Current maturity of this package. See the repository `STATUS.md`.
20
20
  *
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import { createInlineThreadPool, createNativeThreadPool, createWorkerPool } from
12
12
  /** The npm package name. */
13
13
  const name = "@mindees/core";
14
14
  /** The package version. All `@mindees/*` packages share one locked version line. */
15
- const VERSION = "0.22.7";
15
+ const VERSION = "0.23.0";
16
16
  /**
17
17
  * Current maturity of this package. See the repository `STATUS.md`.
18
18
  *
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Maturity, PackageInfo } from './types'\n\n/**\n * Animation engine: reactive animated values + timing/spring drivers + interpolate, driven by an\n * injected frame source (RN Animated/Reanimated + Flutter AnimationController parity).\n */\nexport {\n _activeAnimationCount,\n _resetAnimation,\n type AnimatedValue,\n type AnimationHandle,\n animate,\n cubicBezier,\n type Easing,\n easeInOutQuad,\n easeInQuad,\n easeOutCubic,\n easeOutQuad,\n type FrameSource,\n getFrameSource,\n interpolate,\n linear,\n manualFrameSource,\n rafFrameSource,\n setFrameSource,\n spring,\n timing,\n} from './animation'\n/**\n * Component model: a renderer-agnostic element tree plus selector-based,\n * re-render-isolated context. (Phase 2)\n */\nexport {\n type Component,\n type Context,\n type ContextProvider,\n createContext,\n createElement,\n createProvider,\n ELEMENT_TYPE,\n type ElementType,\n Fragment,\n hasOwner,\n isElement,\n isKeyedRegion,\n isPortal,\n KEYED_REGION,\n type KeyedRegion,\n type KeyedRegionOptions,\n keyedRegion,\n type MindeesElement,\n type MindeesNode,\n PORTAL,\n type PortalRegion,\n portal,\n renderComponent,\n type SelectorEquals,\n} from './component'\nexport { NotImplementedError } from './errors'\n/**\n * Gesture recognizers: tap/longPress/pan/pinch/swipe → reactive state that drives styles and the\n * animation engine (RN Gesture Handler / Flutter GestureDetector parity).\n */\nexport {\n _setGestureClock,\n composeGestures,\n type GestureHandlers,\n longPress,\n normalizePointer,\n type PanEvent,\n type PanState,\n type PinchEvent,\n type PinchState,\n type PointerSample,\n pan,\n panAnimated,\n pinch,\n type Recognizer,\n type SwipeDirection,\n type SwipeEvent,\n swipe,\n type TapState,\n tap,\n} from './gesture'\nexport { notImplemented } from './not-implemented'\n/**\n * Fine-grained reactivity: signals, computed values, effects, batching, and\n * disposal scopes. This is the reactive core of MindeesNative.\n */\nexport {\n type Accessor,\n batch,\n type ComputedOptions,\n computed,\n createRoot,\n deferred,\n type EffectOptions,\n type EqualsFn,\n effect,\n getOwner,\n type Memo,\n memo,\n type Owner,\n on,\n onCleanup,\n runWithOwner,\n type Signal,\n type SignalOptions,\n setReactiveScheduler,\n signal,\n startTransition,\n untrack,\n} from './reactive'\n/**\n * Priority scheduler: two-lane (sync/normal), microtask-batched, with\n * cancellable and dedupable tasks. (Phase 2)\n */\nexport {\n createScheduler,\n type Priority,\n type ScheduledTask,\n type ScheduleOptions,\n Scheduler,\n type SchedulerOptions,\n type Task,\n} from './scheduler'\n/**\n * Threading abstraction: a {@link ThreadPool} contract with a working Web Worker\n * backend and an inline fallback. Native multi-threading is a research track. (Phase 2)\n */\nexport {\n createInlineThreadPool,\n createNativeThreadPool,\n createWorkerPool,\n type ThreadPool,\n type WorkerLike,\n type WorkerPoolOptions,\n} from './threading'\nexport type { Maturity, PackageInfo } from './types'\n\n/** The npm package name. */\nexport const name = '@mindees/core'\n\n/** The package version. All `@mindees/*` packages share one locked version line. */\nexport const VERSION = '0.22.7'\n\n/**\n * Current maturity of this package. See the repository `STATUS.md`.\n *\n * The reactivity layer (signals/computed/effect/batch), the component model with\n * selector-isolated context, the priority scheduler, and the thread-pool\n * abstraction (Web Worker + inline) are all implemented and tested. Native\n * multi-threading remains a research track (throws `NotImplementedError`).\n */\nexport const maturity: Maturity = 'experimental'\n\n/**\n * Static identity + maturity metadata for this package. Frozen so the\n * self-reported identity tooling introspects cannot be mutated at runtime,\n * matching the `readonly` fields of {@link PackageInfo}.\n */\nexport const info: PackageInfo = Object.freeze({ name, version: VERSION, maturity })\n"],"mappings":";;;;;;;;;;;;AA6IA,MAAa,OAAO;;AAGpB,MAAa,UAAU;;;;;;;;;AAUvB,MAAa,WAAqB;;;;;;AAOlC,MAAa,OAAoB,OAAO,OAAO;CAAE;CAAM,SAAS;CAAS;AAAS,CAAC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Maturity, PackageInfo } from './types'\n\n/**\n * Animation engine: reactive animated values + timing/spring drivers + interpolate, driven by an\n * injected frame source (RN Animated/Reanimated + Flutter AnimationController parity).\n */\nexport {\n _activeAnimationCount,\n _resetAnimation,\n type AnimatedValue,\n type AnimationHandle,\n animate,\n cubicBezier,\n type Easing,\n easeInOutQuad,\n easeInQuad,\n easeOutCubic,\n easeOutQuad,\n type FrameSource,\n getFrameSource,\n interpolate,\n linear,\n manualFrameSource,\n rafFrameSource,\n setFrameSource,\n spring,\n timing,\n} from './animation'\n/**\n * Component model: a renderer-agnostic element tree plus selector-based,\n * re-render-isolated context. (Phase 2)\n */\nexport {\n type Component,\n type Context,\n type ContextProvider,\n createContext,\n createElement,\n createProvider,\n ELEMENT_TYPE,\n type ElementType,\n Fragment,\n hasOwner,\n isElement,\n isKeyedRegion,\n isPortal,\n KEYED_REGION,\n type KeyedRegion,\n type KeyedRegionOptions,\n keyedRegion,\n type MindeesElement,\n type MindeesNode,\n PORTAL,\n type PortalRegion,\n portal,\n renderComponent,\n type SelectorEquals,\n} from './component'\nexport { NotImplementedError } from './errors'\n/**\n * Gesture recognizers: tap/longPress/pan/pinch/swipe → reactive state that drives styles and the\n * animation engine (RN Gesture Handler / Flutter GestureDetector parity).\n */\nexport {\n _setGestureClock,\n composeGestures,\n type GestureHandlers,\n longPress,\n normalizePointer,\n type PanEvent,\n type PanState,\n type PinchEvent,\n type PinchState,\n type PointerSample,\n pan,\n panAnimated,\n pinch,\n type Recognizer,\n type SwipeDirection,\n type SwipeEvent,\n swipe,\n type TapState,\n tap,\n} from './gesture'\nexport { notImplemented } from './not-implemented'\n/**\n * Fine-grained reactivity: signals, computed values, effects, batching, and\n * disposal scopes. This is the reactive core of MindeesNative.\n */\nexport {\n type Accessor,\n batch,\n type ComputedOptions,\n computed,\n createRoot,\n deferred,\n type EffectOptions,\n type EqualsFn,\n effect,\n getOwner,\n type Memo,\n memo,\n type Owner,\n on,\n onCleanup,\n runWithOwner,\n type Signal,\n type SignalOptions,\n setReactiveScheduler,\n signal,\n startTransition,\n untrack,\n} from './reactive'\n/**\n * Priority scheduler: two-lane (sync/normal), microtask-batched, with\n * cancellable and dedupable tasks. (Phase 2)\n */\nexport {\n createScheduler,\n type Priority,\n type ScheduledTask,\n type ScheduleOptions,\n Scheduler,\n type SchedulerOptions,\n type Task,\n} from './scheduler'\n/**\n * Threading abstraction: a {@link ThreadPool} contract with a working Web Worker\n * backend and an inline fallback. Native multi-threading is a research track. (Phase 2)\n */\nexport {\n createInlineThreadPool,\n createNativeThreadPool,\n createWorkerPool,\n type ThreadPool,\n type WorkerLike,\n type WorkerPoolOptions,\n} from './threading'\nexport type { Maturity, PackageInfo } from './types'\n\n/** The npm package name. */\nexport const name = '@mindees/core'\n\n/** The package version. All `@mindees/*` packages share one locked version line. */\nexport const VERSION = '0.23.0'\n\n/**\n * Current maturity of this package. See the repository `STATUS.md`.\n *\n * The reactivity layer (signals/computed/effect/batch), the component model with\n * selector-isolated context, the priority scheduler, and the thread-pool\n * abstraction (Web Worker + inline) are all implemented and tested. Native\n * multi-threading remains a research track (throws `NotImplementedError`).\n */\nexport const maturity: Maturity = 'experimental'\n\n/**\n * Static identity + maturity metadata for this package. Frozen so the\n * self-reported identity tooling introspects cannot be mutated at runtime,\n * matching the `readonly` fields of {@link PackageInfo}.\n */\nexport const info: PackageInfo = Object.freeze({ name, version: VERSION, maturity })\n"],"mappings":";;;;;;;;;;;;AA6IA,MAAa,OAAO;;AAGpB,MAAa,UAAU;;;;;;;;;AAUvB,MAAa,WAAqB;;;;;;AAOlC,MAAa,OAAoB,OAAO,OAAO;CAAE;CAAM,SAAS;CAAS;AAAS,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindees/core",
3
- "version": "0.22.7",
3
+ "version": "0.23.0",
4
4
  "description": "MindeesNative core — fine-grained reactivity (signals/computed/effect/batch), component model with selector-isolated context, priority scheduler, and a thread-pool abstraction (Web Worker + inline; native is a research track).",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "type": "module",