ripple@0.3.124
Ripple-TS/rippleripple@0.3.124Aug 21, 2026by github-actions[bot]
AI Summary
Patch release fixing event delegation logic for multiple portals and roots.
Key Highlights
- Fixed event delegation breaking when multiple roots (Portals, mounts) share or mix targets.
- Implemented ref-counting for delegated event listeners to prevent incorrect cleanup.
- Removed the single `root_target` global in favor of per-root target checks.
- Portal now acquires root event delegation keyed on target to prevent unnecessary re-attaching.
Full Release Notes
### Patch Changes
- [#1434](https://github.com/Ripple-TS/ripple/pull/1434)
[`2f4d02d`](https://github.com/Ripple-TS/ripple/commit/2f4d02d6a6ab83fd1af7e16b86967223990f1aa3)
Thanks [@chenzylab](https://github.com/chenzylab)! - Fix event delegation
breaking when multiple roots (Portals, mounts) share or mix targets.
- `handle_root_events(target)` had no notion of multiple callers sharing the
same `target` element. Each Portal (or the app root) calls it once on mount;
its cleanup unconditionally removed the delegated event listeners from
`target`. When two Portals both mount to `document.body` (e.g. a Modal and a
SideSheet), closing the first tore down the delegated listeners for
`document.body` entirely, silently breaking every click inside the second — no
error, no warning. `handle_root_events` now ref-counts callers per target, and
the delegated listeners are only torn down once every caller for that target
has released it.
- The single `root_target` global is gone. `on()` now checks the element against
every active root target, so attaching a listener directly to one root's
target while another root (e.g. a Portal to a sibling layer) was acquired
later no longer silently takes the broken delegated path.
- `Portal` acquires root event delegation in its own render block keyed on
`target`, so a children-only update no longer releases and re-adds every
delegated listener on the target.