From 68a37c640785ea6fb7a1eb026544cc4cb78a9a0c Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Sun, 18 Feb 2024 18:04:31 +0100 Subject: [PATCH] Add support of onBeforeToggle and onToggle --- .../src/client/ReactDOMComponent.js | 12 +++++ .../src/events/DOMEventNames.js | 1 + .../src/events/DOMEventProperties.js | 1 + .../src/events/DOMPluginEventSystem.js | 1 + .../src/events/ReactDOMEventListener.js | 1 + .../ReactDOMEventPropagation-test.js | 46 +++++++++++++++++-- .../src/__tests__/ReactTestUtils-test.js | 1 + .../src/test-utils/ReactTestUtilsFB.js | 1 + 8 files changed, 59 insertions(+), 5 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactDOMComponent.js b/packages/react-dom-bindings/src/client/ReactDOMComponent.js index 673fd47eca464..2a26580225365 100644 --- a/packages/react-dom-bindings/src/client/ReactDOMComponent.js +++ b/packages/react-dom-bindings/src/client/ReactDOMComponent.js @@ -770,6 +770,11 @@ function setProp( } break; } + case 'popover': + listenToNonDelegatedEvent('beforetoggle', domElement); + listenToNonDelegatedEvent('toggle', domElement); + setValueForAttribute(domElement, 'popover', value); + break; case 'xlinkActuate': setValueForNamespacedAttribute( domElement, @@ -2953,6 +2958,13 @@ export function hydrateProperties( } } + if (props.popover != null) { + // We listen to this event in case to ensure emulated bubble + // listeners still fire for the toggle event. + listenToNonDelegatedEvent('beforetoggle', domElement); + listenToNonDelegatedEvent('toggle', domElement); + } + if (props.onScroll != null) { listenToNonDelegatedEvent('scroll', domElement); } diff --git a/packages/react-dom-bindings/src/events/DOMEventNames.js b/packages/react-dom-bindings/src/events/DOMEventNames.js index 7b9825040c310..73f0e2f632c55 100644 --- a/packages/react-dom-bindings/src/events/DOMEventNames.js +++ b/packages/react-dom-bindings/src/events/DOMEventNames.js @@ -18,6 +18,7 @@ export type DOMEventName = // 'animationstart' | | 'beforeblur' // Not a real event. This is used by event experiments. | 'beforeinput' + | 'beforetoggle' | 'blur' | 'canplay' | 'canplaythrough' diff --git a/packages/react-dom-bindings/src/events/DOMEventProperties.js b/packages/react-dom-bindings/src/events/DOMEventProperties.js index 27961ddfc284e..7dc4bee901076 100644 --- a/packages/react-dom-bindings/src/events/DOMEventProperties.js +++ b/packages/react-dom-bindings/src/events/DOMEventProperties.js @@ -37,6 +37,7 @@ export const topLevelEventsToReactNames: Map = const simpleEventPluginEvents = [ 'abort', 'auxClick', + 'beforeToggle', 'cancel', 'canPlay', 'canPlayThrough', diff --git a/packages/react-dom-bindings/src/events/DOMPluginEventSystem.js b/packages/react-dom-bindings/src/events/DOMPluginEventSystem.js index 7e7221a6d393f..fe007b6209a5d 100644 --- a/packages/react-dom-bindings/src/events/DOMPluginEventSystem.js +++ b/packages/react-dom-bindings/src/events/DOMPluginEventSystem.js @@ -214,6 +214,7 @@ export const mediaEventTypes: Array = [ // set them on the actual target element itself. This is primarily // because these events do not consistently bubble in the DOM. export const nonDelegatedEvents: Set = new Set([ + 'beforetoggle', 'cancel', 'close', 'invalid', diff --git a/packages/react-dom-bindings/src/events/ReactDOMEventListener.js b/packages/react-dom-bindings/src/events/ReactDOMEventListener.js index 9f8601bb1d75e..00916f6c0d2d1 100644 --- a/packages/react-dom-bindings/src/events/ReactDOMEventListener.js +++ b/packages/react-dom-bindings/src/events/ReactDOMEventListener.js @@ -345,6 +345,7 @@ export function getEventPriority(domEventName: DOMEventName): EventPriority { case 'select': case 'selectstart': return DiscreteEventPriority; + case 'beforetoggle': case 'drag': case 'dragenter': case 'dragexit': diff --git a/packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js b/packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js index de19f1ecf43c5..1598329340073 100644 --- a/packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js @@ -1268,6 +1268,40 @@ describe('ReactDOMEventListener', () => { }); }); + it('onBeforeToggle Popover API', async () => { + await testEmulatedBubblingEvent({ + type: 'div', + targetProps: {popover: 'any'}, + reactEvent: 'onBeforeToggle', + reactEventType: 'beforetoggle', + nativeEvent: 'beforetoggle', + dispatch(node) { + const e = new Event('beforetoggle', { + bubbles: false, + cancelable: true, + }); + node.dispatchEvent(e); + }, + }); + }); + + it('onToggle Popover API', async () => { + await testEmulatedBubblingEvent({ + type: 'div', + targetProps: {popover: 'any'}, + reactEvent: 'onToggle', + reactEventType: 'toggle', + nativeEvent: 'toggle', + dispatch(node) { + const e = new Event('toggle', { + bubbles: false, + cancelable: true, + }); + node.dispatchEvent(e); + }, + }); + }); + it('onVolumeChange', async () => { await testEmulatedBubblingEvent({ type: 'video', @@ -1969,6 +2003,7 @@ describe('ReactDOMEventListener', () => { type={eventConfig.type} targetRef={targetRef} targetProps={{ + ...eventConfig.targetProps, [eventConfig.reactEvent]: e => { log.push('---- inner'); }, @@ -2135,11 +2170,10 @@ describe('ReactDOMEventListener', () => { { log.push('--- inner parent'); @@ -2368,6 +2402,7 @@ describe('ReactDOMEventListener', () => { type={eventConfig.type} targetRef={targetRef} targetProps={{ + ...eventConfig.targetProps, [eventConfig.reactEvent]: e => { e.stopPropagation(); // <--------- log.push('---- inner'); @@ -2705,6 +2740,7 @@ describe('ReactDOMEventListener', () => { } }} targetProps={{ + ...eventConfig.targetProps, [eventConfig.reactEvent]: e => { log.push('---- inner'); }, diff --git a/packages/react-dom/src/__tests__/ReactTestUtils-test.js b/packages/react-dom/src/__tests__/ReactTestUtils-test.js index 927998afc2f91..534b3538eb49b 100644 --- a/packages/react-dom/src/__tests__/ReactTestUtils-test.js +++ b/packages/react-dom/src/__tests__/ReactTestUtils-test.js @@ -45,6 +45,7 @@ describe('ReactTestUtils', () => { "animationStart", "auxClick", "beforeInput", + "beforeToggle", "blur", "canPlay", "canPlayThrough", diff --git a/packages/react-dom/src/test-utils/ReactTestUtilsFB.js b/packages/react-dom/src/test-utils/ReactTestUtilsFB.js index ad9a18d58abda..39ac99c3bc100 100644 --- a/packages/react-dom/src/test-utils/ReactTestUtilsFB.js +++ b/packages/react-dom/src/test-utils/ReactTestUtilsFB.js @@ -850,6 +850,7 @@ const simulatedEventTypes = [ 'change', 'select', 'beforeInput', + 'beforeToggle', 'compositionEnd', 'compositionStart', 'compositionUpdate',