From 4ded827587a7c6bfa4d1d1bc04ad90a2a5e88acb Mon Sep 17 00:00:00 2001 From: Tyler Roach Date: Thu, 14 May 2026 10:24:33 -0400 Subject: [PATCH] fix(autocapture): register click/change/submit listeners in capture phase Bubble-phase listeners on window are silenced when downstream component code calls event.stopPropagation(). React Native Web's PressResponder does this unconditionally on every onClick, breaking autocapture for all RNW-rendered components. Capture-phase listeners fire before any component handler runs, so stopPropagation() in bubble cannot reach them. Applied to all five user-interaction listeners: click, dead-click, rage-click, input change, and form submit. Matching removeEventListener calls also updated since browsers treat capture and bubble registrations as separate. Co-Authored-By: Claude Opus 4.7 --- src/autocapture/index.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/autocapture/index.js b/src/autocapture/index.js index 557ccb2c..779f373b 100644 --- a/src/autocapture/index.js +++ b/src/autocapture/index.js @@ -292,7 +292,7 @@ Autocapture.prototype._initScrollDepthTracking = function() { }; Autocapture.prototype.initClickTracking = function() { - window.removeEventListener(EV_CLICK, this.listenerClick); + window.removeEventListener(EV_CLICK, this.listenerClick, true); if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) { return; @@ -305,7 +305,7 @@ Autocapture.prototype.initClickTracking = function() { } this.trackDomEvent(ev, MP_EV_CLICK); }.bind(this); - window.addEventListener(EV_CLICK, this.listenerClick); + window.addEventListener(EV_CLICK, this.listenerClick, true); }; Autocapture.prototype.initDeadClickTracking = function() { @@ -340,12 +340,12 @@ Autocapture.prototype.initDeadClickTracking = function() { } this._deadClickTracker.trackClick(ev, normalizedConfig); }.bind(this); - window.addEventListener(EV_CLICK, this.listenerDeadClick); + window.addEventListener(EV_CLICK, this.listenerDeadClick, true); } }; Autocapture.prototype.initInputTracking = function() { - window.removeEventListener(EV_CHANGE, this.listenerChange); + window.removeEventListener(EV_CHANGE, this.listenerChange, true); if (!this.getConfig(CONFIG_TRACK_INPUT)) { return; @@ -358,7 +358,7 @@ Autocapture.prototype.initInputTracking = function() { } this.trackDomEvent(ev, MP_EV_INPUT); }.bind(this); - window.addEventListener(EV_CHANGE, this.listenerChange); + window.addEventListener(EV_CHANGE, this.listenerChange, true); }; Autocapture.prototype.initPageviewTracking = function() { @@ -410,7 +410,7 @@ Autocapture.prototype.initPageviewTracking = function() { }; Autocapture.prototype.initRageClickTracking = function() { - window.removeEventListener(EV_CLICK, this.listenerRageClick); + window.removeEventListener(EV_CLICK, this.listenerRageClick, true); var rageClickConfig = this._getClickTrackingConfig(CONFIG_TRACK_RAGE_CLICK); if (!rageClickConfig && !this.mp.get_config('record_heatmap_data')) { @@ -436,7 +436,7 @@ Autocapture.prototype.initRageClickTracking = function() { this.trackDomEvent(ev, MP_EV_RAGE_CLICK); } }.bind(this); - window.addEventListener(EV_CLICK, this.listenerRageClick); + window.addEventListener(EV_CLICK, this.listenerRageClick, true); }; Autocapture.prototype.initScrollTracking = function() { @@ -497,7 +497,7 @@ Autocapture.prototype.initScrollTracking = function() { }; Autocapture.prototype.initSubmitTracking = function() { - window.removeEventListener(EV_SUBMIT, this.listenerSubmit); + window.removeEventListener(EV_SUBMIT, this.listenerSubmit, true); if (!this.getConfig(CONFIG_TRACK_SUBMIT)) { return; @@ -510,7 +510,7 @@ Autocapture.prototype.initSubmitTracking = function() { } this.trackDomEvent(ev, MP_EV_SUBMIT); }.bind(this); - window.addEventListener(EV_SUBMIT, this.listenerSubmit); + window.addEventListener(EV_SUBMIT, this.listenerSubmit, true); }; Autocapture.prototype.initPageLeaveTracking = function() { @@ -566,7 +566,7 @@ Autocapture.prototype.initPageLeaveTracking = function() { Autocapture.prototype.stopDeadClickTracking = function() { if (this.listenerDeadClick) { - window.removeEventListener(EV_CLICK, this.listenerDeadClick); + window.removeEventListener(EV_CLICK, this.listenerDeadClick, true); this.listenerDeadClick = null; }