Skip to content

Commit 7fa4907

Browse files
rubennortemeta-codesync[bot]
authored andcommitted
Add cancelBubble to Event and adopt it in LegacySyntheticEvent (#57561)
Summary: Pull Request resolved: #57561 Implements the standard `cancelBubble` accessor on the `Event` interface and refactors the legacy synthetic event to rely on it instead of tracking propagation state on its own. - `Event` now exposes a `cancelBubble` getter/setter (per https://dom.spec.whatwg.org/#dom-event-cancelbubble): reading it returns the stop-propagation flag, setting it to `true` stops propagation, and setting it to `false` is a no-op. - `LegacySyntheticEvent` drops its private `_propagationStopped` field and the `stopPropagation()` / `stopImmediatePropagation()` overrides (the base `Event` already sets the stop-propagation flag), and `isPropagationStopped()` now returns `cancelBubble`. Changelog: [Internal] Reviewed By: cipolleschi Differential Revision: D112102632 fbshipit-source-id: 85c530239f5722c28a826867f97d7e60ea7dad5a
1 parent 30d9593 commit 7fa4907

3 files changed

Lines changed: 62 additions & 13 deletions

File tree

packages/react-native/src/private/renderer/events/LegacySyntheticEvent.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ export type DispatchConfig =
3131
*/
3232
export default class LegacySyntheticEvent extends Event {
3333
_nativeEvent: {[string]: unknown};
34-
_propagationStopped: boolean;
3534
_dispatchConfig: DispatchConfig | null;
3635

3736
constructor(
@@ -42,7 +41,6 @@ export default class LegacySyntheticEvent extends Event {
4241
) {
4342
super(type, options);
4443
this._nativeEvent = nativeEvent;
45-
this._propagationStopped = false;
4644
this._dispatchConfig = dispatchConfig ?? null;
4745
}
4846

@@ -54,16 +52,6 @@ export default class LegacySyntheticEvent extends Event {
5452
return this._dispatchConfig;
5553
}
5654

57-
stopPropagation(): void {
58-
super.stopPropagation();
59-
this._propagationStopped = true;
60-
}
61-
62-
stopImmediatePropagation(): void {
63-
super.stopImmediatePropagation();
64-
this._propagationStopped = true;
65-
}
66-
6755
/**
6856
* No-op for backward compatibility. The legacy SyntheticEvent system
6957
* used pooling which required calling persist() to keep the event.
@@ -85,6 +73,6 @@ export default class LegacySyntheticEvent extends Event {
8573
* has been called.
8674
*/
8775
isPropagationStopped(): boolean {
88-
return this._propagationStopped;
76+
return this.cancelBubble;
8977
}
9078
}

packages/react-native/src/private/webapis/dom/events/Event.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
getEventPhase,
3434
getInPassiveListenerFlag,
3535
getIsTrusted,
36+
getStopPropagationFlag,
3637
getTarget,
3738
setStopImmediatePropagationFlag,
3839
setStopPropagationFlag,
@@ -144,6 +145,22 @@ export default class Event {
144145
return this._cancelable;
145146
}
146147

148+
/**
149+
* Historical alias for the stop-propagation flag. Reading it returns whether
150+
* `stopPropagation()` has been called (or `cancelBubble` has been set to
151+
* `true`). Setting it to `true` stops propagation; setting it to `false` is a
152+
* no-op. See https://dom.spec.whatwg.org/#dom-event-cancelbubble.
153+
*/
154+
get cancelBubble(): boolean {
155+
return getStopPropagationFlag(this);
156+
}
157+
158+
set cancelBubble(value: boolean) {
159+
if (value) {
160+
setStopPropagationFlag(this, true);
161+
}
162+
}
163+
147164
get composed(): boolean {
148165
return this._composed;
149166
}

packages/react-native/src/private/webapis/dom/events/__tests__/Event-itest.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,4 +314,48 @@ describe('Event', () => {
314314
);
315315
});
316316
});
317+
318+
describe('cancelBubble', () => {
319+
it('defaults to false', () => {
320+
const event = new Event('custom');
321+
322+
expect(event.cancelBubble).toBe(false);
323+
});
324+
325+
it('stops propagation when set to true', () => {
326+
const event = new Event('custom');
327+
328+
event.cancelBubble = true;
329+
330+
expect(event.cancelBubble).toBe(true);
331+
});
332+
333+
it('is a no-op when set to false', () => {
334+
const event = new Event('custom');
335+
336+
event.cancelBubble = false;
337+
expect(event.cancelBubble).toBe(false);
338+
339+
// Setting it back to false does not reset a previously set flag.
340+
event.cancelBubble = true;
341+
event.cancelBubble = false;
342+
expect(event.cancelBubble).toBe(true);
343+
});
344+
345+
it('reflects stopPropagation()', () => {
346+
const event = new Event('custom');
347+
348+
event.stopPropagation();
349+
350+
expect(event.cancelBubble).toBe(true);
351+
});
352+
353+
it('reflects stopImmediatePropagation()', () => {
354+
const event = new Event('custom');
355+
356+
event.stopImmediatePropagation();
357+
358+
expect(event.cancelBubble).toBe(true);
359+
});
360+
});
317361
});

0 commit comments

Comments
 (0)