Skip to content

feat: add gesture-runtime#1984

Merged
colinaaa merged 9 commits intolynx-family:mainfrom
f0rdream:gesture-runtime
Dec 17, 2025
Merged

feat: add gesture-runtime#1984
colinaaa merged 9 commits intolynx-family:mainfrom
f0rdream:gesture-runtime

Conversation

@f0rdream
Copy link
Copy Markdown
Collaborator

@f0rdream f0rdream commented Dec 5, 2025

@lynx-js/gesture-runtime provides typed gesture primitives and simple composition utilities for Lynx. It helps with gestures, from simple PanGesture, TapGesture to complex Gesture Compositions

Summary by CodeRabbit

  • New Features

    • New gesture-runtime package: Pan, Tap, LongPress, Fling, Default Scroll gestures; composition helpers (Simultaneous, Exclusive, Race); unified Gesture API and useGesture hook; public TypeScript typings and shared defaults.
  • Documentation

    • Added package README with overview, installation and usage examples.
  • Tests

    • Extensive test suites covering configs, callbacks, cloning, composition, relations, serialization, runtime behavior and type-safety.
  • Chores

    • Project build/test configs and linter ignores for runtime tests.

✏️ Tip: You can customize this high-level summary in your review settings.

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).
  • Changeset added, and when a BREAKING CHANGE occurs, it needs to be clearly marked (or not required).

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Dec 5, 2025

🦋 Changeset detected

Latest commit: ec1ef5a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@lynx-js/gesture-runtime Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 5, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Adds a new @lynx-js/gesture-runtime package: runtime gesture classes, composition system, TypeScript interfaces and globals, React hook, utilities, packaging/build/test configs, README, and a comprehensive test suite; plus lint ignore and monorepo tsconfig updates.

Changes

Cohort / File(s) Summary
Package & Build Config
packages/lynx/gesture-runtime/package.json, packages/lynx/gesture-runtime/rslib.config.ts, packages/lynx/gesture-runtime/vitest.config.ts, packages/lynx/gesture-runtime/tsconfig.build.json, packages/lynx/gesture-runtime/tsconfig.json, packages/lynx/gesture-runtime/tsconfig.test.json, packages/lynx/gesture-runtime/turbo.jsonc, packages/lynx/tsconfig.json, tsconfig.json, .changeset/olive-bugs-prove.md
New package metadata, rslib build config, Vitest config and project entry, TypeScript project refs/configs, turbo task, and a changeset initializing @lynx-js/gesture-runtime.
Lint / Test ignores
biome.jsonc, eslint.config.js
Added ignore pattern packages/lynx/gesture-runtime/__test__/** to linter/test tooling ignores.
Core Gesture Framework
packages/lynx/gesture-runtime/src/baseGesture.ts, packages/lynx/gesture-runtime/src/composition.ts, packages/lynx/gesture-runtime/src/index.ts
Implements BaseGesture/ContinuousGesture, composed gesture classes (Composed/Simultaneous/Exclusive/Race), relation wiring/serialization, and package entry exports including a Gesture factory and re-exports.
Concrete Gestures
packages/lynx/gesture-runtime/src/panGesture.ts, packages/lynx/gesture-runtime/src/tapGesture.ts, packages/lynx/gesture-runtime/src/longPressGesture.ts, packages/lynx/gesture-runtime/src/flingGesture.ts, packages/lynx/gesture-runtime/src/defaultScrollGesture.ts
Adds Pan, Tap, LongPress, Fling, and DefaultScroll gesture classes with configs, setters, and exports.
Type Surface & Globals
packages/lynx/gesture-runtime/src/gestureInterface.ts, packages/lynx/gesture-runtime/src/env_types/global.d.ts
Adds comprehensive TypeScript interfaces/enums for gestures/state managers and ambient global declarations (gesture detector hooks, runWorklet) plus module augmentation.
React Integration
packages/lynx/gesture-runtime/src/useGesture.ts
Adds useGesture hook that manages gesture instances and clones when execId changes.
Utilities
packages/lynx/gesture-runtime/src/utils/const.ts, packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts, packages/lynx/gesture-runtime/src/utils/removeUndefined.ts
New constants (DEFAULT_*), isWorkletObj detection helper, and removeUndefined util.
Tests
packages/lynx/gesture-runtime/__test__/*
Large suite of unit and integration tests covering callbacks, cloning, composition, configuration, React binding, relations, worklet detection, and type-safety.
Test Utilities & Setup
packages/lynx/gesture-runtime/__test__/utils/callback.ts, packages/lynx/gesture-runtime/__test__/utils/setup.ts
Adds MockGestureManager, event generators, trigger helpers, and test setup file with license header.
Documentation
packages/lynx/gesture-runtime/README.md
Adds README with overview, installation, usage example, and docs link.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Pay extra attention to:
    • packages/lynx/gesture-runtime/src/composition.ts — relation wiring, grouping logic, pan-distance propagation.
    • packages/lynx/gesture-runtime/src/baseGesture.ts — state manager proxy, execId mutation/clone semantics, main-thread callback wrapping.
    • Type/interface consistency between gestureInterface.ts and concrete classes.
    • Tests that mock globals (__SetGestureDetector, runWorklet) for correct setup/teardown and isolation.

Suggested reviewers

  • Yradex
  • colinaaa

Poem

🐇 I hopped through code with nimble paws,
new gestures stitched with careful laws.
Pan and Tap and LongPress play,
tests applaud each hopping sway.
A tiny runtime — I nibble, hooray!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add gesture-runtime' clearly and concisely summarizes the main addition - a new gesture-runtime package for the Lynx project.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 533b90f and ec1ef5a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (4)
  • biome.jsonc (1 hunks)
  • eslint.config.js (1 hunks)
  • tsconfig.json (1 hunks)
  • vitest.config.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • eslint.config.js
  • biome.jsonc
  • vitest.config.ts
  • tsconfig.json

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 5, 2025

Codecov Report

❌ Patch coverage is 99.54128% with 2 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...es/lynx/gesture-runtime/__test__/utils/callback.ts 93.75% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (16)
packages/lynx/gesture-runtime/src/utils/removeUndefined.ts (1)

4-10: LGTM! Clean and correct implementation.

The function correctly removes undefined values using a non-mutating, shallow approach. The use of Object.fromEntries and strict equality checking is idiomatic and appropriate.

Optionally, consider adding JSDoc to document that this is a shallow operation (nested undefined values are not removed) and that null values are preserved:

+/**
+ * Removes properties with undefined values from an object (shallow).
+ * @param obj - The input object
+ * @returns A new object with undefined values filtered out
+ */
 export function removeUndefined(
   obj: Record<string, unknown>,
 ): Record<string, unknown> {
eslint.config.js (1)

101-103: Ignoring gesture-runtime tests in ESLint is consistent with existing patterns

This matches how other test-heavy areas are excluded; src remains linted while tests are skipped. If we later want lint coverage on gesture-runtime tests, we can narrow or remove this pattern.

biome.jsonc (1)

54-57: Biome ignore for gesture-runtime tests aligns with ESLint

Ignoring packages/lynx/gesture-runtime/__test__/** here keeps Biome behavior consistent with ESLint and avoids noise from test-only patterns. As with ESLint, we can revisit this if we want Biome checks on tests later.

packages/lynx/gesture-runtime/src/utils/const.ts (1)

1-6: Constants look fine; consider clarifying units

The constants are straightforward and keep gesture defaults centralized. Consider encoding units in the name or adding a brief comment (e.g., DEFAULT_LONGPRESS_DURATION_MS) so callers don't have to infer that 500 is milliseconds and what “distance” represents in this context.

.changeset/olive-bugs-prove.md (1)

1-5: Description uses a different package scope than the actual package

The changeset header correctly references @lynx-js/gesture-runtime, but the description mentions @byted-lynx/gesture-runtime. If there isn’t a separate @byted-lynx/* package intended here, it might be clearer to use the same name as in package.json to avoid confusion.

packages/lynx/gesture-runtime/README.md (1)

1-25: Good initial README; consider tightening the Docs section later

The overview, install command, and basic useGesture(PanGesture) example are clear and match the new API. Once the dedicated guide site is ready, consider replacing the generic “dedicated guide website” note with a concrete link or brief section list so users know where to look for gesture types, composition patterns, and main-thread vs worklet semantics.

packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts (1)

1-13: Clarify main-thread semantics and Worklet typing in isWorkletObj

Two points to double-check:

  1. Main-thread behavior:
    With __MAIN_THREAD__ truthy, this returns true for any input (including null, undefined, primitives, etc.), while still acting as a type guard (obj is Worklet). If the intent is to only treat object-like values as worklets even on the main thread, you might want to move the falsy/object check before the main-thread short-circuit, e.g.:
-export function isWorkletObj(obj: unknown): obj is Worklet {
-  if (__MAIN_THREAD__) {
-    return true;
-  }
-
-  if (!obj) {
-    return false;
-  }
-  return typeof obj === 'object' && '_wkltId' in obj;
-}
+export function isWorkletObj(obj: unknown): obj is Worklet {
+  if (!obj || typeof obj !== 'object') {
+    return false;
+  }
+
+  if (__MAIN_THREAD__) {
+    return true;
+  }
+
+  return '_wkltId' in obj;
+}
  1. Worklet type visibility:
    Ensure Worklet is available in this package’s type scope (e.g., via a global ambient declaration or an explicit import type { Worklet } from '…'). If it’s only exported from a module (like @lynx-js/react/worklet-runtime), you may need to import the type here to avoid TS name resolution issues.
packages/lynx/gesture-runtime/src/defaultGesture.ts (1)

1-26: DefaultGesture implementation is sound; optional constant for tapSlop

The class correctly extends ContinuousGesture, sets type = GestureTypeInner.DEFAULT, provides sensible defaults, and exposes a fluent tapSlop setter via updateConfig.

To avoid magic numbers and keep the default in one place, you could optionally extract the 3 into a named constant:

-import { ContinuousGesture } from './baseGesture.js';
+import { ContinuousGesture } from './baseGesture.js';
 import type {
   DefaultGestureChangeEvent,
   DefaultGestureConfig,
 } from './gestureInterface.js';
 import { GestureTypeInner } from './gestureInterface.js';
 
+const DEFAULT_TAP_SLOP = 3;
+
 class DefaultGesture
   extends ContinuousGesture<DefaultGestureConfig, DefaultGestureChangeEvent>
 {
   type: GestureTypeInner = GestureTypeInner.DEFAULT;
 
   override config: DefaultGestureConfig = {
     enabled: true,
-    tapSlop: 3, // default tap slop
+    tapSlop: DEFAULT_TAP_SLOP,
   };

Purely stylistic; current code is already correct.

packages/lynx/gesture-runtime/tsconfig.build.json (1)

1-20: Confirm noEmit: true in tsconfig.build.json is intentional

This build config extends the root (which has "declaration": true) but overrides with "noEmit": true. That means a tsc -b using this file will not emit JS or .d.ts for @lynx-js/gesture-runtime.

If this tsconfig is meant purely for type-checking in the solution build, that’s fine. If you expect tsc to produce publishable type declarations for this package, you’ll probably want to drop noEmit here instead:

-  "compilerOptions": {
-    "noEmit": true,
+  "compilerOptions": {
     "stripInternal": true,
     "target": "ESNext",
     "lib": ["es2021"],
     "module": "Node16",
     "moduleResolution": "Node16",
     "resolveJsonModule": true,
     "composite": true,
     "jsx": "react-jsx",
     "jsxImportSource": "@lynx-js/react",
     "rootDir": "src",
   },
packages/lynx/gesture-runtime/src/tapGesture.ts (1)

14-18: Consider using a more descriptive constant name for tap maxDuration.

Line 16 uses DEFAULT_LONGPRESS_DURATION for the tap gesture's maxDuration. While the value (500ms) may be appropriate for both gestures, using a constant named "LONGPRESS" for a tap gesture reduces clarity.

Consider either:

  • Creating a separate DEFAULT_TAP_MAX_DURATION constant
  • Using a shared constant with a neutral name like DEFAULT_MAX_DURATION
packages/lynx/gesture-runtime/__test__/gesture-composition-advanced.test.ts (1)

115-148: Clarify “no-throw” intention in external relation tests

In the externalWaitFor / externalSimultaneous / externalContinueWith tests you currently only assert that the resulting arrays have length ≥ 0, which is always true and mainly acts as a proxy for “the call didn’t throw”. To make the intent clearer and avoid vacuous assertions, consider explicitly wrapping the call in an expectation:

-      const composed = Gesture.Simultaneous(tap1, tap2);
-      pan.externalWaitFor(composed);
-
-      // Should not throw
-      expect(pan.waitFor.length).toBeGreaterThanOrEqual(0);
+      const composed = Gesture.Simultaneous(tap1, tap2);
+
+      expect(() => {
+        pan.externalWaitFor(composed);
+      }).not.toThrow();

(and similarly for externalSimultaneous / externalContinueWith).

packages/lynx/gesture-runtime/__test__/gesture-plain.test.ts (1)

71-110: Rename panGesture to tapGesture in this test for clarity

In test('gesture callbacks should have callbacks set'), the variable is a TapGesture but named panGesture, which can be confusing when scanning tests quickly. You can rename it without behavioral impact:

-  test('gesture callbacks should have callbacks set', () => {
-    const panGesture = new TapGesture();
+  test('gesture callbacks should have callbacks set', () => {
+    const tapGesture = new TapGesture();
@@
-    // @ts-expect-error Expected
-    panGesture.onBegin(MainThreadFunction);
-    // @ts-expect-error Expected
-    panGesture.onEnd(MainThreadFunction);
-    // @ts-expect-error Expected
-    panGesture.onTouchesDown(MainThreadFunction);
-    // @ts-expect-error Expected
-    panGesture.onTouchesMove(MainThreadFunction);
-    // @ts-expect-error Expected
-    panGesture.onTouchesUp(MainThreadFunction);
-    // @ts-expect-error Expected
-    panGesture.onTouchesCancel(MainThreadFunction);
-
-    expect(panGesture.callbacks.onBegin).toMatchObject({
+    // @ts-expect-error Expected
+    tapGesture.onBegin(MainThreadFunction);
+    // @ts-expect-error Expected
+    tapGesture.onEnd(MainThreadFunction);
+    // @ts-expect-error Expected
+    tapGesture.onTouchesDown(MainThreadFunction);
+    // @ts-expect-error Expected
+    tapGesture.onTouchesMove(MainThreadFunction);
+    // @ts-expect-error Expected
+    tapGesture.onTouchesUp(MainThreadFunction);
+    // @ts-expect-error Expected
+    tapGesture.onTouchesCancel(MainThreadFunction);
+
+    expect(tapGesture.callbacks.onBegin).toMatchObject({
@@
-    expect(panGesture.callbacks.onEnd).toMatchObject({
+    expect(tapGesture.callbacks.onEnd).toMatchObject({
@@
-    expect(panGesture.callbacks.onTouchesDown).toMatchObject({
+    expect(tapGesture.callbacks.onTouchesDown).toMatchObject({
@@
-    expect(panGesture.callbacks.onTouchesMove).toMatchObject({
+    expect(tapGesture.callbacks.onTouchesMove).toMatchObject({
@@
-    expect(panGesture.callbacks.onTouchesUp).toMatchObject({
+    expect(tapGesture.callbacks.onTouchesUp).toMatchObject({
@@
-    expect(panGesture.callbacks.onTouchesCancel).toMatchObject({
+    expect(tapGesture.callbacks.onTouchesCancel).toMatchObject({
packages/lynx/gesture-runtime/src/panGesture.ts (1)

23-46: Align minDistance parameter type with its undefined handling

minDistance is typed as (distance: number) but its implementation explicitly branches on distance === undefined to clear distanceSet. In regular TS usage, callers won’t be able to pass undefined without a type assertion, so that branch is effectively unreachable from type-safe code.

To make the intent explicit and keep type and implementation in sync, consider:

-  minDistance = (distance: number): this => {
+  minDistance = (distance?: number): this => {
     // We need to know whether distance is set by user or it's default value
     // So that we can get to know override it or not
     if (distance === undefined) {
       this.distanceSet = false;
     } else {
       this.distanceSet = true;
     }
     return this.updateConfig('minDistance', distance);
   };

This keeps current behavior but better reflects the “reset to default when undefined” semantics.

packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (2)

70-75: Strengthen the gesture callback assertion

expect(panGesture.callbacks.onUpdate).toMatchObject({}); will pass for any object, so it doesn’t really validate the shape of the stored callback. Since other tests assert the Worklet-like structure, you could make this more meaningful by mirroring that pattern:

-    panGesture.onUpdate(MainThreadFunction);
-
-    expect(panGesture.callbacks.onUpdate).toMatchObject({});
+    panGesture.onUpdate(MainThreadFunction);
+
+    expect(panGesture.callbacks.onUpdate).toMatchObject({
+      _c: {},
+      _wkltId: expect.any(String),
+    });

This would better confirm that onUpdate stores a proper main-thread callback object.


131-162: Clarify naming and intent in useGesture instance-change test

In test('useGesture should create different instance when updated'), prevPanExecId actually holds the whole gesture instance, not an execId, and the assertion is comparing object identity:

prevPanExecId = _panGesture;

expect(_panGesture).not.toBe(prevPanExecId);

For clarity (and to express intent more accurately), either rename the variable or compare execId explicitly. For example:

-    await act(() => {
-      const { container } = render(<App />);
-    });
-
-    prevPanExecId = _panGesture;
+    await act(() => {
+      render(<App />);
+    });
+
+    prevPanExecId = _panGesture.execId;
@@
-    expect(_panGesture).not.toBe(prevPanExecId);
+    expect(_panGesture.execId).not.toBe(prevPanExecId);

This keeps the behavior but makes the test’s intent much clearer.

packages/lynx/gesture-runtime/src/baseGesture.ts (1)

268-274: Redundant Object.assign after constructor copy.

The constructor already copies all properties from the source gesture (lines 134-140). The subsequent Object.assign(cloned, this) overwrites the shallow-copied arrays with the same references, potentially causing shared mutable state between the original and clone.

   clone = (): this => {
-    // Create new instance
-    const cloned = new (this.constructor as new(gesture?: this) => this)(this);
-    Object.assign(cloned, this);
-
-    return cloned;
+    return new (this.constructor as new(gesture?: this) => this)(this);
   };
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6400f87 and 81e496c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (38)
  • .changeset/olive-bugs-prove.md (1 hunks)
  • biome.jsonc (1 hunks)
  • eslint.config.js (1 hunks)
  • packages/lynx/gesture-runtime/README.md (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-callback.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-clone.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-composition-advanced.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-config.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-plain.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/type-safety.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/utils/callback.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/utils/setup.ts (1 hunks)
  • packages/lynx/gesture-runtime/package.json (1 hunks)
  • packages/lynx/gesture-runtime/rslib.config.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/baseGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/composition.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/defaultGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/env_types/global.d.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/flingGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/gestureInterface.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/index.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/longPressGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/nativeGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/panGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/tapGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/useGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/utils/const.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/utils/removeUndefined.ts (1 hunks)
  • packages/lynx/gesture-runtime/tsconfig.build.json (1 hunks)
  • packages/lynx/gesture-runtime/tsconfig.json (1 hunks)
  • packages/lynx/gesture-runtime/tsconfig.test.json (1 hunks)
  • packages/lynx/gesture-runtime/vitest.config.ts (1 hunks)
  • packages/lynx/tsconfig.json (1 hunks)
  • tsconfig.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

For contributions, generate and commit a Changeset describing your changes

Files:

  • .changeset/olive-bugs-prove.md
🧠 Learnings (25)
📓 Common learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.
📚 Learning: 2025-10-11T06:16:12.517Z
Learnt from: Sherry-hue
Repo: lynx-family/lynx-stack PR: 1820
File: packages/web-platform/web-tests/tests/react.spec.ts:834-856
Timestamp: 2025-10-11T06:16:12.517Z
Learning: In packages/web-platform/web-tests/tests/react.spec.ts, the tests `basic-bindmouse` and `basic-mts-bindtouchstart` are NOT duplicates despite having similar test structures. They test different event types: `basic-bindmouse` validates mouse events (mousedown, mouseup, mousemove) with mouse-specific properties (button, buttons, x, y, pageX, pageY, clientX, clientY), while `basic-mts-bindtouchstart` validates touch events (touchstart) with touch arrays (touches, targetTouches, changedTouches). The similar test structure is coincidental and follows testing conventions.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-composition-advanced.test.ts
  • packages/lynx/gesture-runtime/__test__/gesture-callback.test.tsx
  • packages/lynx/gesture-runtime/__test__/gesture-clone.test.ts
  • packages/lynx/gesture-runtime/__test__/gesture-config.test.ts
  • packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • packages/lynx/gesture-runtime/__test__/type-safety.test.ts
  • packages/lynx/gesture-runtime/__test__/gesture-plain.test.ts
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/utils/setup.ts
  • biome.jsonc
  • packages/lynx/gesture-runtime/rslib.config.ts
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • tsconfig.json
  • packages/lynx/tsconfig.json
  • eslint.config.js
  • packages/lynx/gesture-runtime/README.md
  • packages/lynx/gesture-runtime/tsconfig.test.json
  • .changeset/olive-bugs-prove.md
  • packages/lynx/gesture-runtime/package.json
  • packages/lynx/gesture-runtime/tsconfig.json
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/utils/setup.ts
  • biome.jsonc
  • packages/lynx/gesture-runtime/rslib.config.ts
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • tsconfig.json
  • packages/lynx/tsconfig.json
  • eslint.config.js
  • packages/lynx/gesture-runtime/README.md
  • packages/lynx/gesture-runtime/tsconfig.test.json
  • .changeset/olive-bugs-prove.md
  • packages/lynx/gesture-runtime/package.json
  • packages/lynx/gesture-runtime/tsconfig.json
📚 Learning: 2025-08-14T12:54:51.143Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: .changeset/brave-melons-add.md:1-7
Timestamp: 2025-08-14T12:54:51.143Z
Learning: In the lynx-family/lynx-stack repository, packages use 0.x.x versioning where minor version bumps indicate breaking changes (not major bumps), following pre-1.0 semantic versioning conventions.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/utils/setup.ts
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Applied to files:

  • biome.jsonc
  • packages/lynx/gesture-runtime/rslib.config.ts
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • tsconfig.json
  • packages/lynx/tsconfig.json
  • eslint.config.js
  • packages/lynx/gesture-runtime/tsconfig.test.json
  • .changeset/olive-bugs-prove.md
  • packages/lynx/gesture-runtime/tsconfig.json
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • biome.jsonc
  • packages/lynx/gesture-runtime/__test__/gesture-config.test.ts
  • packages/lynx/gesture-runtime/rslib.config.ts
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • packages/lynx/gesture-runtime/vitest.config.ts
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • tsconfig.json
  • packages/lynx/tsconfig.json
  • eslint.config.js
  • packages/lynx/gesture-runtime/tsconfig.test.json
  • packages/lynx/gesture-runtime/package.json
  • packages/lynx/gesture-runtime/tsconfig.json
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts
📚 Learning: 2025-08-11T05:59:28.530Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:4-6
Timestamp: 2025-08-11T05:59:28.530Z
Learning: In the lynx-family/lynx-stack repository, the `packages/react/testing-library` package does not have `vite` as a direct dependency. It relies on `vitest` being available from the monorepo root and accesses Vite types through re-exports from `vitest/node`. Direct imports from `vite` should not be suggested for this package.

Applied to files:

  • biome.jsonc
  • packages/lynx/gesture-runtime/vitest.config.ts
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • tsconfig.json
  • eslint.config.js
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • biome.jsonc
  • packages/lynx/gesture-runtime/rslib.config.ts
  • packages/lynx/gesture-runtime/vitest.config.ts
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • tsconfig.json
  • packages/lynx/tsconfig.json
  • eslint.config.js
  • packages/lynx/gesture-runtime/tsconfig.test.json
  • packages/lynx/gesture-runtime/tsconfig.json
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts
📚 Learning: 2025-08-11T06:00:04.376Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:59-61
Timestamp: 2025-08-11T06:00:04.376Z
Learning: In the lynx-family/lynx-stack repository, the `testingLibraryPlugin` in `packages/react/testing-library/src/plugins/vitest.ts` intentionally uses `process.exit` when jsdom installation fails, maintaining consistency with the previous implementation from `packages/react/testing-library/src/vitest.config.js`. This behavior should not be changed to use `this.error` despite being a Vite plugin best practice.

Applied to files:

  • biome.jsonc
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • biome.jsonc
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • tsconfig.json
  • packages/lynx/tsconfig.json
  • packages/lynx/gesture-runtime/README.md
  • packages/lynx/gesture-runtime/package.json
  • packages/lynx/gesture-runtime/tsconfig.json
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • biome.jsonc
  • packages/lynx/gesture-runtime/src/env_types/global.d.ts
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts
📚 Learning: 2025-08-11T05:57:18.212Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/testing-library/testing-environment/src/index.ts:255-258
Timestamp: 2025-08-11T05:57:18.212Z
Learning: In the ReactLynx testing environment (`packages/testing-library/testing-environment/src/index.ts`), the dual assignment pattern `target.console.method = console.method = () => {}` is required for rstest compatibility. This is because rstest provides `console` in an IIFE (Immediately Invoked Function Expression), and both the target and global console need to have these methods defined for proper test execution.

Applied to files:

  • biome.jsonc
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • packages/lynx/gesture-runtime/vitest.config.ts
  • eslint.config.js
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts
📚 Learning: 2025-11-04T10:15:14.965Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1899
File: packages/react/runtime/__test__/snapshotPatch.test.jsx:725-749
Timestamp: 2025-11-04T10:15:14.965Z
Learning: In packages/react/runtime/src/snapshot.ts, the snapshotCreatorMap type signature uses `Record<string, (uniqId: string) => string>` (returning string) rather than void for backward compatibility. Old lazy bundles still use the pattern `const snapshot_xxx = createSnapshot(...)` directly, which requires createSnapshot to return a value. The snapshotCreatorMap creators that wrap createSnapshot calls must maintain the same return type to support these legacy bundles.

Applied to files:

  • packages/lynx/gesture-runtime/src/utils/removeUndefined.ts
📚 Learning: 2025-08-12T16:09:32.413Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.

Applied to files:

  • packages/lynx/gesture-runtime/src/env_types/global.d.ts
  • packages/lynx/gesture-runtime/README.md
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-09-28T08:46:43.177Z
Learnt from: f0rdream
Repo: lynx-family/lynx-stack PR: 1835
File: packages/react/worklet-runtime/src/workletRuntime.ts:52-55
Timestamp: 2025-09-28T08:46:43.177Z
Learning: The legacy worklet path with `_lepusWorkletHash` in `packages/react/worklet-runtime/src/workletRuntime.ts` is preserved for compatibility with MTS (Mini-app Threading Service) that doesn't support Initial Frame Rendering. This path will not be touched in current implementations.

Applied to files:

  • packages/lynx/gesture-runtime/src/env_types/global.d.ts
  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts
📚 Learning: 2025-08-21T08:46:54.494Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.

Applied to files:

  • packages/lynx/gesture-runtime/src/env_types/global.d.ts
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • packages/lynx/gesture-runtime/README.md
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • packages/lynx/gesture-runtime/rslib.config.ts
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • packages/lynx/tsconfig.json
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • packages/lynx/gesture-runtime/rslib.config.ts
  • packages/lynx/gesture-runtime/vitest.config.ts
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • tsconfig.json
  • packages/lynx/tsconfig.json
  • packages/lynx/gesture-runtime/package.json
  • packages/lynx/gesture-runtime/tsconfig.json
📚 Learning: 2025-11-06T01:19:23.670Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1917
File: packages/mcp-servers/devtool-mcp-server/tsconfig.json:8-8
Timestamp: 2025-11-06T01:19:23.670Z
Learning: The lynx-js/devtool-mcp-server package in lynx-family/lynx-stack targets Node.js >=18.19 (specified in its package.json engines), which is different from the root project's requirement of Node.js ^22 || ^24. The package uses "lib": ["ES2024.Promise"] in its tsconfig.json because it manually includes polyfills for Promise.withResolvers while maintaining compatibility with Node.js v18.

Applied to files:

  • packages/lynx/gesture-runtime/rslib.config.ts
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • tsconfig.json
  • packages/lynx/tsconfig.json
  • packages/lynx/gesture-runtime/tsconfig.test.json
  • packages/lynx/gesture-runtime/package.json
  • packages/lynx/gesture-runtime/tsconfig.json
📚 Learning: 2025-08-13T11:36:12.075Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:52-72
Timestamp: 2025-08-13T11:36:12.075Z
Learning: The lynx-stack project requires Node.js >=22 as specified in package.json engines, so Node.js compatibility fallbacks for features introduced before v22 are unnecessary.

Applied to files:

  • packages/lynx/gesture-runtime/tsconfig.build.json
  • packages/lynx/tsconfig.json
📚 Learning: 2025-07-22T09:23:07.797Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.

Applied to files:

  • tsconfig.json
  • .changeset/olive-bugs-prove.md
📚 Learning: 2025-10-29T10:28:27.519Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1899
File: packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/lib.rs/should_static_extract_dynamic_inline_style.js:20-24
Timestamp: 2025-10-29T10:28:27.519Z
Learning: Files inside packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/ are auto-generated test snapshot files and should not be manually updated. Any issues with the generated code should be addressed in the code generator/transform logic, not in the snapshots themselves.

Applied to files:

  • packages/lynx/gesture-runtime/tsconfig.test.json
📚 Learning: 2025-08-07T04:00:59.645Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1454
File: pnpm-workspace.yaml:46-46
Timestamp: 2025-08-07T04:00:59.645Z
Learning: In the lynx-family/lynx-stack repository, the webpack patch (patches/webpack5.101.0.patch) was created to fix issues with webpack5.99.9 but only takes effect on webpack5.100.0 and later versions. The patchedDependencies entry should use "webpack@^5.100.0" to ensure the patch applies to the correct version range.

Applied to files:

  • .changeset/olive-bugs-prove.md
📚 Learning: 2025-08-19T12:49:05.875Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/template-webpack-plugin/src/LynxCacheEventsSetupListRuntimeModule.ts:21-25
Timestamp: 2025-08-19T12:49:05.875Z
Learning: In the Lynx cache events system, there are two separate runtime modules with distinct responsibilities: `LynxCacheEventsSetupListRuntimeModule` is only responsible for initializing the setup list with the setup functions, while `LynxCacheEventsRuntimeModule` guarantees the initialization of `loaded` and `cachedActions` properties. The modules have a dependency relationship where `lynxCacheEventsSetupList` is required by `lynxCacheEvents`.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
🧬 Code graph analysis (12)
packages/lynx/gesture-runtime/src/longPressGesture.ts (3)
packages/lynx/gesture-runtime/src/index.ts (2)
  • LongPressGesture (46-46)
  • BaseGesture (38-38)
packages/lynx/gesture-runtime/src/gestureInterface.ts (2)
  • LongPressGestureConfig (237-242)
  • LongPressGestureChangeEvent (65-65)
packages/lynx/gesture-runtime/src/utils/const.ts (2)
  • DEFAULT_LONGPRESS_DURATION (6-6)
  • DEFAULT_DISTANCE (4-4)
packages/lynx/gesture-runtime/__test__/gesture-composition-advanced.test.ts (6)
packages/lynx/gesture-runtime/src/index.ts (4)
  • PanGesture (44-44)
  • TapGesture (45-45)
  • ComposedGesture (40-40)
  • LongPressGesture (46-46)
packages/lynx/gesture-runtime/src/panGesture.ts (1)
  • PanGesture (49-49)
packages/lynx/gesture-runtime/src/tapGesture.ts (1)
  • TapGesture (33-33)
packages/lynx/gesture-runtime/src/composition.ts (1)
  • ComposedGesture (170-170)
packages/web-platform/web-tests/tests/coverage-fixture.ts (1)
  • expect (62-62)
packages/lynx/gesture-runtime/src/longPressGesture.ts (1)
  • LongPressGesture (31-31)
packages/lynx/gesture-runtime/src/defaultGesture.ts (2)
packages/lynx/gesture-runtime/src/baseGesture.ts (1)
  • ContinuousGesture (304-304)
packages/lynx/gesture-runtime/src/gestureInterface.ts (2)
  • DefaultGestureConfig (259-262)
  • DefaultGestureChangeEvent (85-94)
packages/lynx/gesture-runtime/__test__/gesture-config.test.ts (7)
packages/lynx/gesture-runtime/src/index.ts (6)
  • PanGesture (44-44)
  • TapGesture (45-45)
  • LongPressGesture (46-46)
  • FlingGesture (43-43)
  • DefaultGesture (42-42)
  • NativeGesture (47-47)
packages/lynx/gesture-runtime/src/panGesture.ts (1)
  • PanGesture (49-49)
packages/lynx/gesture-runtime/src/tapGesture.ts (1)
  • TapGesture (33-33)
packages/lynx/gesture-runtime/src/longPressGesture.ts (1)
  • LongPressGesture (31-31)
packages/lynx/gesture-runtime/src/flingGesture.ts (1)
  • FlingGesture (22-22)
packages/lynx/gesture-runtime/src/defaultGesture.ts (1)
  • DefaultGesture (26-26)
packages/lynx/gesture-runtime/src/nativeGesture.ts (1)
  • NativeGesture (17-17)
packages/lynx/gesture-runtime/src/flingGesture.ts (3)
packages/lynx/gesture-runtime/src/index.ts (1)
  • FlingGesture (43-43)
packages/lynx/gesture-runtime/src/baseGesture.ts (1)
  • ContinuousGesture (304-304)
packages/lynx/gesture-runtime/src/gestureInterface.ts (2)
  • FlingGestureConfig (248-253)
  • FlingGestureChangeEvent (70-79)
packages/lynx/gesture-runtime/__test__/utils/callback.ts (2)
packages/lynx/gesture-runtime/src/gestureInterface.ts (1)
  • ConsumeGesturePrams (110-113)
packages/react/runtime/src/gesture/types.ts (1)
  • GestureConfig (38-44)
packages/lynx/gesture-runtime/src/index.ts (2)
packages/lynx/gesture-runtime/src/gestureInterface.ts (1)
  • GestureKind (16-24)
packages/lynx/gesture-runtime/src/composition.ts (3)
  • SimultaneousGesture (170-170)
  • RaceGesture (170-170)
  • ExclusiveGesture (170-170)
packages/lynx/gesture-runtime/__test__/type-safety.test.ts (2)
packages/lynx/gesture-runtime/src/index.ts (5)
  • PanGesture (44-44)
  • TapGesture (45-45)
  • LongPressGesture (46-46)
  • FlingGesture (43-43)
  • DefaultGesture (42-42)
packages/lynx/gesture-runtime/src/gestureInterface.ts (5)
  • PanGestureConfig (207-218)
  • TapGestureConfig (224-231)
  • LongPressGestureConfig (237-242)
  • FlingGestureConfig (248-253)
  • DefaultGestureConfig (259-262)
packages/lynx/gesture-runtime/src/nativeGesture.ts (3)
packages/lynx/gesture-runtime/src/index.ts (1)
  • NativeGesture (47-47)
packages/lynx/gesture-runtime/src/baseGesture.ts (1)
  • ContinuousGesture (304-304)
packages/lynx/gesture-runtime/src/gestureInterface.ts (2)
  • NativeGestureConfig (268-270)
  • NativeGestureChangeEvent (100-102)
packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts (1)
packages/react/worklet-runtime/src/bindings/types.ts (1)
  • Worklet (41-52)
packages/lynx/gesture-runtime/__test__/gesture-plain.test.ts (8)
packages/lynx/gesture-runtime/src/index.ts (7)
  • PanGesture (44-44)
  • FlingGesture (43-43)
  • TapGesture (45-45)
  • LongPressGesture (46-46)
  • NativeGesture (47-47)
  • DefaultGesture (42-42)
  • ComposedGesture (40-40)
packages/lynx/gesture-runtime/src/panGesture.ts (1)
  • PanGesture (49-49)
packages/lynx/gesture-runtime/src/flingGesture.ts (1)
  • FlingGesture (22-22)
packages/lynx/gesture-runtime/src/tapGesture.ts (1)
  • TapGesture (33-33)
packages/lynx/gesture-runtime/src/nativeGesture.ts (1)
  • NativeGesture (17-17)
packages/lynx/gesture-runtime/src/defaultGesture.ts (1)
  • DefaultGesture (26-26)
packages/lynx/gesture-runtime/src/composition.ts (1)
  • ComposedGesture (170-170)
packages/lynx/gesture-runtime/src/utils/const.ts (1)
  • DEFAULT_DISTANCE (4-4)
packages/lynx/gesture-runtime/src/gestureInterface.ts (2)
packages/lynx/gesture-runtime/src/baseGesture.ts (1)
  • BaseGesture (304-304)
packages/lynx/gesture-runtime/src/index.ts (1)
  • BaseGesture (38-38)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: zizmor
  • GitHub Check: test-rust / Test (Ubuntu)
  • GitHub Check: test-typos
🔇 Additional comments (27)
packages/lynx/gesture-runtime/rslib.config.ts (1)

1-17: Config looks good and consistent for a typed ESM runtime lib

The rslib config is minimal, syntactically correct, and matches a sensible setup for @lynx-js/gesture-runtime (ESM output, ES2022 syntax, declarations on, no bundling, and publint enabled). No changes requested.

packages/lynx/gesture-runtime/__test__/utils/setup.ts (1)

1-3: Header matches project licensing format

The Apache-2.0 header here is consistent with the rest of the repo and the eslint header rule configuration.

packages/lynx/tsconfig.json (1)

1-11: Solution-style tsconfig for Lynx packages looks correct

Using composite: true with an empty include and a reference to ./gesture-runtime/tsconfig.build.json is a standard solution-style setup and should integrate gesture-runtime cleanly into the project references.

packages/lynx/gesture-runtime/tsconfig.test.json (1)

1-7: Check that extending tsconfig.build doesn’t drop required includes for tests

tsconfig.test.json overrides include with ["src", "__test__"]. In TypeScript, this replaces (does not merge with) the base include, so any extra paths from tsconfig.build.json (e.g., env_types/global.d.ts or similar) won’t be picked up unless they’re referenced via files/typeRoots or re-added here.

Please verify that all required declaration files for the gesture runtime test environment are still part of the TS program, and add them to include if they were previously only included in the base config.

packages/lynx/gesture-runtime/package.json (1)

1-37: License string and version number require verification

package.json declares "license": "ISC", but this should be verified against the actual source file headers and repo-level licensing configuration (expected to be Apache-2.0 based on typical monorepo practices). Ensure the license field matches the actual license applied to this package.

Also, "version": "2.0.0" appears inconsistent with the versioning convention used for other @lynx-js/* packages in this repository, which typically follow pre-1.0 semantic versioning (0.x.y). Confirm whether 2.0.0 is intentional or should align with the existing versioning scheme.

packages/lynx/gesture-runtime/tsconfig.json (1)

1-7: Package tsconfig wiring looks good

Using an empty "files": [] with references to tsconfig.build.json and tsconfig.test.json matches the usual solution-style pattern and should integrate cleanly with the project references.

tsconfig.json (1)

109-131: New ./packages/lynx project reference is appropriate

Adding the ./packages/lynx reference here is the right way to bring the new Lynx subtree (and gesture-runtime under it) into the solution build graph.

packages/lynx/gesture-runtime/src/nativeGesture.ts (1)

1-17: NativeGesture implementation is consistent with the gesture base API

Extending ContinuousGesture<NativeGestureConfig, NativeGestureChangeEvent> and setting type = GestureTypeInner.NATIVE aligns with the pattern used by the other gesture classes and the types defined in gestureInterface.ts. No issues from this file.

packages/lynx/gesture-runtime/vitest.config.ts (1)

1-17: Vitest configuration looks appropriate for the new package

Merging the shared createVitestConfig() with a focused override (package name, setup file, coverage include of src/**, and excluding __test__/utils/**) is a clean way to plug gesture-runtime into the existing test tooling. The config shape looks correct for Vitest.

packages/lynx/gesture-runtime/__test__/gesture-config.test.ts (1)

1-238: LGTM! Comprehensive test coverage for gesture configuration.

The test suite thoroughly validates configuration APIs across all gesture types (PanGesture, TapGesture, LongPressGesture, FlingGesture, DefaultGesture, NativeGesture), including default values, method chaining, unique ID generation, and execId progression. The tests provide solid coverage for the new gesture-runtime API surface.

packages/lynx/gesture-runtime/src/useGesture.ts (1)

21-34: LGTM! Clean gesture lifecycle management.

The hook correctly manages gesture instances by:

  1. Creating the gesture once via useRef initialization
  2. Detecting configuration changes through execId comparison
  3. Cloning the gesture when configuration changes to ensure proper React integration

This pattern ensures that gesture configuration updates are properly tracked and propagated.

packages/lynx/gesture-runtime/src/flingGesture.ts (1)

1-22: LGTM! Clean minimal gesture implementation.

The FlingGesture class appropriately extends ContinuousGesture and defines the payload interface for change events. All configuration and behavior are correctly inherited from the base class.

packages/lynx/gesture-runtime/__test__/type-safety.test.ts (1)

1-98: LGTM! Solid type safety validation.

The test suite effectively validates TypeScript type constraints across gesture configuration APIs, ensuring that:

  • Config types are correctly inferred for each gesture type
  • Method chaining preserves correct types
  • Callbacks are properly typed
  • Runtime behaviors work as expected with appropriate type annotations

The use of @ts-expect-error for main-thread callback testing is appropriate.

packages/lynx/gesture-runtime/src/longPressGesture.ts (1)

1-31: LGTM! Well-structured gesture implementation.

The LongPressGesture class is cleanly implemented with:

  • Appropriate defaults (500ms minDuration, 10 points maxDistance)
  • Fluent configuration API with proper method chaining
  • Correct type declaration
packages/lynx/gesture-runtime/src/tapGesture.ts (1)

20-31: LGTM! Clean fluent API implementation.

The configuration methods properly implement the fluent API pattern with appropriate parameter types and return values for method chaining.

packages/lynx/gesture-runtime/__test__/gesture-callback.test.tsx (1)

1-323: LGTM! Comprehensive gesture callback testing.

The test suite thoroughly validates gesture interactions with the main thread, including:

  • Gesture binding and event parameter passing
  • State manager operations (active, fail, end)
  • Gesture consumption and interception
  • Proper mock setup and teardown

The tests correctly use the 'main thread'; directive to mark callbacks for main-thread execution and verify the expected interactions with platform APIs.

packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts (1)

78-85: Confirm that isWorkletObj checks for property existence, not truthiness.

The test expects isWorkletObj({ _wkltId: '' }) to return true, indicating the implementation must check property existence (e.g., '_wkltId' in obj or hasOwnProperty) rather than evaluating the property value. Verify the implementation uses a property existence check to handle falsy values correctly.

packages/lynx/gesture-runtime/__test__/gesture-clone.test.ts (1)

18-249: Clone behavior test coverage looks consistent with intended semantics

The cloning tests comprehensively pin down config, callbacks, relationships, identity (id/execId/type), and special flags like distanceSet / __isGesture, including the intentional shallow sharing of config. This gives a solid safety net for future refactors of the clone logic.

packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx (1)

14-191: Edge-case coverage for relations and compositions is strong

These tests thoroughly exercise relation extension (including undefined/empty cases), prepareSingleGesture for both base and composed gestures, serialization/toJSON, flattening, pan-distance idempotence, and single/empty composition scenarios. This should catch most regressions in ComposedGesture relation handling.

packages/lynx/gesture-runtime/src/index.ts (1)

21-48: Entry-point API is clear and aligned with tests

GestureEntry (aliased as Gesture) cleanly wraps SimultaneousGesture, RaceGesture, and ExclusiveGesture and returns GestureKind, which matches how all the tests consume it. The explicit re-exports of gesture classes, gestureInterface, and useGesture make this a solid, coherent public surface for the package.

packages/lynx/gesture-runtime/src/env_types/global.d.ts (1)

1-30: Ambient declarations for Lynx Engine globals look appropriate.

The use of __-prefixed functions aligns with Lynx Engine conventions for globally injected functions. The module augmentation pattern for @lynx-js/types is clean.

packages/lynx/gesture-runtime/src/baseGesture.ts (1)

25-114: Callback wrapping and StateManager implementation are well-structured.

The main-thread validation via isWorkletObj check and the dynamic StateManager class instantiation within the worklet context is a solid pattern for gesture state management.

packages/lynx/gesture-runtime/src/composition.ts (3)

52-56: Inconsistent relationship handling for nested ComposedGesture.

When gesture is a BaseGesture, relationships are extended (using extendRelation). However, when it's a ComposedGesture, relationships are overwritten directly. This asymmetry may cause loss of pre-existing relationships on nested composed gestures.

Is this intentional behavior? If composed gestures should also preserve their existing relationships, consider:

     } else if (gesture instanceof ComposedGesture) {
-      gesture.simultaneousWith = simultaneousGestures;
-      gesture.waitFor = waitFor;
+      gesture.simultaneousWith = extendRelation(
+        gesture.simultaneousWith,
+        simultaneousGestures,
+      );
+      gesture.waitFor = extendRelation(gesture.waitFor, waitFor);
       gesture.prepare();
     }

115-142: SimultaneousGesture.prepare() logic is correct and well-documented.

The algorithm correctly builds mutual simultaneity relationships while avoiding self-referential linkage for exclusive gestures. The inline comments explaining the "magic" are helpful.


144-166: ExclusiveGesture.prepare() correctly chains wait-for dependencies.

The cascading requireToFail accumulation ensures each gesture group waits for all preceding groups, implementing proper exclusive behavior.

packages/lynx/gesture-runtime/src/gestureInterface.ts (2)

26-103: Gesture event interfaces are well-structured with proper inheritance.

The event type hierarchy with GestureChangeEvent as the base and specific extensions for pan, fling, and default gestures provides good type safety. Empty extensions for tap, long-press, and native gestures allow future additions without breaking changes.


194-302: Configuration and callback interfaces are comprehensive and well-documented.

The JSDoc comments clearly explain each config option with defaults. The module augmentation for StandardProps properly extends the external type system.

Comment thread packages/lynx/gesture-runtime/__test__/utils/callback.ts Outdated
Comment thread packages/lynx/gesture-runtime/src/baseGesture.ts
Comment thread packages/lynx/gesture-runtime/src/baseGesture.ts
Comment thread packages/lynx/gesture-runtime/src/baseGesture.ts
Comment thread packages/lynx/gesture-runtime/src/env_types/global.d.ts Outdated
Comment thread packages/lynx/gesture-runtime/src/gestureInterface.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
packages/lynx/gesture-runtime/src/flingGesture.ts (1)

16-20: Consider adding configuration methods for consistency.

FlingGesture is notably minimal compared to other gesture implementations (e.g., PanGesture has minDistance(), TapGesture has maxDuration(), maxDistance()). According to gestureInterface.ts, FlingGestureConfig includes direction and numberOfPointers properties, but there are no fluent configuration methods to set these values.

Consider adding configuration methods for better developer experience:

direction = (direction: 'up' | 'down' | 'left' | 'right'): this => {
  return this.updateConfig('direction', direction);
};

numberOfPointers = (count: number): this => {
  return this.updateConfig('numberOfPointers', count);
};
packages/lynx/gesture-runtime/src/panGesture.ts (1)

39-46: Minor: Simplify control flow.

The method has a slightly redundant control flow structure.

Consider simplifying:

 overrideDefaultMinDistance = (): this => {
-  if (this.distanceSet) {
-    return this;
-  } else {
+  if (!this.distanceSet) {
     this.updateConfig('minDistance', DEFAULT_DISTANCE);
   }
   return this;
 };
packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (1)

158-348: Consolidate duplicate test cases.

The three test cases (lines 172-224, 226-278, 295-347) appear to be duplicates with identical setup, execution, and assertions. The only differences are the test names: "bind gestures should call __SetGestureDetector correctly", "bind gestures should call __SetGestureDetector with relationsConfig", and "Old ReactLynx would call __SetGestureDetector correctly".

Consider consolidating into a single test or clearly differentiating what each test validates. If they're testing different scenarios, update the test setup or assertions to reflect those differences.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 81e496c and 8ee8885.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (37)
  • .changeset/olive-bugs-prove.md (1 hunks)
  • biome.jsonc (1 hunks)
  • eslint.config.js (1 hunks)
  • packages/lynx/gesture-runtime/README.md (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-callback.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-clone.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-composition-advanced.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-config.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-plain.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/type-safety.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/utils/callback.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/utils/setup.ts (1 hunks)
  • packages/lynx/gesture-runtime/package.json (1 hunks)
  • packages/lynx/gesture-runtime/rslib.config.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/baseGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/composition.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/defaultScrollGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/env_types/global.d.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/flingGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/gestureInterface.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/index.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/longPressGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/panGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/tapGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/useGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/utils/const.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/utils/removeUndefined.ts (1 hunks)
  • packages/lynx/gesture-runtime/tsconfig.build.json (1 hunks)
  • packages/lynx/gesture-runtime/tsconfig.json (1 hunks)
  • packages/lynx/gesture-runtime/tsconfig.test.json (1 hunks)
  • packages/lynx/gesture-runtime/vitest.config.ts (1 hunks)
  • packages/lynx/tsconfig.json (1 hunks)
  • tsconfig.json (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • packages/lynx/gesture-runtime/test/utils/setup.ts
  • packages/lynx/gesture-runtime/tsconfig.json
🚧 Files skipped from review as they are similar to previous changes (19)
  • packages/lynx/gesture-runtime/test/type-safety.test.ts
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • packages/lynx/gesture-runtime/src/tapGesture.ts
  • packages/lynx/gesture-runtime/test/gesture-callback.test.tsx
  • packages/lynx/gesture-runtime/src/baseGesture.ts
  • packages/lynx/gesture-runtime/src/longPressGesture.ts
  • packages/lynx/tsconfig.json
  • packages/lynx/gesture-runtime/src/useGesture.ts
  • packages/lynx/gesture-runtime/test/gesture-plain.test.ts
  • packages/lynx/gesture-runtime/test/gesture-composition-advanced.test.ts
  • biome.jsonc
  • packages/lynx/gesture-runtime/test/is-worklet-object.test.ts
  • packages/lynx/gesture-runtime/src/composition.ts
  • packages/lynx/gesture-runtime/src/utils/const.ts
  • packages/lynx/gesture-runtime/src/env_types/global.d.ts
  • packages/lynx/gesture-runtime/tsconfig.test.json
  • packages/lynx/gesture-runtime/test/utils/callback.ts
  • packages/lynx/gesture-runtime/test/gesture-config.test.ts
  • packages/lynx/gesture-runtime/rslib.config.ts
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

For contributions, generate and commit a Changeset describing your changes

Files:

  • .changeset/olive-bugs-prove.md
🧠 Learnings (21)
📓 Common learnings
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • .changeset/olive-bugs-prove.md
  • packages/lynx/gesture-runtime/package.json
  • packages/lynx/gesture-runtime/README.md
  • eslint.config.js
  • tsconfig.json
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • .changeset/olive-bugs-prove.md
  • packages/lynx/gesture-runtime/package.json
  • packages/lynx/gesture-runtime/README.md
  • eslint.config.js
  • tsconfig.json
📚 Learning: 2025-07-22T09:23:07.797Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.

Applied to files:

  • .changeset/olive-bugs-prove.md
  • tsconfig.json
📚 Learning: 2025-08-07T04:00:59.645Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1454
File: pnpm-workspace.yaml:46-46
Timestamp: 2025-08-07T04:00:59.645Z
Learning: In the lynx-family/lynx-stack repository, the webpack patch (patches/webpack5.101.0.patch) was created to fix issues with webpack5.99.9 but only takes effect on webpack5.100.0 and later versions. The patchedDependencies entry should use "webpack@^5.100.0" to ensure the patch applies to the correct version range.

Applied to files:

  • .changeset/olive-bugs-prove.md
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Applied to files:

  • .changeset/olive-bugs-prove.md
  • eslint.config.js
  • tsconfig.json
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/lynx/gesture-runtime/vitest.config.ts
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • packages/lynx/gesture-runtime/package.json
  • eslint.config.js
  • tsconfig.json
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/lynx/gesture-runtime/vitest.config.ts
  • eslint.config.js
  • tsconfig.json
📚 Learning: 2025-08-11T05:59:28.530Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:4-6
Timestamp: 2025-08-11T05:59:28.530Z
Learning: In the lynx-family/lynx-stack repository, the `packages/react/testing-library` package does not have `vite` as a direct dependency. It relies on `vitest` being available from the monorepo root and accesses Vite types through re-exports from `vitest/node`. Direct imports from `vite` should not be suggested for this package.

Applied to files:

  • packages/lynx/gesture-runtime/vitest.config.ts
  • eslint.config.js
  • tsconfig.json
📚 Learning: 2025-08-11T05:57:18.212Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/testing-library/testing-environment/src/index.ts:255-258
Timestamp: 2025-08-11T05:57:18.212Z
Learning: In the ReactLynx testing environment (`packages/testing-library/testing-environment/src/index.ts`), the dual assignment pattern `target.console.method = console.method = () => {}` is required for rstest compatibility. This is because rstest provides `console` in an IIFE (Immediately Invoked Function Expression), and both the target and global console need to have these methods defined for proper test execution.

Applied to files:

  • packages/lynx/gesture-runtime/vitest.config.ts
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • eslint.config.js
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • packages/lynx/gesture-runtime/vitest.config.ts
  • packages/lynx/gesture-runtime/package.json
  • tsconfig.json
📚 Learning: 2025-10-11T06:16:12.517Z
Learnt from: Sherry-hue
Repo: lynx-family/lynx-stack PR: 1820
File: packages/web-platform/web-tests/tests/react.spec.ts:834-856
Timestamp: 2025-10-11T06:16:12.517Z
Learning: In packages/web-platform/web-tests/tests/react.spec.ts, the tests `basic-bindmouse` and `basic-mts-bindtouchstart` are NOT duplicates despite having similar test structures. They test different event types: `basic-bindmouse` validates mouse events (mousedown, mouseup, mousemove) with mouse-specific properties (button, buttons, x, y, pageX, pageY, clientX, clientY), while `basic-mts-bindtouchstart` validates touch events (touchstart) with touch arrays (touches, targetTouches, changedTouches). The similar test structure is coincidental and follows testing conventions.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx
  • packages/lynx/gesture-runtime/__test__/gesture-clone.test.ts
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
📚 Learning: 2025-11-04T10:15:14.965Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1899
File: packages/react/runtime/__test__/snapshotPatch.test.jsx:725-749
Timestamp: 2025-11-04T10:15:14.965Z
Learning: In packages/react/runtime/src/snapshot.ts, the snapshotCreatorMap type signature uses `Record<string, (uniqId: string) => string>` (returning string) rather than void for backward compatibility. Old lazy bundles still use the pattern `const snapshot_xxx = createSnapshot(...)` directly, which requires createSnapshot to return a value. The snapshotCreatorMap creators that wrap createSnapshot calls must maintain the same return type to support these legacy bundles.

Applied to files:

  • packages/lynx/gesture-runtime/src/utils/removeUndefined.ts
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • packages/lynx/gesture-runtime/package.json
  • tsconfig.json
📚 Learning: 2025-11-06T01:19:23.670Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1917
File: packages/mcp-servers/devtool-mcp-server/tsconfig.json:8-8
Timestamp: 2025-11-06T01:19:23.670Z
Learning: The lynx-js/devtool-mcp-server package in lynx-family/lynx-stack targets Node.js >=18.19 (specified in its package.json engines), which is different from the root project's requirement of Node.js ^22 || ^24. The package uses "lib": ["ES2024.Promise"] in its tsconfig.json because it manually includes polyfills for Promise.withResolvers while maintaining compatibility with Node.js v18.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
  • tsconfig.json
📚 Learning: 2025-08-21T08:46:54.494Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
  • packages/lynx/gesture-runtime/README.md
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-19T12:49:05.875Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/template-webpack-plugin/src/LynxCacheEventsSetupListRuntimeModule.ts:21-25
Timestamp: 2025-08-19T12:49:05.875Z
Learning: In the Lynx cache events system, there are two separate runtime modules with distinct responsibilities: `LynxCacheEventsSetupListRuntimeModule` is only responsible for initializing the setup list with the setup functions, while `LynxCacheEventsRuntimeModule` guarantees the initialization of `loaded` and `cachedActions` properties. The modules have a dependency relationship where `lynxCacheEventsSetupList` is required by `lynxCacheEvents`.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-14T12:54:51.143Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: .changeset/brave-melons-add.md:1-7
Timestamp: 2025-08-14T12:54:51.143Z
Learning: In the lynx-family/lynx-stack repository, packages use 0.x.x versioning where minor version bumps indicate breaking changes (not major bumps), following pre-1.0 semantic versioning conventions.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-12T16:09:32.413Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
  • packages/lynx/gesture-runtime/README.md
📚 Learning: 2025-09-28T08:46:43.177Z
Learnt from: f0rdream
Repo: lynx-family/lynx-stack PR: 1835
File: packages/react/worklet-runtime/src/workletRuntime.ts:52-55
Timestamp: 2025-09-28T08:46:43.177Z
Learning: The legacy worklet path with `_lepusWorkletHash` in `packages/react/worklet-runtime/src/workletRuntime.ts` is preserved for compatibility with MTS (Mini-app Threading Service) that doesn't support Initial Frame Rendering. This path will not be touched in current implementations.

Applied to files:

  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts
🧬 Code graph analysis (6)
packages/lynx/gesture-runtime/__test__/gesture-clone.test.ts (2)
packages/lynx/gesture-runtime/src/index.ts (5)
  • PanGesture (43-43)
  • TapGesture (44-44)
  • LongPressGesture (45-45)
  • DefaultScrollGesture (41-41)
  • FlingGesture (42-42)
packages/lynx/gesture-runtime/src/defaultScrollGesture.ts (1)
  • DefaultScrollGesture (11-24)
packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (8)
packages/lynx/gesture-runtime/src/index.ts (6)
  • PanGesture (43-43)
  • FlingGesture (42-42)
  • TapGesture (44-44)
  • LongPressGesture (45-45)
  • DefaultScrollGesture (41-41)
  • useGesture (48-48)
packages/lynx/gesture-runtime/src/panGesture.ts (1)
  • PanGesture (49-49)
packages/lynx/gesture-runtime/src/flingGesture.ts (1)
  • FlingGesture (22-22)
packages/lynx/gesture-runtime/src/tapGesture.ts (1)
  • TapGesture (33-33)
packages/lynx/gesture-runtime/src/longPressGesture.ts (1)
  • LongPressGesture (31-31)
packages/lynx/gesture-runtime/src/defaultScrollGesture.ts (1)
  • DefaultScrollGesture (11-24)
packages/lynx/gesture-runtime/src/useGesture.ts (1)
  • useGesture (36-36)
packages/react/testing-library/types/entry.d.ts (1)
  • act (15-15)
packages/lynx/gesture-runtime/src/flingGesture.ts (2)
packages/lynx/gesture-runtime/src/baseGesture.ts (1)
  • ContinuousGesture (304-304)
packages/lynx/gesture-runtime/src/gestureInterface.ts (2)
  • FlingGestureConfig (248-253)
  • FlingGestureChangeEvent (70-79)
packages/lynx/gesture-runtime/src/defaultScrollGesture.ts (3)
packages/lynx/gesture-runtime/src/index.ts (1)
  • DefaultScrollGesture (41-41)
packages/lynx/gesture-runtime/src/baseGesture.ts (1)
  • ContinuousGesture (304-304)
packages/lynx/gesture-runtime/src/gestureInterface.ts (2)
  • DefaultGestureConfig (259-262)
  • DefaultGestureChangeEvent (85-94)
packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts (1)
packages/react/worklet-runtime/src/bindings/types.ts (1)
  • Worklet (41-52)
packages/lynx/gesture-runtime/src/gestureInterface.ts (2)
packages/lynx/gesture-runtime/src/baseGesture.ts (1)
  • BaseGesture (304-304)
packages/lynx/gesture-runtime/src/index.ts (1)
  • BaseGesture (37-37)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: test-rust / Test (Ubuntu)
🔇 Additional comments (20)
tsconfig.json (1)

127-130: LGTM! Project reference correctly added.

The new project reference for ./packages/lynx is properly positioned and enables TypeScript composite build support for the gesture-runtime package.

packages/lynx/gesture-runtime/vitest.config.ts (1)

1-17: LGTM! Vitest configuration properly structured.

The test configuration follows the standard pattern used across the Lynx stack, with appropriate setup files, coverage includes, and test file matching patterns.

packages/lynx/gesture-runtime/src/utils/removeUndefined.ts (1)

4-10: LGTM! Clean utility implementation.

The function correctly filters out undefined values using a straightforward approach with Object.entries and Object.fromEntries.

packages/lynx/gesture-runtime/package.json (2)

3-3: Verify version 2.0.0 for a new package.

Starting a new package at version 2.0.0 is unconventional. Typically new packages start at 0.1.0 or 1.0.0. Please confirm this is intentional, perhaps for alignment with other Lynx packages.


6-6: Verify sideEffects: true is necessary.

Setting sideEffects: true disables tree-shaking optimizations. This is appropriate if the package has side effects during module initialization (e.g., global registrations, polyfills), but should be avoided otherwise for better bundle sizes.

Please verify that this package genuinely requires side effects, or consider setting this to false or an array of specific files with side effects.

packages/lynx/gesture-runtime/src/defaultScrollGesture.ts (1)

11-24: LGTM! DefaultScrollGesture properly implements the gesture pattern.

The class correctly extends ContinuousGesture, initializes configuration with sensible defaults, and provides a fluent API method for updating the tapSlop configuration.

packages/lynx/gesture-runtime/src/gestureInterface.ts (1)

1-302: Comprehensive type definitions for the gesture system.

The file provides a well-structured type system covering gesture events, configurations, callbacks, and state management. The interfaces are appropriately generic and extensible.

Note: A typo in the interface name at line 110 (ConsumeGesturePrams) has already been flagged in a previous review.

packages/lynx/gesture-runtime/README.md (1)

1-25: LGTM! Clear and concise documentation.

The README provides a good starting point for users with installation instructions and a basic usage example. The reference to dedicated documentation is appropriate for comprehensive API details.

eslint.config.js (1)

100-102: LGTM! Consistent with existing ignore patterns.

The new ignore pattern for gesture-runtime tests follows the established convention for excluding test directories from linting.

packages/lynx/gesture-runtime/__test__/gesture-clone.test.ts (6)

19-65: LGTM! Comprehensive configuration cloning tests.

The tests thoroughly validate that configuration values and identity fields (id, execId) are preserved across different gesture types during cloning.


67-108: LGTM! Thorough callback cloning validation.

The tests verify that all callback types are properly preserved during cloning, including the full spectrum of lifecycle and touch event callbacks.


110-162: LGTM! Complete relationship cloning coverage.

The tests validate that all relationship types (simultaneousWith, waitFor, continueWith) are properly preserved during cloning, both individually and in combination.


164-203: LGTM! Identity preservation thoroughly validated.

The tests ensure that cloned gestures maintain their identity (id, execId, type) and constructor relationships across all gesture types.


233-249: LGTM! Special properties properly tested.

The tests verify that internal markers and flags (distanceSet, __isGesture) are correctly preserved during cloning.


206-219: Verify shallow copy behavior is intentional.

The test confirms that cloned gestures share the same config object (shallow copy), meaning modifications to one affect both. This could lead to unexpected behavior if users modify a cloned gesture's config.

Is this shallow copy behavior intentional? Consider whether config objects should be deep-copied during cloning to prevent unintended mutations between original and cloned instances.

#!/bin/bash
# Search for clone() implementation and related documentation
ast-grep --pattern $'clone() {
  $$$
}'

# Search for any comments or docs about clone behavior
rg -n -C3 "clone.*shallow|shallow.*clone|config.*copy" --type=ts
packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx (1)

14-191: LGTM! Comprehensive edge case coverage.

The test suite thoroughly validates gesture composition, relationship handling, serialization, and various edge cases including empty arrays, single gestures, and nested compositions. The tests effectively document expected behavior of the composition system.

packages/lynx/gesture-runtime/src/index.ts (1)

20-48: LGTM! Clean factory API design.

The GestureEntry factory provides a clean, intuitive API for creating composed gestures. The aliasing to Gesture enables clean usage like Gesture.Simultaneous(...), and the re-exports provide comprehensive access to all gesture types and utilities.

packages/lynx/gesture-runtime/src/panGesture.ts (1)

28-37: Review undefined handling in minDistance.

The current logic updates the config with undefined when distance === undefined, which may not be the intended behavior. Consider whether this should instead skip the update or use a default value.

minDistance = (distance: number): this => {
  if (distance === undefined) {
    this.distanceSet = false;
  } else {
    this.distanceSet = true;
  }
  return this.updateConfig('minDistance', distance); // <-- passes undefined to config
};

Verify if passing undefined to updateConfig is intentional. Consider returning early when distance is undefined, or using a default value.

packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (2)

33-94: LGTM! Solid gesture creation and configuration tests.

The tests validate core functionality including type checking, configuration, callbacks, and cloning. The test for non-main-thread callbacks appropriately verifies the safety constraint.


96-156: LGTM! useGesture hook properly tested.

The tests verify that the hook correctly instantiates gesture types and creates new instances when component state changes, ensuring proper React integration.

Comment thread .changeset/olive-bugs-prove.md Outdated
Comment thread packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts Outdated
@f0rdream f0rdream force-pushed the gesture-runtime branch 2 times, most recently from 6189f8a to ada93b5 Compare December 5, 2025 08:48
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (7)
packages/lynx/gesture-runtime/src/tapGesture.ts (1)

10-18: Consider using a tap-specific constant for maxDuration.

The TapGesture uses DEFAULT_LONGPRESS_DURATION for its maxDuration default. While this may work correctly, it's semantically confusing since:

  • Tap's maxDuration = maximum time allowed for a tap
  • LongPress's minDuration = minimum time required for a long press

Consider introducing a DEFAULT_TAP_DURATION constant for clarity, or verify this is intentionally shared.

packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (3)

27-27: Unused import: DEFAULT_DISTANCE.

DEFAULT_DISTANCE is imported but never used in this test file.

-import { DEFAULT_DISTANCE } from '../src/utils/const.js';

124-155: Misleading variable name: prevPanExecId stores a gesture object, not an ID.

The variable prevPanExecId at line 148 stores the entire gesture object (_panGesture), not an execution ID. Consider renaming for clarity.

-    let prevPanExecId = 0;
+    let prevPanGesture: typeof _panGesture;
     ...
-    prevPanExecId = _panGesture;
+    prevPanGesture = _panGesture;
     ...
-    expect(_panGesture).not.toBe(prevPanExecId);
+    expect(_panGesture).not.toBe(prevPanGesture);

226-278: Duplicate test cases detected.

The tests "bind gestures should call __SetGestureDetector with relationsConfig" (lines 226-278) and "Old ReactLynx would call __SetGestureDetector correctly" (lines 295-347) have identical implementations and assertions. Consider consolidating or differentiating them to test distinct scenarios.

Also applies to: 295-347

packages/lynx/gesture-runtime/src/baseGesture.ts (1)

266-272: clone() has redundant property copying.

The clone() method calls the constructor with this (which copies all properties in lines 129-136), then immediately calls Object.assign(cloned, this) which copies the same properties again. The Object.assign appears redundant.

 clone = (): this => {
   // Create new instance
   const cloned = new (this.constructor as new(gesture?: this) => this)(this);
-  Object.assign(cloned, this);
-
   return cloned;
 };
packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx (2)

36-48: Misleading variable name: fling is a PanGesture.

At line 39, the variable fling is assigned a PanGesture instance, which is confusing since FlingGesture is a separate class. Consider renaming to pan3 or similar.

-    const fling = new PanGesture();
+    const pan3 = new PanGesture();
     ...
-    composed.prepareSingleGesture(fling, [pan, tap], []);
-    expect(fling.simultaneousWith).toContain(pan);
-    expect(fling.simultaneousWith).toContain(tap);
+    composed.prepareSingleGesture(pan3, [pan, tap], []);
+    expect(pan3.simultaneousWith).toContain(pan);
+    expect(pan3.simultaneousWith).toContain(tap);

101-113: Unused variable: longPress.

The longPress variable at line 104 is declared but never used in this test.

   test('should serialize composed gesture with all fields', () => {
     const pan = new PanGesture();
     const tap = new TapGesture();
-    const longPress = new LongPressGesture();

     const composed = Gesture.Simultaneous(pan, tap);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ee8885 and ada93b5.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (37)
  • .changeset/olive-bugs-prove.md (1 hunks)
  • biome.jsonc (1 hunks)
  • eslint.config.js (1 hunks)
  • packages/lynx/gesture-runtime/README.md (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-callback.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-clone.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-composition-advanced.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-config.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-plain.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/type-safety.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/utils/callback.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/utils/setup.ts (1 hunks)
  • packages/lynx/gesture-runtime/package.json (1 hunks)
  • packages/lynx/gesture-runtime/rslib.config.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/baseGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/composition.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/defaultScrollGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/env_types/global.d.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/flingGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/gestureInterface.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/index.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/longPressGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/panGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/tapGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/useGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/utils/const.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/utils/removeUndefined.ts (1 hunks)
  • packages/lynx/gesture-runtime/tsconfig.build.json (1 hunks)
  • packages/lynx/gesture-runtime/tsconfig.json (1 hunks)
  • packages/lynx/gesture-runtime/tsconfig.test.json (1 hunks)
  • packages/lynx/gesture-runtime/vitest.config.ts (1 hunks)
  • packages/lynx/tsconfig.json (1 hunks)
  • tsconfig.json (1 hunks)
✅ Files skipped from review due to trivial changes (4)
  • packages/lynx/gesture-runtime/test/gesture-config.test.ts
  • packages/lynx/gesture-runtime/package.json
  • packages/lynx/gesture-runtime/test/type-safety.test.ts
  • packages/lynx/gesture-runtime/src/utils/const.ts
🚧 Files skipped from review as they are similar to previous changes (25)
  • packages/lynx/gesture-runtime/tsconfig.test.json
  • packages/lynx/gesture-runtime/src/useGesture.ts
  • .changeset/olive-bugs-prove.md
  • packages/lynx/gesture-runtime/test/gesture-callback.test.tsx
  • packages/lynx/gesture-runtime/src/panGesture.ts
  • packages/lynx/gesture-runtime/src/utils/removeUndefined.ts
  • packages/lynx/tsconfig.json
  • packages/lynx/gesture-runtime/test/utils/callback.ts
  • packages/lynx/gesture-runtime/src/env_types/global.d.ts
  • packages/lynx/gesture-runtime/src/longPressGesture.ts
  • packages/lynx/gesture-runtime/test/gesture-composition-advanced.test.ts
  • packages/lynx/gesture-runtime/test/gesture-plain.test.ts
  • packages/lynx/gesture-runtime/test/is-worklet-object.test.ts
  • packages/lynx/gesture-runtime/src/index.ts
  • eslint.config.js
  • packages/lynx/gesture-runtime/src/flingGesture.ts
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • packages/lynx/gesture-runtime/README.md
  • biome.jsonc
  • packages/lynx/gesture-runtime/src/defaultScrollGesture.ts
  • packages/lynx/gesture-runtime/test/utils/setup.ts
  • tsconfig.json
  • packages/lynx/gesture-runtime/test/gesture-clone.test.ts
  • packages/lynx/gesture-runtime/rslib.config.ts
  • packages/lynx/gesture-runtime/tsconfig.json
🧰 Additional context used
🧠 Learnings (14)
📓 Common learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.
📚 Learning: 2025-10-11T06:16:12.517Z
Learnt from: Sherry-hue
Repo: lynx-family/lynx-stack PR: 1820
File: packages/web-platform/web-tests/tests/react.spec.ts:834-856
Timestamp: 2025-10-11T06:16:12.517Z
Learning: In packages/web-platform/web-tests/tests/react.spec.ts, the tests `basic-bindmouse` and `basic-mts-bindtouchstart` are NOT duplicates despite having similar test structures. They test different event types: `basic-bindmouse` validates mouse events (mousedown, mouseup, mousemove) with mouse-specific properties (button, buttons, x, y, pageX, pageY, clientX, clientY), while `basic-mts-bindtouchstart` validates touch events (touchstart) with touch arrays (touches, targetTouches, changedTouches). The similar test structure is coincidental and follows testing conventions.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • packages/lynx/gesture-runtime/vitest.config.ts
📚 Learning: 2025-08-11T05:57:18.212Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/testing-library/testing-environment/src/index.ts:255-258
Timestamp: 2025-08-11T05:57:18.212Z
Learning: In the ReactLynx testing environment (`packages/testing-library/testing-environment/src/index.ts`), the dual assignment pattern `target.console.method = console.method = () => {}` is required for rstest compatibility. This is because rstest provides `console` in an IIFE (Immediately Invoked Function Expression), and both the target and global console need to have these methods defined for proper test execution.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • packages/lynx/gesture-runtime/vitest.config.ts
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • packages/lynx/gesture-runtime/vitest.config.ts
📚 Learning: 2025-10-29T10:28:27.519Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1899
File: packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/lib.rs/should_static_extract_dynamic_inline_style.js:20-24
Timestamp: 2025-10-29T10:28:27.519Z
Learning: Files inside packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/ are auto-generated test snapshot files and should not be manually updated. Any issues with the generated code should be addressed in the code generator/transform logic, not in the snapshots themselves.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx
📚 Learning: 2025-11-11T08:05:14.163Z
Learnt from: Sherry-hue
Repo: lynx-family/lynx-stack PR: 1932
File: packages/web-platform/web-tests/tests/react/basic-element-x-input-ng-bindinput/index.jsx:10-26
Timestamp: 2025-11-11T08:05:14.163Z
Learning: In packages/web-platform/web-tests/tests/react/basic-element-x-input-ng-bindinput/index.jsx, the test intentionally uses selectionStart twice in the result string (instead of selectionStart and selectionEnd) because it prioritizes testing whether x-input-ng works functionally, rather than validating the correctness of selection values.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
📚 Learning: 2025-08-13T09:20:00.936Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1502
File: packages/react/testing-library/types/entry.d.ts:71-71
Timestamp: 2025-08-13T09:20:00.936Z
Learning: In lynx-js/react testing library, wrapper components must have children as a required prop because they are always called with `h(WrapperComponent, null, innerElement)` where innerElement is passed as children. The type `React.JSXElementConstructor<{ children: React.ReactNode }>` correctly requires children to be mandatory.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
📚 Learning: 2025-08-11T05:59:28.530Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:4-6
Timestamp: 2025-08-11T05:59:28.530Z
Learning: In the lynx-family/lynx-stack repository, the `packages/react/testing-library` package does not have `vite` as a direct dependency. It relies on `vitest` being available from the monorepo root and accesses Vite types through re-exports from `vitest/node`. Direct imports from `vite` should not be suggested for this package.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • packages/lynx/gesture-runtime/vitest.config.ts
  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • packages/lynx/gesture-runtime/vitest.config.ts
  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts
📚 Learning: 2025-09-28T08:46:43.177Z
Learnt from: f0rdream
Repo: lynx-family/lynx-stack PR: 1835
File: packages/react/worklet-runtime/src/workletRuntime.ts:52-55
Timestamp: 2025-09-28T08:46:43.177Z
Learning: The legacy worklet path with `_lepusWorkletHash` in `packages/react/worklet-runtime/src/workletRuntime.ts` is preserved for compatibility with MTS (Mini-app Threading Service) that doesn't support Initial Frame Rendering. This path will not be touched in current implementations.

Applied to files:

  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts
📚 Learning: 2025-11-05T03:26:52.546Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1916
File: packages/react/transform/crates/swc_plugin_snapshot/lib.rs:9-9
Timestamp: 2025-11-05T03:26:52.546Z
Learning: In the lynx-stack repository's swc_core v47 upgrade (PR #1916), the import `use swc_core::atoms as swc_atoms;` is required in files that use the `quote!` macro (e.g., packages/react/transform/crates/swc_plugin_snapshot/lib.rs, swc_plugin_list/lib.rs, swc_plugin_worklet/gen_stmt.rs) even though swc_atoms may not appear explicitly in the source code. This is because the quote! macro generates code that internally references swc_atoms. Removing this import causes compiler error: "failed to resolve: use of unresolved module or unlinked crate `swc_atoms`".

Applied to files:

  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts
📚 Learning: 2025-08-21T08:46:54.494Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.

Applied to files:

  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts
🧬 Code graph analysis (1)
packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx (5)
packages/lynx/gesture-runtime/src/index.ts (4)
  • PanGesture (43-43)
  • TapGesture (44-44)
  • LongPressGesture (45-45)
  • ComposedGesture (39-39)
packages/lynx/gesture-runtime/src/panGesture.ts (1)
  • PanGesture (49-49)
packages/lynx/gesture-runtime/src/tapGesture.ts (1)
  • TapGesture (33-33)
packages/lynx/gesture-runtime/src/longPressGesture.ts (1)
  • LongPressGesture (31-31)
packages/lynx/gesture-runtime/src/composition.ts (1)
  • ComposedGesture (170-170)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: test-rust / Test (Ubuntu)
🔇 Additional comments (13)
packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts (1)

5-14: LGTM - Worklet detection logic is correct.

The function correctly handles:

  1. Main thread context (always returns true)
  2. Falsy values (returns false)
  3. Object check with _wkltId property detection

Note: The past review comment about missing Worklet type import is not applicable here since the function returns boolean rather than using a type guard (obj is Worklet).

packages/lynx/gesture-runtime/src/gestureInterface.ts (2)

1-302: Well-structured type declarations for the gesture system.

The comprehensive type surface covers:

  • Gesture event types with proper inheritance
  • Configuration interfaces for each gesture type
  • Callback types with generics
  • State management interfaces
  • Module augmentation for @lynx-js/types

The empty interface extensions (e.g., TapGestureChangeEvent, NativeGestureChangeEvent) are appropriate for type discrimination and future extensibility.


136-151: FiberElement type is used but not imported.

The InternalStateManager interface references FiberElement at lines 142 and 147, but this type is not imported. This will cause a TypeScript compilation error unless FiberElement is declared globally.

packages/lynx/gesture-runtime/src/tapGesture.ts (1)

20-31: Fluent API implementation is correct.

The configuration methods properly delegate to updateConfig and return this for chaining. The pattern is consistent with other gesture classes in the package.

packages/lynx/gesture-runtime/vitest.config.ts (1)

1-17: LGTM - Standard Vitest configuration.

The configuration properly:

  • Inherits from the shared testing library config
  • Sets up appropriate test file patterns and exclusions
  • Configures coverage for the src/ directory
  • Uses the test setup file for environment preparation
packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (1)

33-94: Good test coverage for gesture creation.

The tests thoroughly cover:

  • Gesture type verification
  • Configuration methods
  • Callback validation (main thread requirement)
  • Clone equality
packages/lynx/gesture-runtime/src/baseGesture.ts (3)

25-110: Well-designed callback wrapping with StateManager.

The wrapCallback function properly:

  • Validates that callbacks are worklet objects (main-thread functions)
  • Creates a StateManager instance inside the worklet scope for accessibility
  • Provides a clean API for gesture state control (active/fail/end, consume/intercept)

The inline class declaration inside the worklet is intentional for main-thread accessibility.


112-191: BaseGesture class structure is well-designed.

The abstract class provides:

  • Unique ID generation per instance
  • Configuration management with updateConfig
  • Callback management with main-thread validation
  • Fluent API for all lifecycle hooks
  • Proper cloning via constructor

192-237: Relationship methods correctly handle composed gestures.

The concat() bugs from previous reviews have been properly fixed - all three methods (externalWaitFor, externalSimultaneous, externalContinueWith) now correctly assign the concatenated result back to the array.

packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx (1)

14-191: Comprehensive test coverage for gesture composition.

The test suite thoroughly covers:

  • Relation extension and propagation
  • prepareSingleGesture for both BaseGesture and ComposedGesture
  • Serialization and JSON conversion
  • Nested composition flattening
  • Edge cases (empty arrays, single gestures)
  • All composition types (Simultaneous, Exclusive, Race)
packages/lynx/gesture-runtime/src/composition.ts (3)

115-142: SimultaneousGesture correctly excludes self from simultaneous lists.

The implementation properly creates per-gesture simultaneous lists that exclude the gesture itself, preventing gestures from being made simultaneous with themselves. This is particularly important for nested ExclusiveGesture compositions.


144-166: ExclusiveGesture correctly chains waitFor relations.

The implementation properly accumulates requireToFail as it iterates, ensuring each group waits for all preceding groups. This creates the exclusive priority ordering.


68-96: processPanDistance logic is correct and idempotent.

The method:

  • Guards against multiple executions via panProcessed flag
  • Correctly detects TAP/LONGPRESS presence
  • Overrides Pan gesture minDistance when needed

This handles the edge case where pan gestures need adjusted sensitivity when composed with tap-like gestures.

Comment thread packages/lynx/gesture-runtime/src/composition.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
packages/lynx/gesture-runtime/__test__/utils/callback.ts (1)

22-45: Guard against missing gesture.config in getCallback.

The past review comment on this code segment remains valid. triggerGestureCallback passes node?.gesture?.config into getCallback, but getCallback assumes config is always defined. If node (or gesture/config) is undefined, this will throw a TypeError instead of the explicit "No gesture callback for ${method}" error.

Apply the suggested fix from the previous review:

-function getCallback(config: GestureConfig, method: string) {
-  if (config.callbacks) {
-    return config.callbacks.find((callback) => callback.name === method);
-  } else {
-    return undefined;
-  }
-}
+function getCallback(
+  config: GestureConfig | undefined,
+  method: string,
+) {
+  if (!config?.callbacks) {
+    return undefined;
+  }
+  return config.callbacks.find((callback) => callback.name === method);
+}
packages/lynx/gesture-runtime/src/composition.ts (1)

41-57: Asymmetric relation handling between BaseGesture and ComposedGesture.

The past review comment remains valid. For BaseGesture, relations are merged using extendRelation, but for ComposedGesture, they are directly replaced. This means a ComposedGesture with pre-existing relations will lose them when nested in another composition.

Apply the suggested fix to use extendRelation for both paths:

     } else if (gesture instanceof ComposedGesture) {
-      gesture.simultaneousWith = simultaneousGestures;
-      gesture.waitFor = waitFor;
+      gesture.simultaneousWith = extendRelation(gesture.simultaneousWith, simultaneousGestures);
+      gesture.waitFor = extendRelation(gesture.waitFor, waitFor);
       gesture.prepare();
     }
🧹 Nitpick comments (8)
packages/lynx/gesture-runtime/src/useGesture.ts (1)

21-34: Consider lazy initialization to avoid creating instances on every render.

useRef(new GestureConstructor()) evaluates the constructor on every render, even though useRef only uses the initial value once. For performance, consider lazy initialization:

 function useGesture<T extends IBasicGestures>(
   GestureConstructor: new() => T,
 ): T {
-  const gestureRef = useRef<T>(new GestureConstructor());
+  const gestureRef = useRef<T | null>(null);
+  if (gestureRef.current === null) {
+    gestureRef.current = new GestureConstructor();
+  }
   const lastExecIdRef = useRef(gestureRef.current.execId);
 
   if (lastExecIdRef.current !== gestureRef.current.execId) {
     lastExecIdRef.current = gestureRef.current.execId;
     const cloned = gestureRef.current.clone() as T;
     gestureRef.current = cloned;
   }
 
   return gestureRef.current;
 }
packages/lynx/gesture-runtime/package.json (1)

34-37: Consider adding version constraints to peer dependencies.

Using "*" for peer dependencies is very permissive and may lead to compatibility issues with incompatible versions. Consider specifying minimum version constraints (e.g., ">=2.0.0" or "^2.0.0") to ensure consumers use compatible versions.

packages/lynx/gesture-runtime/src/baseGesture.ts (2)

266-272: Redundant copying in clone() method.

The constructor already copies all relevant properties when a gesture is passed. The subsequent Object.assign(cloned, this) duplicates this work. Consider removing the redundant assignment:

   clone = (): this => {
     // Create new instance
     const cloned = new (this.constructor as new(gesture?: this) => this)(this);
-    Object.assign(cloned, this);
-
     return cloned;
   };

Alternatively, if Object.assign is needed for properties not handled by the constructor, document which ones.


283-295: Code duplication in updateCallback override.

This override is identical to the parent BaseGesture.updateCallback (lines 149-161). The override exists for TypeScript to handle the extended callback keys, but the runtime logic is duplicated. Consider extracting the common logic or using a protected helper method to reduce duplication.

packages/lynx/gesture-runtime/src/env_types/global.d.ts (1)

18-20: Consider more specific types for runWorklet parameters.

The unknown types for both worklet and data parameters are safe but could benefit from more descriptive types if the expected shapes are known. This would improve developer experience and catch type errors at compile time.

 declare global {
-  var runWorklet: (worklet: unknown, data: unknown) => void;
+  var runWorklet: (worklet: { _wkltId: string; _c?: object }, data: Record<string, unknown>) => void;
 }
packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts (1)

9-22: Use try/finally to ensure __MAIN_THREAD__ is restored on test failure.

If the assertion fails, __MAIN_THREAD__ won't be restored, potentially affecting subsequent tests.

   test('should return true in MAIN THREAD mode', () => {
     // @ts-expect-error Testing MAIN THREAD mode
     // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
     const original = globalThis.__MAIN_THREAD__;
     // @ts-expect-error Testing MAIN THREAD mode
     globalThis.__MAIN_THREAD__ = true;
 
-    const result = isWorkletObj({});
-
-    // @ts-expect-error Restore
-    globalThis.__MAIN_THREAD__ = original;
-
-    expect(result).toBe(true);
+    try {
+      const result = isWorkletObj({});
+      expect(result).toBe(true);
+    } finally {
+      // @ts-expect-error Restore
+      globalThis.__MAIN_THREAD__ = original;
+    }
   });
packages/lynx/gesture-runtime/__test__/gesture-plain.test.ts (2)

4-4: Remove unused afterEach import.

afterEach is imported but not used in this test file.

-import { afterEach, describe, expect, test } from 'vitest';
+import { describe, expect, test } from 'vitest';

68-70: Misleading variable name: panGesture is a TapGesture.

The variable is named panGesture but instantiated as TapGesture, which could confuse readers.

   test('gesture callbacks should have callbacks set', () => {
-    const panGesture = new TapGesture();
+    const tapGesture = new TapGesture();
     // @ts-expect-error Expected
-    panGesture.onBegin(MainThreadFunction);
+    tapGesture.onBegin(MainThreadFunction);
     // @ts-expect-error Expected
-    panGesture.onEnd(MainThreadFunction);
+    tapGesture.onEnd(MainThreadFunction);
     // ... (update remaining references)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ada93b5 and 2e857df.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (37)
  • .changeset/olive-bugs-prove.md (1 hunks)
  • biome.jsonc (1 hunks)
  • eslint.config.js (1 hunks)
  • packages/lynx/gesture-runtime/README.md (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-callback.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-clone.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-composition-advanced.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-config.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-plain.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-relations.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/type-safety.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/utils/callback.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/utils/setup.ts (1 hunks)
  • packages/lynx/gesture-runtime/package.json (1 hunks)
  • packages/lynx/gesture-runtime/rslib.config.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/baseGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/composition.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/defaultScrollGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/env_types/global.d.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/flingGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/gestureInterface.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/index.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/longPressGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/panGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/tapGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/useGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/utils/const.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts (1 hunks)
  • packages/lynx/gesture-runtime/src/utils/removeUndefined.ts (1 hunks)
  • packages/lynx/gesture-runtime/tsconfig.build.json (1 hunks)
  • packages/lynx/gesture-runtime/tsconfig.json (1 hunks)
  • packages/lynx/gesture-runtime/tsconfig.test.json (1 hunks)
  • packages/lynx/gesture-runtime/vitest.config.ts (1 hunks)
  • packages/lynx/tsconfig.json (1 hunks)
  • tsconfig.json (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • packages/lynx/gesture-runtime/tsconfig.json
  • packages/lynx/gesture-runtime/test/gesture-config.test.ts
  • packages/lynx/gesture-runtime/test/utils/setup.ts
🚧 Files skipped from review as they are similar to previous changes (19)
  • packages/lynx/gesture-runtime/src/tapGesture.ts
  • packages/lynx/gesture-runtime/vitest.config.ts
  • packages/lynx/gesture-runtime/test/gesture-composition-advanced.test.ts
  • packages/lynx/gesture-runtime/test/gesture-callback.test.tsx
  • packages/lynx/gesture-runtime/src/utils/const.ts
  • packages/lynx/gesture-runtime/test/gesture-relations.test.tsx
  • packages/lynx/gesture-runtime/src/longPressGesture.ts
  • packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts
  • packages/lynx/tsconfig.json
  • packages/lynx/gesture-runtime/test/gesture-clone.test.ts
  • packages/lynx/gesture-runtime/src/panGesture.ts
  • packages/lynx/gesture-runtime/test/type-safety.test.ts
  • packages/lynx/gesture-runtime/src/flingGesture.ts
  • packages/lynx/gesture-runtime/rslib.config.ts
  • .changeset/olive-bugs-prove.md
  • packages/lynx/gesture-runtime/src/defaultScrollGesture.ts
  • packages/lynx/gesture-runtime/tsconfig.test.json
  • packages/lynx/gesture-runtime/src/utils/removeUndefined.ts
  • tsconfig.json
🧰 Additional context used
🧠 Learnings (23)
📓 Common learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1917
File: packages/mcp-servers/devtool-mcp-server/tsconfig.json:8-8
Timestamp: 2025-11-06T01:19:23.670Z
Learning: The lynx-js/devtool-mcp-server package in lynx-family/lynx-stack targets Node.js >=18.19 (specified in its package.json engines), which is different from the root project's requirement of Node.js ^22 || ^24. The package uses "lib": ["ES2024.Promise"] in its tsconfig.json because it manually includes polyfills for Promise.withResolvers while maintaining compatibility with Node.js v18.
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:4-6
Timestamp: 2025-08-11T05:59:28.530Z
Learning: In the lynx-family/lynx-stack repository, the `packages/react/testing-library` package does not have `vite` as a direct dependency. It relies on `vitest` being available from the monorepo root and accesses Vite types through re-exports from `vitest/node`. Direct imports from `vite` should not be suggested for this package.
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • packages/lynx/gesture-runtime/README.md
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • eslint.config.js
  • biome.jsonc
  • packages/lynx/gesture-runtime/package.json
  • packages/lynx/gesture-runtime/src/gestureInterface.ts
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • packages/lynx/gesture-runtime/README.md
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • eslint.config.js
  • biome.jsonc
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • packages/lynx/gesture-runtime/README.md
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • biome.jsonc
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-21T08:46:54.494Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.

Applied to files:

  • packages/lynx/gesture-runtime/README.md
  • packages/lynx/gesture-runtime/tsconfig.build.json
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-12T16:09:32.413Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.

Applied to files:

  • packages/lynx/gesture-runtime/README.md
  • packages/lynx/gesture-runtime/src/env_types/global.d.ts
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-11-06T01:19:23.670Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1917
File: packages/mcp-servers/devtool-mcp-server/tsconfig.json:8-8
Timestamp: 2025-11-06T01:19:23.670Z
Learning: The lynx-js/devtool-mcp-server package in lynx-family/lynx-stack targets Node.js >=18.19 (specified in its package.json engines), which is different from the root project's requirement of Node.js ^22 || ^24. The package uses "lib": ["ES2024.Promise"] in its tsconfig.json because it manually includes polyfills for Promise.withResolvers while maintaining compatibility with Node.js v18.

Applied to files:

  • packages/lynx/gesture-runtime/tsconfig.build.json
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/lynx/gesture-runtime/tsconfig.build.json
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • eslint.config.js
  • biome.jsonc
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/lynx/gesture-runtime/tsconfig.build.json
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • eslint.config.js
  • biome.jsonc
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Applied to files:

  • packages/lynx/gesture-runtime/tsconfig.build.json
  • eslint.config.js
  • biome.jsonc
📚 Learning: 2025-08-13T11:36:12.075Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:52-72
Timestamp: 2025-08-13T11:36:12.075Z
Learning: The lynx-stack project requires Node.js >=22 as specified in package.json engines, so Node.js compatibility fallbacks for features introduced before v22 are unnecessary.

Applied to files:

  • packages/lynx/gesture-runtime/tsconfig.build.json
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • packages/lynx/gesture-runtime/tsconfig.build.json
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • packages/lynx/gesture-runtime/tsconfig.build.json
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-11T05:59:28.530Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:4-6
Timestamp: 2025-08-11T05:59:28.530Z
Learning: In the lynx-family/lynx-stack repository, the `packages/react/testing-library` package does not have `vite` as a direct dependency. It relies on `vitest` being available from the monorepo root and accesses Vite types through re-exports from `vitest/node`. Direct imports from `vite` should not be suggested for this package.

Applied to files:

  • packages/lynx/gesture-runtime/tsconfig.build.json
  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts
  • eslint.config.js
  • biome.jsonc
📚 Learning: 2025-09-28T08:46:43.177Z
Learnt from: f0rdream
Repo: lynx-family/lynx-stack PR: 1835
File: packages/react/worklet-runtime/src/workletRuntime.ts:52-55
Timestamp: 2025-09-28T08:46:43.177Z
Learning: The legacy worklet path with `_lepusWorkletHash` in `packages/react/worklet-runtime/src/workletRuntime.ts` is preserved for compatibility with MTS (Mini-app Threading Service) that doesn't support Initial Frame Rendering. This path will not be touched in current implementations.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts
  • packages/lynx/gesture-runtime/src/env_types/global.d.ts
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts
  • biome.jsonc
📚 Learning: 2025-10-11T06:16:12.517Z
Learnt from: Sherry-hue
Repo: lynx-family/lynx-stack PR: 1820
File: packages/web-platform/web-tests/tests/react.spec.ts:834-856
Timestamp: 2025-10-11T06:16:12.517Z
Learning: In packages/web-platform/web-tests/tests/react.spec.ts, the tests `basic-bindmouse` and `basic-mts-bindtouchstart` are NOT duplicates despite having similar test structures. They test different event types: `basic-bindmouse` validates mouse events (mousedown, mouseup, mousemove) with mouse-specific properties (button, buttons, x, y, pageX, pageY, clientX, clientY), while `basic-mts-bindtouchstart` validates touch events (touchstart) with touch arrays (touches, targetTouches, changedTouches). The similar test structure is coincidental and follows testing conventions.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • packages/lynx/gesture-runtime/__test__/gesture-plain.test.ts
📚 Learning: 2025-08-11T05:57:18.212Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/testing-library/testing-environment/src/index.ts:255-258
Timestamp: 2025-08-11T05:57:18.212Z
Learning: In the ReactLynx testing environment (`packages/testing-library/testing-environment/src/index.ts`), the dual assignment pattern `target.console.method = console.method = () => {}` is required for rstest compatibility. This is because rstest provides `console` in an IIFE (Immediately Invoked Function Expression), and both the target and global console need to have these methods defined for proper test execution.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • eslint.config.js
  • biome.jsonc
📚 Learning: 2025-10-29T10:28:27.519Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1899
File: packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/lib.rs/should_static_extract_dynamic_inline_style.js:20-24
Timestamp: 2025-10-29T10:28:27.519Z
Learning: Files inside packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/ are auto-generated test snapshot files and should not be manually updated. Any issues with the generated code should be addressed in the code generator/transform logic, not in the snapshots themselves.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
📚 Learning: 2025-11-11T08:05:14.163Z
Learnt from: Sherry-hue
Repo: lynx-family/lynx-stack PR: 1932
File: packages/web-platform/web-tests/tests/react/basic-element-x-input-ng-bindinput/index.jsx:10-26
Timestamp: 2025-11-11T08:05:14.163Z
Learning: In packages/web-platform/web-tests/tests/react/basic-element-x-input-ng-bindinput/index.jsx, the test intentionally uses selectionStart twice in the result string (instead of selectionStart and selectionEnd) because it prioritizes testing whether x-input-ng works functionally, rather than validating the correctness of selection values.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
📚 Learning: 2025-08-11T06:00:04.376Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:59-61
Timestamp: 2025-08-11T06:00:04.376Z
Learning: In the lynx-family/lynx-stack repository, the `testingLibraryPlugin` in `packages/react/testing-library/src/plugins/vitest.ts` intentionally uses `process.exit` when jsdom installation fails, maintaining consistency with the previous implementation from `packages/react/testing-library/src/vitest.config.js`. This behavior should not be changed to use `this.error` despite being a Vite plugin best practice.

Applied to files:

  • biome.jsonc
📚 Learning: 2025-08-19T12:49:05.875Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/template-webpack-plugin/src/LynxCacheEventsSetupListRuntimeModule.ts:21-25
Timestamp: 2025-08-19T12:49:05.875Z
Learning: In the Lynx cache events system, there are two separate runtime modules with distinct responsibilities: `LynxCacheEventsSetupListRuntimeModule` is only responsible for initializing the setup list with the setup functions, while `LynxCacheEventsRuntimeModule` guarantees the initialization of `loaded` and `cachedActions` properties. The modules have a dependency relationship where `lynxCacheEventsSetupList` is required by `lynxCacheEvents`.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-14T12:54:51.143Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: .changeset/brave-melons-add.md:1-7
Timestamp: 2025-08-14T12:54:51.143Z
Learning: In the lynx-family/lynx-stack repository, packages use 0.x.x versioning where minor version bumps indicate breaking changes (not major bumps), following pre-1.0 semantic versioning conventions.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
🧬 Code graph analysis (7)
packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts (1)
packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts (1)
  • isWorkletObj (5-14)
packages/lynx/gesture-runtime/src/baseGesture.ts (4)
packages/lynx/gesture-runtime/src/gestureInterface.ts (8)
  • GestureChangeEvent (30-43)
  • InternalStateManager (136-151)
  • GestureCallback (177-182)
  • BaseGestureCallbacks (276-286)
  • ContinuousGestureCallbacks (292-296)
  • StateManager (153-159)
  • BaseGestureConfig (198-201)
  • GestureKind (16-24)
packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts (1)
  • isWorkletObj (5-14)
packages/lynx/gesture-runtime/src/index.ts (1)
  • BaseGesture (37-37)
packages/lynx/gesture-runtime/src/utils/removeUndefined.ts (1)
  • removeUndefined (4-10)
packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (7)
packages/lynx/gesture-runtime/src/index.ts (6)
  • PanGesture (43-43)
  • FlingGesture (42-42)
  • TapGesture (44-44)
  • LongPressGesture (45-45)
  • DefaultScrollGesture (41-41)
  • useGesture (48-48)
packages/lynx/gesture-runtime/src/panGesture.ts (1)
  • PanGesture (49-49)
packages/lynx/gesture-runtime/src/flingGesture.ts (1)
  • FlingGesture (22-22)
packages/lynx/gesture-runtime/src/tapGesture.ts (1)
  • TapGesture (33-33)
packages/lynx/gesture-runtime/src/longPressGesture.ts (1)
  • LongPressGesture (31-31)
packages/lynx/gesture-runtime/src/defaultScrollGesture.ts (1)
  • DefaultScrollGesture (11-24)
packages/lynx/gesture-runtime/src/useGesture.ts (1)
  • useGesture (36-36)
packages/lynx/gesture-runtime/src/useGesture.ts (5)
packages/lynx/gesture-runtime/src/index.ts (5)
  • PanGesture (43-43)
  • FlingGesture (42-42)
  • TapGesture (44-44)
  • LongPressGesture (45-45)
  • useGesture (48-48)
packages/lynx/gesture-runtime/src/panGesture.ts (1)
  • PanGesture (49-49)
packages/lynx/gesture-runtime/src/flingGesture.ts (1)
  • FlingGesture (22-22)
packages/lynx/gesture-runtime/src/tapGesture.ts (1)
  • TapGesture (33-33)
packages/lynx/gesture-runtime/src/longPressGesture.ts (1)
  • LongPressGesture (31-31)
packages/lynx/gesture-runtime/__test__/utils/callback.ts (2)
packages/lynx/gesture-runtime/src/gestureInterface.ts (1)
  • ConsumeGestureParams (110-113)
packages/react/runtime/src/gesture/types.ts (1)
  • GestureConfig (38-44)
packages/lynx/gesture-runtime/__test__/gesture-plain.test.ts (8)
packages/lynx/gesture-runtime/src/index.ts (6)
  • PanGesture (43-43)
  • FlingGesture (42-42)
  • TapGesture (44-44)
  • LongPressGesture (45-45)
  • DefaultScrollGesture (41-41)
  • ComposedGesture (39-39)
packages/lynx/gesture-runtime/src/panGesture.ts (1)
  • PanGesture (49-49)
packages/lynx/gesture-runtime/src/flingGesture.ts (1)
  • FlingGesture (22-22)
packages/lynx/gesture-runtime/src/tapGesture.ts (1)
  • TapGesture (33-33)
packages/lynx/gesture-runtime/src/longPressGesture.ts (1)
  • LongPressGesture (31-31)
packages/lynx/gesture-runtime/src/defaultScrollGesture.ts (1)
  • DefaultScrollGesture (11-24)
packages/lynx/gesture-runtime/src/composition.ts (1)
  • ComposedGesture (170-170)
packages/lynx/gesture-runtime/src/utils/const.ts (1)
  • DEFAULT_DISTANCE (4-4)
packages/lynx/gesture-runtime/src/index.ts (2)
packages/lynx/gesture-runtime/src/gestureInterface.ts (1)
  • GestureKind (16-24)
packages/lynx/gesture-runtime/src/composition.ts (3)
  • SimultaneousGesture (170-170)
  • RaceGesture (170-170)
  • ExclusiveGesture (170-170)
🔇 Additional comments (26)
packages/lynx/gesture-runtime/tsconfig.build.json (2)

6-9: Verify lib and module settings match package requirements.

The configuration specifies lib: ["es2021"] with target: ESNext, and uses module: "Node16" with moduleResolution: "Node16". Confirm that:

  1. The ES2021 lib version is intentional and aligns with the root tsconfig.json defaults and package's minimum supported ES version.
  2. The Node16 module/resolution strategy is appropriate if this package targets both Node.js and browser environments. If the package is browser-focused, consider alignment with the root config.

Based on learnings, check the root tsconfig.json to see if these settings diverge from project-wide conventions for lib targeting.


4-4: Verify whether noEmit: true is appropriate for this build configuration.

Setting noEmit: true in a file named tsconfig.build.json may prevent TypeScript from generating compiled output. Typically, build-specific TypeScript configs emit artifacts, while type-checking-only configs use this option. Confirm whether:

  • This config is intended to produce build artifacts
  • A separate TypeScript config handles emission
  • The build pipeline expects this configuration to emit files

If this config should emit output, change "noEmit": true to "noEmit": false.

biome.jsonc (1)

56-56: LGTM!

The ignore pattern for the gesture-runtime test directory follows the existing conventions for excluding test files from Biome linting.

packages/lynx/gesture-runtime/package.json (1)

3-3: Verify the initial version choice.

Starting a new package at version 2.0.0 is unusual. Based on learnings, this repository uses 0.x.x versioning where minor bumps indicate breaking changes. Consider whether this should start at 0.1.0 to align with the repository's versioning conventions, or if 2.0.0 is intentional to match a specific Lynx ecosystem version.

packages/lynx/gesture-runtime/src/baseGesture.ts (1)

192-237: Previous concat() issues have been addressed.

The relationship management methods (externalWaitFor, externalSimultaneous, externalContinueWith) now correctly assign the result of concat() back to the arrays, fixing the bugs identified in previous reviews.

packages/lynx/gesture-runtime/src/env_types/global.d.ts (1)

1-30: Ambient declarations look correct.

The FiberElement class is now properly declared, and the module augmentation for @lynx-js/types is correctly structured. The internal-only comment on line 22 clarifies the scope appropriately.

eslint.config.js (1)

100-102: Ignore pattern for gesture-runtime tests is consistent with existing conventions.

The new ignore pattern follows the same approach used for other testing-library directories. Consider adding a TODO comment similar to line 96-97 if the intention is to enable linting for these tests in the future.

packages/lynx/gesture-runtime/__test__/is-worklet-object.test.ts (2)

1-86: Good test coverage for isWorkletObj utility.

The tests comprehensively cover various input types including null, undefined, primitives, arrays, functions, and objects with/without _wkltId. The edge case for falsy _wkltId (empty string) is also tested.


24-30: Ensure __MAIN_THREAD__ is explicitly false for non-MAIN_THREAD tests.

The test assumes __MAIN_THREAD__ is falsy, but test execution order isn't guaranteed in vitest. Consider using beforeEach to explicitly set __MAIN_THREAD__ = false for all tests in this describe block, or wrap tests that depend on non-MAIN_THREAD behavior.

packages/lynx/gesture-runtime/__test__/gesture-plain.test.ts (1)

22-200: Comprehensive test coverage for gesture primitives and composition.

The tests thoroughly validate gesture type initialization, configuration setters, callback enforcement, cloning behavior, and composition mechanics (simultaneous, waitFor, continueWith). The self-exclusion test at lines 189-199 is a good edge case to include.

packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (4)

67-72: Verify the expected callback structure.

The assertion expects panGesture.callbacks.onUpdate to match an empty object {}. This seems inconsistent with the test in gesture-plain.test.ts (lines 83-106) which expects callbacks to have _c: {} and _wkltId. Verify this is the intended behavior when using the 'main thread' directive.


96-156: useGesture hook tests validate instance creation and updates.

The tests correctly verify that useGesture creates gesture instances and produces new instances when state changes. The async/await pattern with act is appropriate for testing React state updates.


226-278: Duplicate test: identical assertions to lines 172-224.

This test ("bind gestures should call __SetGestureDetector with relationsConfig") has the same test name pattern and identical assertions as the test at lines 172-224. Consider removing the duplicate or differentiating the test cases if they're meant to cover different scenarios.

If these tests are meant to be different, update the second test to actually test different relationsConfig values (e.g., with populated waitFor, simultaneous, or continueWith arrays).

⛔ Skipped due to learnings
Learnt from: Sherry-hue
Repo: lynx-family/lynx-stack PR: 1820
File: packages/web-platform/web-tests/tests/react.spec.ts:834-856
Timestamp: 2025-10-11T06:16:12.517Z
Learning: In packages/web-platform/web-tests/tests/react.spec.ts, the tests `basic-bindmouse` and `basic-mts-bindtouchstart` are NOT duplicates despite having similar test structures. They test different event types: `basic-bindmouse` validates mouse events (mousedown, mouseup, mousemove) with mouse-specific properties (button, buttons, x, y, pageX, pageY, clientX, clientY), while `basic-mts-bindtouchstart` validates touch events (touchstart) with touch arrays (touches, targetTouches, changedTouches). The similar test structure is coincidental and follows testing conventions.
Learnt from: Sherry-hue
Repo: lynx-family/lynx-stack PR: 1932
File: packages/web-platform/web-tests/tests/react/basic-element-x-input-ng-bindinput/index.jsx:10-26
Timestamp: 2025-11-11T08:05:14.163Z
Learning: In packages/web-platform/web-tests/tests/react/basic-element-x-input-ng-bindinput/index.jsx, the test intentionally uses selectionStart twice in the result string (instead of selectionStart and selectionEnd) because it prioritizes testing whether x-input-ng works functionally, rather than validating the correctness of selection values.
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/testing-library/testing-environment/src/index.ts:255-258
Timestamp: 2025-08-11T05:57:18.212Z
Learning: In the ReactLynx testing environment (`packages/testing-library/testing-environment/src/index.ts`), the dual assignment pattern `target.console.method = console.method = () => {}` is required for rstest compatibility. This is because rstest provides `console` in an IIFE (Immediately Invoked Function Expression), and both the target and global console need to have these methods defined for proper test execution.
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

281-347: Duplicate describe block: "test processGesture in MTS" is identical to "gestures mt".

This describe block contains the same setup, teardown, and test assertions as the "gestures mt" block at lines 158-224. Consider consolidating or differentiating the test cases.

-describe('test processGesture in MTS', () => {
-  let spySetGesture: MockInstance;
-
-  beforeEach(() => {
-    spySetGesture = vi.spyOn(
-      lynxTestingEnv.mainThread.globalThis,
-      '__SetGestureDetector',
-    );
-  });
-
-  afterEach(() => {
-    spySetGesture.mockRestore();
-  });
-
-  test('Old ReactLynx would call __SetGestureDetector correctly', async () => {
-    // ... identical test code ...
-  });
-});
⛔ Skipped due to learnings
Learnt from: Sherry-hue
Repo: lynx-family/lynx-stack PR: 1820
File: packages/web-platform/web-tests/tests/react.spec.ts:834-856
Timestamp: 2025-10-11T06:16:12.517Z
Learning: In packages/web-platform/web-tests/tests/react.spec.ts, the tests `basic-bindmouse` and `basic-mts-bindtouchstart` are NOT duplicates despite having similar test structures. They test different event types: `basic-bindmouse` validates mouse events (mousedown, mouseup, mousemove) with mouse-specific properties (button, buttons, x, y, pageX, pageY, clientX, clientY), while `basic-mts-bindtouchstart` validates touch events (touchstart) with touch arrays (touches, targetTouches, changedTouches). The similar test structure is coincidental and follows testing conventions.
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/testing-library/testing-environment/src/index.ts:255-258
Timestamp: 2025-08-11T05:57:18.212Z
Learning: In the ReactLynx testing environment (`packages/testing-library/testing-environment/src/index.ts`), the dual assignment pattern `target.console.method = console.method = () => {}` is required for rstest compatibility. This is because rstest provides `console` in an IIFE (Immediately Invoked Function Expression), and both the target and global console need to have these methods defined for proper test execution.
packages/lynx/gesture-runtime/__test__/utils/callback.ts (2)

13-20: LGTM!

The MockGestureManager class is well-structured for testing purposes, with properly typed mock functions.


47-64: LGTM!

The genEventObj helper correctly constructs event objects for testing with the expected structure.

packages/lynx/gesture-runtime/src/index.ts (1)

1-48: LGTM!

The entry point provides a clean factory API via the Gesture object and properly re-exports all public gesture classes and interfaces.

packages/lynx/gesture-runtime/src/composition.ts (3)

13-24: LGTM!

The extendRelation helper correctly handles merging gesture relations while maintaining immutability.


98-113: LGTM!

The serialization and flattening methods follow good patterns and provide necessary functionality for debugging and state inspection.


115-169: LGTM!

The composed gesture implementations are well-structured with clear comments explaining the complex relation-wiring logic. The defensive coding comment at line 135 appropriately acknowledges the array bounds safety.

packages/lynx/gesture-runtime/src/gestureInterface.ts (6)

8-24: LGTM!

The separation between GestureKindSerialized and GestureKind provides a clean distinction between serialized and runtime representations.


26-102: LGTM!

The gesture event interface hierarchy is well-structured with clear documentation. The use of empty extensions for certain gesture types (like TapGestureChangeEvent) serves as useful type markers.


104-131: LGTM!

The enums and configuration interfaces are well-defined. The previous typo in ConsumeGestureParams has been properly addressed.


161-270: LGTM!

The gesture type enums, callback types, and configuration interfaces are well-structured with comprehensive documentation. The use of generics with proper constraints provides good type safety.


272-302: LGTM!

The callback interfaces use proper generics for type safety, and the module augmentation correctly extends @lynx-js/types to add gesture support to StandardProps.


136-151: Verify FiberElement type availability.

The InternalStateManager interface references FiberElement at lines 142 and 147. Ensure this type is properly imported in this file or available through the module's type definitions. Check the imports at the top of gestureInterface.ts and verify that FiberElement originates from a valid module export or is defined globally for this file's context.

Comment thread packages/lynx/gesture-runtime/README.md Outdated
Comment thread packages/lynx/gesture-runtime/src/composition.ts
@f0rdream f0rdream force-pushed the gesture-runtime branch 2 times, most recently from 190d753 to e184215 Compare December 5, 2025 10:54
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Dec 5, 2025

CodSpeed Performance Report

Merging #1984 will degrade performances by 5.96%

Comparing f0rdream:gesture-runtime (ec1ef5a) with main (27dea6e)

Summary

⚡ 1 improvement
❌ 1 regression
✅ 61 untouched
⏩ 3 skipped1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark BASE HEAD Change
basic-performance-nest-level-100 6.7 ms 6.2 ms +7.99%
basic-performance-scroll-view-100 9.4 ms 10 ms -5.96%

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@relativeci
Copy link
Copy Markdown

relativeci Bot commented Dec 5, 2025

Web Explorer

#6651 Bundle Size — 372.5KiB (0%).

ec1ef5a(current) vs 27dea6e main#6647(baseline)

Bundle metrics  Change 1 change
                 Current
#6651
     Baseline
#6647
No change  Initial JS 146.23KiB 146.23KiB
No change  Initial CSS 32.4KiB 32.4KiB
Change  Cache Invalidation 0% 39.25%
No change  Chunks 8 8
No change  Assets 8 8
Change  Modules 229(-0.43%) 230
No change  Duplicate Modules 16 16
No change  Duplicate Code 2.97% 2.97%
No change  Packages 4 4
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#6651
     Baseline
#6647
No change  JS 243.12KiB 243.12KiB
No change  Other 96.98KiB 96.98KiB
No change  CSS 32.4KiB 32.4KiB

Bundle analysis reportBranch f0rdream:gesture-runtimeProject dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented Dec 5, 2025

React Example

#6491 Bundle Size — 236.9KiB (0%).

ec1ef5a(current) vs 27dea6e main#6487(baseline)

Bundle metrics  no changes
                 Current
#6491
     Baseline
#6487
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 0%
No change  Chunks 0 0
No change  Assets 4 4
No change  Modules 162 162
No change  Duplicate Modules 65 65
No change  Duplicate Code 46.74% 46.74%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#6491
     Baseline
#6487
No change  IMG 145.76KiB 145.76KiB
No change  Other 91.14KiB 91.14KiB

Bundle analysis reportBranch f0rdream:gesture-runtimeProject dashboard


Generated by RelativeCIDocumentationReport issue

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
vitest.config.ts (1)

81-81: Consider using a glob pattern for the lynx package directory.

For consistency with other multi-package directories (react, rspeedy, webpack, etc.) and to future-proof the configuration, consider using a glob pattern instead of a specific path.

Apply this diff:

-      'packages/lynx/gesture-runtime/vitest.config.ts',
+      'packages/lynx/*/vitest.config.ts',

This would automatically include any future test configurations added under packages/lynx/ without requiring updates to this file.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e67ef58 and a47245e.

📒 Files selected for processing (2)
  • packages/lynx/gesture-runtime/turbo.jsonc (1 hunks)
  • vitest.config.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/lynx/gesture-runtime/turbo.jsonc
  • vitest.config.ts
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • packages/lynx/gesture-runtime/turbo.jsonc
📚 Learning: 2025-09-29T06:43:40.182Z
Learnt from: CR
Repo: lynx-family/lynx-stack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:43:40.182Z
Learning: Applies to packages/**/etc/*.api.md : Always commit API extractor output after running `pnpm turbo api-extractor -- --local` (commit updated API report files)

Applied to files:

  • packages/lynx/gesture-runtime/turbo.jsonc
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • vitest.config.ts
📚 Learning: 2025-08-11T05:59:28.530Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:4-6
Timestamp: 2025-08-11T05:59:28.530Z
Learning: In the lynx-family/lynx-stack repository, the `packages/react/testing-library` package does not have `vite` as a direct dependency. It relies on `vitest` being available from the monorepo root and accesses Vite types through re-exports from `vitest/node`. Direct imports from `vite` should not be suggested for this package.

Applied to files:

  • vitest.config.ts
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Applied to files:

  • vitest.config.ts
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • vitest.config.ts
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • vitest.config.ts
📚 Learning: 2025-08-11T06:00:04.376Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:59-61
Timestamp: 2025-08-11T06:00:04.376Z
Learning: In the lynx-family/lynx-stack repository, the `testingLibraryPlugin` in `packages/react/testing-library/src/plugins/vitest.ts` intentionally uses `process.exit` when jsdom installation fails, maintaining consistency with the previous implementation from `packages/react/testing-library/src/vitest.config.js`. This behavior should not be changed to use `this.error` despite being a Vite plugin best practice.

Applied to files:

  • vitest.config.ts
🔇 Additional comments (1)
packages/lynx/gesture-runtime/turbo.jsonc (1)

6-8: Verify the necessity of the @lynx-js/react#build build-time dependency.

The gesture-runtime package declares @lynx-js/react#build as a dependency in turbo.jsonc. Confirm whether gesture-runtime imports React types or utilities—a low-level gesture runtime may not require React as a build-time dependency. Check the source files for actual React imports to determine if this dependency is intentional or over-specified.

Comment thread packages/lynx/gesture-runtime/turbo.jsonc
@Yradex
Copy link
Copy Markdown
Collaborator

Yradex commented Dec 8, 2025

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/lynx/gesture-runtime/__test__/utils/callback.ts Outdated
Comment thread packages/lynx/gesture-runtime/src/baseGesture.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/lynx/gesture-runtime/package.json (1)

34-37: Consider adding version constraints to peer dependencies.

Using "*" for peer dependencies is very permissive and could lead to runtime compatibility issues with future breaking changes in @lynx-js/react or @lynx-js/types. Consider specifying minimum version ranges (e.g., ">=2.0.0" or "^2.0.0") to ensure consumers use compatible versions.

   "peerDependencies": {
-    "@lynx-js/react": "*",
-    "@lynx-js/types": "*"
+    "@lynx-js/react": ">=0.1.0",
+    "@lynx-js/types": ">=3.0.0"
   }
packages/lynx/gesture-runtime/src/baseGesture.ts (1)

266-272: Consider simplifying the clone method.

The Object.assign(cloned, this) call after the copy constructor may be redundant since the constructor already copies all properties. However, this could be intentional for ensuring subclass properties are copied. If intentional, consider adding a brief comment explaining the purpose.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d3a2f27 and 02799a9.

📒 Files selected for processing (5)
  • packages/lynx/gesture-runtime/__test__/utils/callback.ts (1 hunks)
  • packages/lynx/gesture-runtime/package.json (1 hunks)
  • packages/lynx/gesture-runtime/src/baseGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/turbo.jsonc (1 hunks)
  • vitest.config.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/lynx/gesture-runtime/turbo.jsonc
  • packages/lynx/gesture-runtime/test/utils/callback.ts
🧰 Additional context used
🧠 Learnings (17)
📓 Common learnings
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • vitest.config.ts
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • vitest.config.ts
📚 Learning: 2025-08-11T05:59:28.530Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:4-6
Timestamp: 2025-08-11T05:59:28.530Z
Learning: In the lynx-family/lynx-stack repository, the `packages/react/testing-library` package does not have `vite` as a direct dependency. It relies on `vitest` being available from the monorepo root and accesses Vite types through re-exports from `vitest/node`. Direct imports from `vite` should not be suggested for this package.

Applied to files:

  • vitest.config.ts
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • vitest.config.ts
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Applied to files:

  • vitest.config.ts
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • vitest.config.ts
📚 Learning: 2025-08-11T06:00:04.376Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:59-61
Timestamp: 2025-08-11T06:00:04.376Z
Learning: In the lynx-family/lynx-stack repository, the `testingLibraryPlugin` in `packages/react/testing-library/src/plugins/vitest.ts` intentionally uses `process.exit` when jsdom installation fails, maintaining consistency with the previous implementation from `packages/react/testing-library/src/vitest.config.js`. This behavior should not be changed to use `this.error` despite being a Vite plugin best practice.

Applied to files:

  • vitest.config.ts
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • vitest.config.ts
  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-11-06T01:19:23.670Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1917
File: packages/mcp-servers/devtool-mcp-server/tsconfig.json:8-8
Timestamp: 2025-11-06T01:19:23.670Z
Learning: The lynx-js/devtool-mcp-server package in lynx-family/lynx-stack targets Node.js >=18.19 (specified in its package.json engines), which is different from the root project's requirement of Node.js ^22 || ^24. The package uses "lib": ["ES2024.Promise"] in its tsconfig.json because it manually includes polyfills for Promise.withResolvers while maintaining compatibility with Node.js v18.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-21T08:46:54.494Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-14T12:54:51.143Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: .changeset/brave-melons-add.md:1-7
Timestamp: 2025-08-14T12:54:51.143Z
Learning: In the lynx-family/lynx-stack repository, packages use 0.x.x versioning where minor version bumps indicate breaking changes (not major bumps), following pre-1.0 semantic versioning conventions.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-19T12:49:05.875Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/template-webpack-plugin/src/LynxCacheEventsSetupListRuntimeModule.ts:21-25
Timestamp: 2025-08-19T12:49:05.875Z
Learning: In the Lynx cache events system, there are two separate runtime modules with distinct responsibilities: `LynxCacheEventsSetupListRuntimeModule` is only responsible for initializing the setup list with the setup functions, while `LynxCacheEventsRuntimeModule` guarantees the initialization of `loaded` and `cachedActions` properties. The modules have a dependency relationship where `lynxCacheEventsSetupList` is required by `lynxCacheEvents`.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-12T16:09:32.413Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
🧬 Code graph analysis (1)
packages/lynx/gesture-runtime/src/baseGesture.ts (3)
packages/lynx/gesture-runtime/src/gestureInterface.ts (7)
  • GestureChangeEvent (30-43)
  • InternalStateManager (136-151)
  • GestureCallback (177-182)
  • BaseGestureCallbacks (276-286)
  • ContinuousGestureCallbacks (292-296)
  • StateManager (153-159)
  • GestureKind (16-24)
packages/lynx/gesture-runtime/src/utils/isWorkletObject.ts (1)
  • isWorkletObj (5-14)
packages/lynx/gesture-runtime/src/utils/removeUndefined.ts (1)
  • removeUndefined (4-10)
🔇 Additional comments (7)
vitest.config.ts (1)

81-81: LGTM!

The gesture-runtime vitest configuration is correctly added to the projects array, following the established pattern for packages that require explicit paths rather than glob patterns.

packages/lynx/gesture-runtime/package.json (1)

3-3: Verify initial package version.

Starting a new package at version 2.0.0 is unusual. Based on learnings, this repository follows 0.x.x versioning where minor bumps indicate breaking changes. Consider whether this should start at 0.1.0 or if the 2.0.0 version is intentionally aligned with another package's major version.

packages/lynx/gesture-runtime/src/baseGesture.ts (5)

25-110: Well-structured main-thread callback wrapper.

The wrapCallback function correctly enforces main-thread execution via the worklet check and properly encapsulates the StateManager class inside the callback for worklet accessibility. The error message clearly indicates the constraint to developers.


112-141: LGTM!

The BaseGesture class is well-designed with proper generic constraints, a clear copy constructor pattern for cloning, and correct initialization of the unique gesture ID.


143-190: LGTM!

The configuration and callback registration methods properly track changes via execId and support fluent API chaining. The wrapper type casting is necessary due to the signature difference between raw and wrapped callbacks.


192-237: LGTM!

The relationship management methods correctly handle both single and composed gestures. The previously flagged concat() issues have been properly addressed by assigning the result back to the arrays.


275-303: LGTM!

The ContinuousGesture class properly extends BaseGesture with the additional onUpdate callback. The updateCallback override is necessary due to the extended callback type definition, even though the implementation is identical to the parent.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/lynx/gesture-runtime/package.json (1)

4-4: Enhance package description for clarity.

The description "Lynx Gesture" is too generic. Expand it to briefly convey what the package does, e.g., "Runtime gesture primitives and composition utilities for Lynx" or similar.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02799a9 and f35f9c4.

📒 Files selected for processing (6)
  • packages/lynx/gesture-runtime/README.md (1 hunks)
  • packages/lynx/gesture-runtime/__test__/utils/callback.ts (1 hunks)
  • packages/lynx/gesture-runtime/package.json (1 hunks)
  • packages/lynx/gesture-runtime/src/baseGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/turbo.jsonc (1 hunks)
  • vitest.config.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/lynx/gesture-runtime/src/baseGesture.ts
  • packages/lynx/gesture-runtime/README.md
  • packages/lynx/gesture-runtime/test/utils/callback.ts
  • packages/lynx/gesture-runtime/turbo.jsonc
  • vitest.config.ts
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:4-6
Timestamp: 2025-08-11T05:59:28.530Z
Learning: In the lynx-family/lynx-stack repository, the `packages/react/testing-library` package does not have `vite` as a direct dependency. It relies on `vitest` being available from the monorepo root and accesses Vite types through re-exports from `vitest/node`. Direct imports from `vite` should not be suggested for this package.
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-11-06T01:19:23.670Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1917
File: packages/mcp-servers/devtool-mcp-server/tsconfig.json:8-8
Timestamp: 2025-11-06T01:19:23.670Z
Learning: The lynx-js/devtool-mcp-server package in lynx-family/lynx-stack targets Node.js >=18.19 (specified in its package.json engines), which is different from the root project's requirement of Node.js ^22 || ^24. The package uses "lib": ["ES2024.Promise"] in its tsconfig.json because it manually includes polyfills for Promise.withResolvers while maintaining compatibility with Node.js v18.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-13T11:36:12.075Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:52-72
Timestamp: 2025-08-13T11:36:12.075Z
Learning: The lynx-stack project requires Node.js >=22 as specified in package.json engines, so Node.js compatibility fallbacks for features introduced before v22 are unnecessary.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-21T08:46:54.494Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-14T12:54:51.143Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: .changeset/brave-melons-add.md:1-7
Timestamp: 2025-08-14T12:54:51.143Z
Learning: In the lynx-family/lynx-stack repository, packages use 0.x.x versioning where minor version bumps indicate breaking changes (not major bumps), following pre-1.0 semantic versioning conventions.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-19T12:49:05.875Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/template-webpack-plugin/src/LynxCacheEventsSetupListRuntimeModule.ts:21-25
Timestamp: 2025-08-19T12:49:05.875Z
Learning: In the Lynx cache events system, there are two separate runtime modules with distinct responsibilities: `LynxCacheEventsSetupListRuntimeModule` is only responsible for initializing the setup list with the setup functions, while `LynxCacheEventsRuntimeModule` guarantees the initialization of `loaded` and `cachedActions` properties. The modules have a dependency relationship where `lynxCacheEventsSetupList` is required by `lynxCacheEvents`.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
📚 Learning: 2025-08-12T16:09:32.413Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.

Applied to files:

  • packages/lynx/gesture-runtime/package.json
🔇 Additional comments (3)
packages/lynx/gesture-runtime/package.json (3)

31-31: Clarify purpose of @testing-library/jest-dom in devDependencies.

This library provides DOM assertion helpers for testing but is typically imported in test files only when testing DOM interactions. Verify that this gesture-runtime package actually needs it (e.g., if test files import from it), or if it's a leftover dependency.

Check whether @testing-library/jest-dom is actually imported or used in any test files. If not, consider removing it.


17-22: Clarify rationale for including src/ in published files.

Including source files in the published package is non-standard. Most npm packages only publish the dist/ directory and metadata files (README, CHANGELOG). Exposing src/ adds unnecessary bloat and may be unintentional.

Verify whether src/ should be included for source map transparency or if it should be removed from the files array. If it should be removed, update the files array to only include dist (along with metadata files).


3-3: Verify version number for new package; 2.0.0 may need adjustment per team conventions.

New packages in lynx-stack typically follow 0.x.x pre-release versioning (per PR #1370 conventions). Confirm whether this is a brand-new package that should start at 0.1.0 or 0.2.0, or if 2.0.0 indicates continuity from extracted/reorganized existing code.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/lynx/gesture-runtime/turbo.jsonc (1)

9-17: Excellent: inputs are now properly configured. Minor refinement: use glob pattern for outputs.

The critical feedback from the previous review has been addressed—all required inputs (tsconfig, package.json, src, rslib config) are now included for proper cache invalidation. Consider one final refinement: update the outputs to use a glob pattern for more precise artifact tracking.

      "outputs": [
-       "dist",
+       "dist/**",
      ],
🧹 Nitpick comments (3)
packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (3)

67-72: Make the gesture callback expectation more explicit

expect(panGesture.callbacks.onUpdate).toMatchObject({}) is a very weak/indirect assertion: {} matches any object shape and doesn’t convey what behavior you actually need to lock in. Consider asserting something more explicit about the stored callback (e.g. that it’s defined, or has whatever wrapper/type you expect), so future refactors don’t accidentally keep this test green while breaking the intended contract.


124-155: Align variable naming and assertion with what you really want to guarantee

Here prevPanExecId is assigned to the entire _panGesture instance, and later you assert expect(_panGesture).not.toBe(prevPanExecId);. Two small concerns:

  • The name prevPanExecId suggests you’re tracking some ID, but you’re actually storing the full object reference, which is confusing when reading the test.
  • The test hard‑codes the expectation that useGesture returns a different instance on re‑render. If in the future useGesture chooses to keep a stable instance and just update its config, that could be a valid behavior change but this test would start failing.

If your intent is to specifically test instance replacement, renaming to something like prevPanGesture would help readability. If your intent is to test that the gesture “updates” when state changes, consider asserting on a more stable observable (e.g. an internal id/config snapshot) instead of strict object identity.


172-278: Reduce duplication and clarify the distinct scenarios covered by MT binding tests

The three tests:

  • 'bind gestures should call __SetGestureDetector correctly'
  • 'bind gestures should call __SetGestureDetector with relationsConfig'
  • 'Old ReactLynx would call __SetGestureDetector correctly'

all currently render the same App, use the same render options, and assert exactly the same argument shape passed to __SetGestureDetector. This makes the latter two feel like duplicates rather than independent scenarios (relations vs legacy ReactLynx/MTS).

Two suggestions:

  • If different behaviors are intended (e.g. non‑empty relationConfig or a genuinely different “old ReactLynx” path), adjust the setup so each test actually exercises that unique path.
  • Regardless, factor the common “render + assert __SetGestureDetector args” logic into a small helper to avoid copy‑pasting five‑argument destructuring and the same expectations in three places. That will keep these tests easier to maintain when the detector signature evolves.

Also applies to: 295-347

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f35f9c4 and 533b90f.

📒 Files selected for processing (8)
  • packages/lynx/gesture-runtime/README.md (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-plain.test.ts (1 hunks)
  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx (1 hunks)
  • packages/lynx/gesture-runtime/__test__/utils/callback.ts (1 hunks)
  • packages/lynx/gesture-runtime/package.json (1 hunks)
  • packages/lynx/gesture-runtime/src/baseGesture.ts (1 hunks)
  • packages/lynx/gesture-runtime/turbo.jsonc (1 hunks)
  • vitest.config.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/lynx/gesture-runtime/src/baseGesture.ts
  • packages/lynx/gesture-runtime/README.md
  • packages/lynx/gesture-runtime/test/gesture-plain.test.ts
  • packages/lynx/gesture-runtime/test/utils/callback.ts
  • packages/lynx/gesture-runtime/package.json
  • vitest.config.ts
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:4-6
Timestamp: 2025-08-11T05:59:28.530Z
Learning: In the lynx-family/lynx-stack repository, the `packages/react/testing-library` package does not have `vite` as a direct dependency. It relies on `vitest` being available from the monorepo root and accesses Vite types through re-exports from `vitest/node`. Direct imports from `vite` should not be suggested for this package.
📚 Learning: 2025-10-11T06:16:12.517Z
Learnt from: Sherry-hue
Repo: lynx-family/lynx-stack PR: 1820
File: packages/web-platform/web-tests/tests/react.spec.ts:834-856
Timestamp: 2025-10-11T06:16:12.517Z
Learning: In packages/web-platform/web-tests/tests/react.spec.ts, the tests `basic-bindmouse` and `basic-mts-bindtouchstart` are NOT duplicates despite having similar test structures. They test different event types: `basic-bindmouse` validates mouse events (mousedown, mouseup, mousemove) with mouse-specific properties (button, buttons, x, y, pageX, pageY, clientX, clientY), while `basic-mts-bindtouchstart` validates touch events (touchstart) with touch arrays (touches, targetTouches, changedTouches). The similar test structure is coincidental and follows testing conventions.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
📚 Learning: 2025-08-11T05:57:18.212Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/testing-library/testing-environment/src/index.ts:255-258
Timestamp: 2025-08-11T05:57:18.212Z
Learning: In the ReactLynx testing environment (`packages/testing-library/testing-environment/src/index.ts`), the dual assignment pattern `target.console.method = console.method = () => {}` is required for rstest compatibility. This is because rstest provides `console` in an IIFE (Immediately Invoked Function Expression), and both the target and global console need to have these methods defined for proper test execution.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
  • packages/lynx/gesture-runtime/turbo.jsonc
📚 Learning: 2025-11-11T08:05:14.163Z
Learnt from: Sherry-hue
Repo: lynx-family/lynx-stack PR: 1932
File: packages/web-platform/web-tests/tests/react/basic-element-x-input-ng-bindinput/index.jsx:10-26
Timestamp: 2025-11-11T08:05:14.163Z
Learning: In packages/web-platform/web-tests/tests/react/basic-element-x-input-ng-bindinput/index.jsx, the test intentionally uses selectionStart twice in the result string (instead of selectionStart and selectionEnd) because it prioritizes testing whether x-input-ng works functionally, rather than validating the correctness of selection values.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
📚 Learning: 2025-10-29T10:28:27.519Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1899
File: packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/lib.rs/should_static_extract_dynamic_inline_style.js:20-24
Timestamp: 2025-10-29T10:28:27.519Z
Learning: Files inside packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/ are auto-generated test snapshot files and should not be manually updated. Any issues with the generated code should be addressed in the code generator/transform logic, not in the snapshots themselves.

Applied to files:

  • packages/lynx/gesture-runtime/__test__/gesture-react.test.tsx
📚 Learning: 2025-09-29T06:43:40.182Z
Learnt from: CR
Repo: lynx-family/lynx-stack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:43:40.182Z
Learning: Applies to packages/**/etc/*.api.md : Always commit API extractor output after running `pnpm turbo api-extractor -- --local` (commit updated API report files)

Applied to files:

  • packages/lynx/gesture-runtime/turbo.jsonc
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • packages/lynx/gesture-runtime/turbo.jsonc
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/lynx/gesture-runtime/turbo.jsonc
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: test-rust / Test (Ubuntu)
  • GitHub Check: test-rust / clippy

@f0rdream f0rdream requested review from Yradex and colinaaa December 11, 2025 13:34
Signed-off-by: RyanWang <14049186+f0rdream@users.noreply.github.com>
@colinaaa colinaaa merged commit 80c012a into lynx-family:main Dec 17, 2025
50 of 51 checks passed
f0rdream added a commit to f0rdream/lynx-stack that referenced this pull request Dec 18, 2025
`@lynx-js/gesture-runtime` provides typed gesture primitives and simple
composition utilities for Lynx. It helps with gestures, from simple
`PanGesture`, `TapGesture` to complex Gesture Compositions

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* New gesture-runtime package: Pan, Tap, LongPress, Fling, Default
Scroll gestures; composition helpers (Simultaneous, Exclusive, Race);
unified Gesture API and useGesture hook; public TypeScript typings and
shared defaults.

* **Documentation**
  * Added package README with overview, installation and usage examples.

* **Tests**
* Extensive test suites covering configs, callbacks, cloning,
composition, relations, serialization, runtime behavior and type-safety.

* **Chores**
  * Project build/test configs and linter ignores for runtime tests.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

## Checklist

<!--- Check and mark with an "x" -->

- [x] Tests updated (or not required).
- [ ] Documentation updated (or not required).
- [x] Changeset added, and when a BREAKING CHANGE occurs, it needs to be
clearly marked (or not required).

---------

Signed-off-by: RyanWang <14049186+f0rdream@users.noreply.github.com>
colinaaa pushed a commit that referenced this pull request Dec 22, 2025
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @lynx-js/gesture-runtime@2.1.0

### Minor Changes

- Initialize `'@lynx-js/gesture-runtime`
([#1984](#1984))

## @lynx-js/rspeedy@0.12.3

### Patch Changes

- Support environment variants to enable multiple configurations for the
same targets.
([#1969](#1969))

-   Updated dependencies \[]:
    -   @lynx-js/web-rsbuild-server-middleware@0.19.2

## @lynx-js/lynx-bundle-rslib-config@0.0.2

### Patch Changes

- Introduce `@lynx-js/externals-loading-webpack-plugin`. It will help
you to load externals built by `@lynx-js/lynx-bundle-rslib-config`.
([#1924](#1924))

    ```js
    // webpack.config.js
import { ExternalsLoadingPlugin } from
"@lynx-js/externals-loading-webpack-plugin";

    export default {
      plugins: [
        new ExternalsLoadingPlugin({
          mainThreadLayer: "main-thread",
          backgroundLayer: "background",
          externals: {
            lodash: {
              url: "http://lodash.lynx.bundle",
              background: { sectionPath: "background" },
              mainThread: { sectionPath: "main-thread" },
            },
          },
        }),
      ],
    };
    ```

## @lynx-js/react-rsbuild-plugin@0.12.2

### Patch Changes

- Support environment variants to enable multiple configurations for the
same targets.
([#1969](#1969))

-   Updated dependencies \[]:
    -   @lynx-js/react-alias-rsbuild-plugin@0.12.2

## @lynx-js/web-constants@0.19.2

### Patch Changes

-   Updated dependencies \[]:
    -   @lynx-js/web-worker-rpc@0.19.2

## @lynx-js/web-core@0.19.2

### Patch Changes

- chore: mark the "multi-thread" deprecated
([#2030](#2030))

    **NOTICE This will be a breaking change in the future**

    mark the thread strategy "multi-thread" as deprecated.

Please use "all-on-ui" instead. If you still want to use multi-thread
mode, please try to use a cross-origin isolated iframe.

A console warning will be printed if `thread-strategy` is set to
`multi-thread`.

- fix csp issue for mts realm
([#1998](#1998))

-   Updated dependencies \[]:
    -   @lynx-js/web-constants@0.19.2
    -   @lynx-js/web-mainthread-apis@0.19.2
    -   @lynx-js/web-worker-rpc@0.19.2
    -   @lynx-js/web-worker-runtime@0.19.2

## @lynx-js/web-explorer@0.0.15

### Patch Changes

- fix: web-explorer needs to actively send an iframeReady message to the
parent, the parent uses `iframe load` listener cannot guarantee that the
`message-listener` will complete execution.
([#2001](#2001))

## @lynx-js/web-mainthread-apis@0.19.2

### Patch Changes

-   Updated dependencies \[]:
    -   @lynx-js/web-constants@0.19.2

## @lynx-js/web-worker-runtime@0.19.2

### Patch Changes

-   Updated dependencies \[]:
    -   @lynx-js/web-constants@0.19.2
    -   @lynx-js/web-mainthread-apis@0.19.2
    -   @lynx-js/web-worker-rpc@0.19.2

## @lynx-js/externals-loading-webpack-plugin@0.0.1

### Patch Changes

- Introduce `@lynx-js/externals-loading-webpack-plugin`. It will help
you to load externals built by `@lynx-js/lynx-bundle-rslib-config`.
([#1924](#1924))

    ```js
    // webpack.config.js
import { ExternalsLoadingPlugin } from
"@lynx-js/externals-loading-webpack-plugin";

    export default {
      plugins: [
        new ExternalsLoadingPlugin({
          mainThreadLayer: "main-thread",
          backgroundLayer: "background",
          externals: {
            lodash: {
              url: "http://lodash.lynx.bundle",
              background: { sectionPath: "background" },
              mainThread: { sectionPath: "main-thread" },
            },
          },
        }),
      ],
    };
    ```

## create-rspeedy@0.12.3



## @lynx-js/react-alias-rsbuild-plugin@0.12.2



## upgrade-rspeedy@0.12.3



## @lynx-js/web-core-server@0.19.2



## @lynx-js/web-rsbuild-server-middleware@0.19.2



## @lynx-js/web-worker-rpc@0.19.2

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@coderabbitai coderabbitai Bot mentioned this pull request Dec 30, 2025
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants