Skip to content

feat: implement global-bind event support for decoupled cross-element…#2438

Merged
PupilTong merged 8 commits intolynx-family:mainfrom
PupilTong:p/hw/support-global-bind
Apr 10, 2026
Merged

feat: implement global-bind event support for decoupled cross-element…#2438
PupilTong merged 8 commits intolynx-family:mainfrom
PupilTong:p/hw/support-global-bind

Conversation

@PupilTong
Copy link
Copy Markdown
Collaborator

@PupilTong PupilTong commented Apr 8, 2026

… communication

Summary by CodeRabbit

  • New Features

    • Added a global event binding modifier (e.g., global-bindTap) that lets an observer handle events fired anywhere in the component tree via bubbling.
  • Tests

    • Added end-to-end and unit tests verifying registration, dispatch, handler invocation, color/state updates, and unregistration for global-bind behavior.
  • Documentation

    • Added a changeset with examples and usage notes for global-bind.

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).

@PupilTong PupilTong requested a review from Sherry-hue as a code owner April 8, 2026 10:40
@PupilTong PupilTong self-assigned this Apr 8, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 8, 2026

🦋 Changeset detected

Latest commit: 0601e37

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

This PR includes changesets to release 9 packages
Name Type
@lynx-js/web-core Patch
upgrade-rspeedy Patch
@lynx-js/web-rsbuild-server-middleware Patch
@lynx-js/template-webpack-plugin Patch
@lynx-js/react-rsbuild-plugin Patch
create-rspeedy Patch
@lynx-js/web-worker-rpc Patch
@lynx-js/react-alias-rsbuild-plugin Patch
@lynx-js/rspeedy Patch

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 Apr 8, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds documentation, WASM binding declarations, Rust runtime bookkeeping and dispatch, and tests to implement a new global-bind<event> modifier that lets observer elements register handlers invoked when the corresponding event bubbles anywhere in the component tree.

Changes

Cohort / File(s) Summary
Changesets / Docs
\.changeset/feat-global-bind-support.md, \.changeset/red-dragons-tickle.md
New changeset documenting global-bind support and an additional metadata changeset (docs-only).
WASM bindings (client & legacy)
packages/web-platform/web-core/binary/client/client.d.ts, packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts, packages/web-platform/web-core/binary/client_legacy/client.d.ts, packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts
Added mainthreadwasmcontext_dispatch_global_bind_event export and corresponding MainThreadWasmContext.dispatch_global_bind_event declaration to modern and legacy WASM binding d.ts files.
Runtime / Rust event handling
packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs, packages/web-platform/web-core/src/main_thread/client/main_thread_context.rs, packages/web-platform/web-core/src/constants.rs
Added global_bind_events map on context; track global-bindevent registrations on handler add/remove; introduced dispatch_global_bind_event and invoke it from the bubbling path; replaced hardcoded event-type list with EVENT_TYPES.
End-to-end tests
packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts, packages/web-platform/web-core-e2e/tests/reactlynx/basic-global-bind/index.jsx
Added Playwright E2E test and React Lynx test page exercising global-bindTap behavior (observer toggles color when target is tapped).
Unit tests
packages/web-platform/web-core/tests/element-apis.spec.ts
Added Vitest case verifying global-bindevent registration reported by __GetEvents, publishEvent invocation on bubbling DOM events, and deregistration behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • Sherry-hue
  • colinaaa

Poem

🐰
I hopped through runtime trees so wide,
I listened as events did glide,
One tap traveled up the line—
Observers blinked from pink to green in time,
A tiny hop, a global-bind delight.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat: implement global-bind event support for decoupled cross-element...' accurately summarizes the main change—adding global-bind event support for cross-element communication—which is well-reflected across the changeset (WASM bindings, event APIs, tests, and documentation).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 Apr 8, 2026

Codecov Report

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

Files with missing lines Patch % Lines
.../src/main_thread/client/element_apis/event_apis.rs 0.00% 89 Missing ⚠️
...core/src/main_thread/client/main_thread_context.rs 0.00% 1 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: 2

🧹 Nitpick comments (2)
packages/web-platform/web-core-e2e/tests/reactlynx/basic-global-bind/index.jsx (1)

31-31: Prefer functional state update for toggle safety.

Use a functional setter to avoid stale state reads during rapid event bursts.

♻️ Suggested change
-        global-bindTap={() => setColor(color === 'pink' ? 'green' : 'pink')}
+        global-bindTap={() =>
+          setColor((prev) => (prev === 'pink' ? 'green' : 'pink'))
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/web-platform/web-core-e2e/tests/reactlynx/basic-global-bind/index.jsx`
at line 31, The current inline handler on global-bindTap reads the outer color
variable directly, which can produce stale reads under rapid events; change the
handler to call the setColor updater with a functional setter that receives the
previous color (e.g., prevColor) and returns the toggled value to ensure safe
toggling; update the attribute that uses setColor and color (global-bindTap) to
use this functional updater form instead.
packages/web-platform/web-core/tests/element-apis.spec.ts (1)

1464-1511: Add a non-bubbling negative assertion for global-bind.

The test currently validates bubbling + unregister paths only. Add one bubbles: false dispatch check to lock in the “bubble-required” contract.

✅ Suggested test addition
   rootDom.querySelector('#global_bind_target')?.dispatchEvent(
     new window.Event('click', { bubbles: true }),
   );

   expect(publishSpy).toHaveBeenCalledTimes(1);
@@
     undefined,
   );
+
+  publishSpy.mockClear();
+  rootDom.querySelector('#global_bind_target')?.dispatchEvent(
+    new window.Event('click', { bubbles: false }),
+  );
+  expect(publishSpy).toHaveBeenCalledTimes(0);

   // Unregister global-bind
   mtsGlobalThis.__AddEvent(element2, 'global-bind', 'tap', null as any);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/web-platform/web-core/tests/element-apis.spec.ts` around lines 1464
- 1511, Add a non-bubbling negative assertion inside the "should handle
global-bind events" test: after registering the global-bind on element2 (via
mtsGlobalThis.__AddEvent) and after creating publishSpy, dispatch a click event
on the target element (found via rootDom.querySelector('#global_bind_target'))
with bubbles set to false, and assert that mtsBinding.publishEvent (publishSpy)
was not called; keep the existing bubbling dispatch and unregister assertions
unchanged. This ensures the global-bind requires bubbling to trigger.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs`:
- Around line 38-50: The removal logic in the event handler branch
unconditionally removes unique_id from self.global_bind_events based solely on
the current API call; instead, after calling replace_framework_*_event_handler
(the framework-side registration helpers) re-check both handler registries
(i.e., whether any global-bind handler flavor remains for that element) before
removing unique_id from self.global_bind_events so a listener that still has the
other flavor stays in the dispatch index used by dispatch_global_bind_event;
update the removal branch that uses event_handler_identifier and the symmetric
branch (lines ~101-111) to query both registries and only remove when neither
flavor is present, and add a regression test in tests/element-apis.spec.ts
verifying independent unregister of each global-bind flavor and that
dispatch_global_bind_event still delivers to a remaining handler.
- Around line 354-404: The loop holds a borrow of self.global_bind_events via
global_bind_ids while calling back into JS (self.mts_binding.publish_event /
publish_mts_event), which allows re-entrant mutation and UB; fix by snapshotting
the IDs into a Vec<usize> before the loop so the borrow is released (i.e.,
replace iterating over global_bind_ids directly with let ids: Vec<usize> =
self.global_bind_events.get(&event_name_lowercase).cloned().unwrap_or_default().into_iter().collect()
or similar), then iterate over that Vec and use get_element_data_by_unique_id,
get_framework_cross_thread_event_handler, publish_event and publish_mts_event as
before.

---

Nitpick comments:
In
`@packages/web-platform/web-core-e2e/tests/reactlynx/basic-global-bind/index.jsx`:
- Line 31: The current inline handler on global-bindTap reads the outer color
variable directly, which can produce stale reads under rapid events; change the
handler to call the setColor updater with a functional setter that receives the
previous color (e.g., prevColor) and returns the toggled value to ensure safe
toggling; update the attribute that uses setColor and color (global-bindTap) to
use this functional updater form instead.

In `@packages/web-platform/web-core/tests/element-apis.spec.ts`:
- Around line 1464-1511: Add a non-bubbling negative assertion inside the
"should handle global-bind events" test: after registering the global-bind on
element2 (via mtsGlobalThis.__AddEvent) and after creating publishSpy, dispatch
a click event on the target element (found via
rootDom.querySelector('#global_bind_target')) with bubbles set to false, and
assert that mtsBinding.publishEvent (publishSpy) was not called; keep the
existing bubbling dispatch and unregister assertions unchanged. This ensures the
global-bind requires bubbling to trigger.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: db88821f-ab39-40d2-a330-3e678e9216eb

📥 Commits

Reviewing files that changed from the base of the PR and between 59d11b2 and f9f6111.

📒 Files selected for processing (11)
  • .changeset/feat-global-bind-support.md
  • .changeset/red-dragons-tickle.md
  • packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts
  • packages/web-platform/web-core-e2e/tests/reactlynx/basic-global-bind/index.jsx
  • packages/web-platform/web-core/binary/client/client.d.ts
  • packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts
  • packages/web-platform/web-core/binary/client_legacy/client.d.ts
  • packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts
  • packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs
  • packages/web-platform/web-core/src/main_thread/client/main_thread_context.rs
  • packages/web-platform/web-core/tests/element-apis.spec.ts

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Apr 8, 2026

Merging this PR will degrade performance by 8.07%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 1 regressed benchmark
✅ 71 untouched benchmarks
⏩ 21 skipped benchmarks1

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

Performance Changes

Benchmark BASE HEAD Efficiency
transform 1000 view elements 43.6 ms 47.4 ms -8.07%

Comparing PupilTong:p/hw/support-global-bind (0601e37) with main (045ca2f)

Open in CodSpeed

Footnotes

  1. 21 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 Apr 8, 2026

React Example

#7173 Bundle Size — 236.82KiB (0%).

0601e37(current) vs 045ca2f main#7170(baseline)

Bundle metrics  no changes
                 Current
#7173
     Baseline
#7170
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 179 179
No change  Duplicate Modules 70 70
No change  Duplicate Code 46.1% 46.1%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#7173
     Baseline
#7170
No change  IMG 145.76KiB 145.76KiB
No change  Other 91.06KiB 91.06KiB

Bundle analysis reportBranch PupilTong:p/hw/support-global-bi...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci bot commented Apr 8, 2026

React MTF Example

#306 Bundle Size — 206.11KiB (0%).

0601e37(current) vs 045ca2f main#303(baseline)

Bundle metrics  no changes
                 Current
#306
     Baseline
#303
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
Change  Cache Invalidation 0% 46.02%
No change  Chunks 0 0
No change  Assets 3 3
No change  Modules 173 173
No change  Duplicate Modules 67 67
No change  Duplicate Code 45.76% 45.76%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#306
     Baseline
#303
No change  IMG 111.23KiB 111.23KiB
No change  Other 94.88KiB 94.88KiB

Bundle analysis reportBranch PupilTong:p/hw/support-global-bi...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci bot commented Apr 8, 2026

React External

#291 Bundle Size — 590.13KiB (0%).

0601e37(current) vs 045ca2f main#288(baseline)

Bundle metrics  no changes
                 Current
#291
     Baseline
#288
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 3 3
No change  Modules 17 17
No change  Duplicate Modules 5 5
No change  Duplicate Code 8.59% 8.59%
No change  Packages 0 0
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#291
     Baseline
#288
No change  Other 590.13KiB 590.13KiB

Bundle analysis reportBranch PupilTong:p/hw/support-global-bi...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci bot commented Apr 8, 2026

Web Explorer

#8748 Bundle Size — 743.45KiB (+1.81%).

0601e37(current) vs 045ca2f main#8745(baseline)

Bundle metrics  Change 3 changes Regression 1 regression
                 Current
#8748
     Baseline
#8745
Regression  Initial JS 43.82KiB(+0.44%) 43.63KiB
No change  Initial CSS 2.16KiB 2.16KiB
Change  Cache Invalidation 28.41% 0%
No change  Chunks 8 8
No change  Assets 10 10
No change  Modules 149 149
No change  Duplicate Modules 11 11
Change  Duplicate Code 34.96%(+0.78%) 34.69%
No change  Packages 3 3
No change  Duplicate Packages 0 0
Bundle size by type  Change 2 changes Regression 2 regressions
                 Current
#8748
     Baseline
#8745
Regression  Other 398.15KiB (+3.27%) 385.55KiB
Regression  JS 343.13KiB (+0.18%) 342.53KiB
No change  CSS 2.16KiB 2.16KiB

Bundle analysis reportBranch PupilTong:p/hw/support-global-bi...Project 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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs`:
- Around line 165-171: The event lookup fails because the event_types vector
contains "global-bind" while handlers are stored as "global-bindevent" (after
React -> global-bindEvent -> lowercased in add_cross_thread_event); update the
event_types entry (or normalize keys) so get_events queries the same lowercased
stored key: change "global-bind" to "global-bindevent" in the event_types list
used by get_events (or apply the same transformation used in
add_cross_thread_event before calling get_framework_cross_thread_event_handler)
so get_framework_cross_thread_event_handler receives the exact key used when
handlers were registered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ba258de5-f43b-43bf-83da-306a32211a1e

📥 Commits

Reviewing files that changed from the base of the PR and between f9f6111 and a54089a.

📒 Files selected for processing (1)
  • packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs

@PupilTong PupilTong force-pushed the p/hw/support-global-bind branch from a54089a to 806b09d Compare April 8, 2026 13:54
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

♻️ Duplicate comments (1)
packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs (1)

344-389: ⚠️ Potential issue | 🔴 Critical

Drop the global_bind_events borrow before calling back into JS.

The loop borrows self.global_bind_events via global_bind_ids while calling publish_event / publish_mts_event, which can synchronously re-enter wasm. If a handler registers or unregisters a global-bind listener during dispatch, it will cause a RefCell borrow panic.

Snapshot the IDs into a Vec<usize> first so the borrow is released before the first JS callback.

🐛 Proposed fix
-    if let Some(global_bind_ids) = self.global_bind_events.get(&event_name_lowercase) {
-      for unique_id in global_bind_ids {
-        let binding = match self.get_element_data_by_unique_id(*unique_id) {
+    let global_bind_ids: Vec<usize> = self
+      .global_bind_events
+      .get(&event_name_lowercase)
+      .map(|ids| ids.iter().copied().collect())
+      .unwrap_or_default();
+
+    for unique_id in global_bind_ids {
+      let binding = match self.get_element_data_by_unique_id(unique_id) {
           Some(b) => b,
           None => continue,
         };
         let current_target_element_data = binding.borrow();
 
         let bind_handler = current_target_element_data
           .get_framework_cross_thread_event_handler(&event_name_lowercase, "global-bindevent");
 
         if let Some(handler) = bind_handler {
           // ... rest of the code with *unique_id changed to unique_id
         }
         // ...
-      }
     }
-    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs`
around lines 344 - 389, The loop currently holds a borrow of
self.global_bind_events via global_bind_ids while invoking callbacks that can
re-enter JS; to fix, snapshot the IDs into a Vec<usize> (e.g., let
global_bind_ids_vec =
self.global_bind_events.get(&event_name_lowercase).cloned().unwrap_or_default().into_iter().collect::<Vec<_>>();)
and iterate over that Vec instead so the RefCell borrow is dropped before
calling self.mts_binding.publish_event and self.mts_binding.publish_mts_event;
ensure you still use get_element_data_by_unique_id,
get_framework_cross_thread_event_handler, and
get_framework_run_worklet_event_handler against the snapped IDs and preserve the
existing parent_component_unique_id/component_id logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs`:
- Around line 110-116: The add_run_worklet_event path currently adds unique_id
to self.global_bind_events when event_type == "global-bindevent" and
event_handler_identifier.is_some(), but it never removes it when
event_handler_identifier.is_none(); update add_run_worklet_event to mirror the
removal logic used in add_cross_thread_event: when event_type ==
"global-bindevent" and event_handler_identifier.is_none(), remove unique_id from
the set at self.global_bind_events.entry(event_name.clone()), and if the set
becomes empty, remove the key entirely so entries are cleaned up.

---

Duplicate comments:
In
`@packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs`:
- Around line 344-389: The loop currently holds a borrow of
self.global_bind_events via global_bind_ids while invoking callbacks that can
re-enter JS; to fix, snapshot the IDs into a Vec<usize> (e.g., let
global_bind_ids_vec =
self.global_bind_events.get(&event_name_lowercase).cloned().unwrap_or_default().into_iter().collect::<Vec<_>>();)
and iterate over that Vec instead so the RefCell borrow is dropped before
calling self.mts_binding.publish_event and self.mts_binding.publish_mts_event;
ensure you still use get_element_data_by_unique_id,
get_framework_cross_thread_event_handler, and
get_framework_run_worklet_event_handler against the snapped IDs and preserve the
existing parent_component_unique_id/component_id logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 81076f96-41ef-4bf7-9a7e-b687f133234b

📥 Commits

Reviewing files that changed from the base of the PR and between a54089a and 806b09d.

📒 Files selected for processing (12)
  • .changeset/feat-global-bind-support.md
  • .changeset/red-dragons-tickle.md
  • packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts
  • packages/web-platform/web-core-e2e/tests/reactlynx/basic-global-bind/index.jsx
  • packages/web-platform/web-core/binary/client/client.d.ts
  • packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts
  • packages/web-platform/web-core/binary/client_legacy/client.d.ts
  • packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts
  • packages/web-platform/web-core/src/constants.rs
  • packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs
  • packages/web-platform/web-core/src/main_thread/client/main_thread_context.rs
  • packages/web-platform/web-core/tests/element-apis.spec.ts
✅ Files skipped from review due to trivial changes (5)
  • .changeset/red-dragons-tickle.md
  • .changeset/feat-global-bind-support.md
  • packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts
  • packages/web-platform/web-core-e2e/tests/reactlynx.spec.ts
  • packages/web-platform/web-core/tests/element-apis.spec.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts
  • packages/web-platform/web-core/binary/client/client.d.ts
  • packages/web-platform/web-core/binary/client_legacy/client.d.ts
  • packages/web-platform/web-core/src/main_thread/client/main_thread_context.rs

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)
packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs (1)

154-156: Clean up empty global_bind_events buckets after removal.

After removing unique_id, empty sets are left in the map. It’s harmless functionally, but cleaning empty keys avoids unnecessary map growth/lookups over time.

♻️ Suggested cleanup
-        if let Some(ids) = self.global_bind_events.get_mut(event_name) {
-          ids.remove(&unique_id);
-        }
+        let should_remove_key = if let Some(ids) = self.global_bind_events.get_mut(event_name) {
+          ids.remove(&unique_id);
+          ids.is_empty()
+        } else {
+          false
+        };
+        if should_remove_key {
+          self.global_bind_events.remove(event_name);
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs`
around lines 154 - 156, After removing unique_id from the set in
self.global_bind_events (the block that checks if let Some(ids) =
self.global_bind_events.get_mut(event_name)), also check whether ids.is_empty()
and if so remove the key from the map (e.g., call
self.global_bind_events.remove(event_name) or use the entry API) so empty
HashSet buckets aren’t left behind; update the cleanup code in the same scope
that handles event_name and unique_id.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs`:
- Around line 334-401: The PR added dispatch_global_bind_event and
global_bind_events bookkeeping but lacks JS-side tests; add coverage in
tests/element-apis.spec.ts to register, dispatch and unregister global-bind
handlers for both cross-thread and run-worklet paths. Specifically, write tests
that: (1) register a global-bind handler from the JS side, assert that
dispatch_global_bind_event (triggered via the public dispatch API) invokes the
handler that maps to the Rust function dispatch_global_bind_event and that the
handler path uses get_framework_cross_thread_event_handler and calls
publish_event with correct args; (2) register a run-worklet global-bind handler,
dispatch and assert publish_mts_event is invoked (the run-worklet path uses
get_framework_run_worklet_event_handler and publish_mts_event); and (3)
unregister handlers and assert subsequent dispatches do not call either
publish_event or publish_mts_event. Reference the Rust symbols
dispatch_global_bind_event, global_bind_events,
get_framework_cross_thread_event_handler,
get_framework_run_worklet_event_handler, publish_event and publish_mts_event so
the tests exercise both cross-thread and run-worklet global-bind flows.

---

Nitpick comments:
In
`@packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs`:
- Around line 154-156: After removing unique_id from the set in
self.global_bind_events (the block that checks if let Some(ids) =
self.global_bind_events.get_mut(event_name)), also check whether ids.is_empty()
and if so remove the key from the map (e.g., call
self.global_bind_events.remove(event_name) or use the entry API) so empty
HashSet buckets aren’t left behind; update the cleanup code in the same scope
that handles event_name and unique_id.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 863c86c7-0571-4d20-a4bb-b088bdd75040

📥 Commits

Reviewing files that changed from the base of the PR and between cd17a16 and 4daebc8.

📒 Files selected for processing (1)
  • packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs

@PupilTong PupilTong merged commit 5151fcf into lynx-family:main Apr 10, 2026
72 of 78 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants