From dfd3d5af83cadd9bfc904c0a62a30adc20e414c9 Mon Sep 17 00:00:00 2001 From: Hugo Sales Date: Mon, 8 Apr 2024 21:23:04 +0000 Subject: [PATCH] Add support for transition{run,start,cancel} events (#27345) --- .../src/events/DOMEventNames.js | 10 ++++ .../src/events/DOMEventProperties.js | 7 +++ .../src/events/getVendorPrefixedEventName.js | 3 ++ .../ReactDOMEventPropagation-test.js | 53 ++++++++++++++++++- .../src/__tests__/ReactTestUtils-test.js | 3 ++ .../src/test-utils/ReactTestUtilsFB.js | 3 ++ 6 files changed, 78 insertions(+), 1 deletion(-) diff --git a/packages/react-dom-bindings/src/events/DOMEventNames.js b/packages/react-dom-bindings/src/events/DOMEventNames.js index 9145e316f9d1f..7b9825040c310 100644 --- a/packages/react-dom-bindings/src/events/DOMEventNames.js +++ b/packages/react-dom-bindings/src/events/DOMEventNames.js @@ -105,6 +105,9 @@ export type DOMEventName = | 'touchmove' | 'touchstart' // These are vendor-prefixed so you should use the exported constants instead: + // 'transitionrun' | + // 'transitionstart' | + // 'transitioncancel' | // 'transitionend' | | 'volumechange' | 'waiting' @@ -116,5 +119,12 @@ export const ANIMATION_ITERATION: DOMEventName = getVendorPrefixedEventName('animationiteration'); export const ANIMATION_START: DOMEventName = getVendorPrefixedEventName('animationstart'); + +export const TRANSITION_RUN: DOMEventName = + getVendorPrefixedEventName('transitionrun'); +export const TRANSITION_START: DOMEventName = + getVendorPrefixedEventName('transitionstart'); +export const TRANSITION_CANCEL: DOMEventName = + getVendorPrefixedEventName('transitioncancel'); export const TRANSITION_END: DOMEventName = getVendorPrefixedEventName('transitionend'); diff --git a/packages/react-dom-bindings/src/events/DOMEventProperties.js b/packages/react-dom-bindings/src/events/DOMEventProperties.js index 55b3c4f987186..27961ddfc284e 100644 --- a/packages/react-dom-bindings/src/events/DOMEventProperties.js +++ b/packages/react-dom-bindings/src/events/DOMEventProperties.js @@ -14,6 +14,9 @@ import { ANIMATION_END, ANIMATION_ITERATION, ANIMATION_START, + TRANSITION_RUN, + TRANSITION_START, + TRANSITION_CANCEL, TRANSITION_END, } from './DOMEventNames'; @@ -129,5 +132,9 @@ export function registerSimpleEvents() { registerSimpleEvent('dblclick', 'onDoubleClick'); registerSimpleEvent('focusin', 'onFocus'); registerSimpleEvent('focusout', 'onBlur'); + + registerSimpleEvent(TRANSITION_RUN, 'onTransitionRun'); + registerSimpleEvent(TRANSITION_START, 'onTransitionStart'); + registerSimpleEvent(TRANSITION_CANCEL, 'onTransitionCancel'); registerSimpleEvent(TRANSITION_END, 'onTransitionEnd'); } diff --git a/packages/react-dom-bindings/src/events/getVendorPrefixedEventName.js b/packages/react-dom-bindings/src/events/getVendorPrefixedEventName.js index bf0a62db53cd5..16655f71b27e6 100644 --- a/packages/react-dom-bindings/src/events/getVendorPrefixedEventName.js +++ b/packages/react-dom-bindings/src/events/getVendorPrefixedEventName.js @@ -31,6 +31,9 @@ const vendorPrefixes = { animationend: makePrefixMap('Animation', 'AnimationEnd'), animationiteration: makePrefixMap('Animation', 'AnimationIteration'), animationstart: makePrefixMap('Animation', 'AnimationStart'), + transitionrun: makePrefixMap('Transition', 'TransitionRun'), + transitionstart: makePrefixMap('Transition', 'TransitionStart'), + transitioncancel: makePrefixMap('Transition', 'TransitionCancel'), transitionend: makePrefixMap('Transition', 'TransitionEnd'), }; diff --git a/packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js b/packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js index b90ca9efdb32e..de19f1ecf43c5 100644 --- a/packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js @@ -749,6 +749,57 @@ describe('ReactDOMEventListener', () => { }); }); + it('onTransitionRun', async () => { + await testNativeBubblingEvent({ + type: 'div', + reactEvent: 'onTransitionRun', + reactEventType: 'transitionrun', + nativeEvent: 'transitionrun', + dispatch(node) { + node.dispatchEvent( + new Event('transitionrun', { + bubbles: true, + cancelable: false, + }), + ); + }, + }); + }); + + it('onTransitionStart', async () => { + await testNativeBubblingEvent({ + type: 'div', + reactEvent: 'onTransitionStart', + reactEventType: 'transitionstart', + nativeEvent: 'transitionstart', + dispatch(node) { + node.dispatchEvent( + new Event('transitionstart', { + bubbles: true, + cancelable: false, + }), + ); + }, + }); + }); + + it('onTransitionCancel', async () => { + await testNativeBubblingEvent({ + type: 'div', + reactEvent: 'onTransitionCancel', + reactEventType: 'transitioncancel', + nativeEvent: 'transitioncancel', + dispatch(node) { + node.dispatchEvent( + new Event('transitioncancel', { + bubbles: true, + cancelable: false, + }), + ); + }, + }); + }); + it('onTransitionEnd', async () => { await testNativeBubblingEvent({ type: 'div', @@ -759,7 +810,7 @@ describe('ReactDOMEventListener', () => { node.dispatchEvent( new Event('transitionend', { bubbles: true, - cancelable: true, + cancelable: false, }), ); }, diff --git a/packages/react-dom/src/__tests__/ReactTestUtils-test.js b/packages/react-dom/src/__tests__/ReactTestUtils-test.js index 842fb4c1ebc72..927998afc2f91 100644 --- a/packages/react-dom/src/__tests__/ReactTestUtils-test.js +++ b/packages/react-dom/src/__tests__/ReactTestUtils-test.js @@ -120,7 +120,10 @@ describe('ReactTestUtils', () => { "touchEnd", "touchMove", "touchStart", + "transitionCancel", "transitionEnd", + "transitionRun", + "transitionStart", "volumeChange", "waiting", "wheel", diff --git a/packages/react-dom/src/test-utils/ReactTestUtilsFB.js b/packages/react-dom/src/test-utils/ReactTestUtilsFB.js index 1b4125c819e61..0c82865384b9e 100644 --- a/packages/react-dom/src/test-utils/ReactTestUtilsFB.js +++ b/packages/react-dom/src/test-utils/ReactTestUtilsFB.js @@ -838,6 +838,9 @@ const simulatedEventTypes = [ 'stalled', 'suspend', 'timeUpdate', + 'transitionRun', + 'transitionStart', + 'transitionCancel', 'transitionEnd', 'waiting', 'mouseEnter',