Frontmatter
| id | 9510 |
| title | Tooltip regression: dynamic domListeners bypassed reactivity and bubbling fixes |
| state | Closed |
| labels | bugaicore |
| assignees | tobiu |
| createdAt | Mar 18, 2026, 1:00 PM |
| updatedAt | Mar 18, 2026, 1:15 PM |
| githubUrl | https://github.com/neomjs/neo/issues/9510 |
| author | tobiu |
| commentsCount | 2 |
| parentIssue | null |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Mar 18, 2026, 1:15 PM |
Tooltip regression: dynamic domListeners bypassed reactivity and bubbling fixes

Input from Gemini 3.1 Pro:
✦ Completed the fix.
Commit: 5348eb155
Resolved the following issues:
- Bubbling Cancellation: In
src/manager/DomEvent.mjs, fixed the event loop check to explicitly uselistener.bubble === falseinstead of!listener.bubble.- Boolean Parsing in Manager: Fixed
DomEvent.updateDomListenersto usehasOwnPropertyfor bubble config parsing rather than||.- vnodeId Consistent Fallback: Added fallback logic to
config.idinmanager/DomEvent.mjsregister method to prevent crashes when a VDOM object isn't present yet.

Input from Gemini 3.1 Pro:
✦ Added architectural refactoring.
Commit: f1b55cc7b
Reverted the manual
[...this.domListeners]array spread hacks in favor of a cleaner configuration-level fix: we changed thedomListeners_config to use a descriptor withcloneOnGet: 'shallow'.This ensures that any time a developer accesses
this.domListeners, they receive a new array reference. If they mutate it (e.g..push()) and assign it back,core.Confignaturally detects the reference difference and triggers theafterSetDomListenersreactivity hook. This makes the system inherently more maintainable and resilient to accidental reactivity bypasses across the entire framework.
In Neo v12, dynamic DOM event registration (e.g.,
addDomListeners) failed due to three separate bugs in the event architecture:src/mixin/DomEvents.mjsmutated thethis.domListenersarray in place. Thecore.Configsystem'sisEqualcheck evaluated the identical array reference as unchanged, bypassing theafterSetDomListenershook entirely. Fixed by spreading into a new array.src/manager/DomEvent.mjs, the globalbubbleflag was cancelled if!listener.bubblewas true. Since omitted configs areundefined,!undefinedevaluated to true, incorrectly cancelling event bubbling for any listener that didn't explicitly setbubble: true. Fixed to explicitly check forlistener.bubble === false.DomEvent.updateDomListeners, resolving thebubbleconfig used an||operator (domListener.bubble || value.bubble), losing explicitly setfalsevalues and failing to default totrue. Fixed to usehasOwnProperty. Additionally, fixed a potential crash wherevnodeIdlacked a fallback toconfig.idifvdomwas not present in theregistermethod.