From 5ec46b2f906d4af192e095df31f74448f0f77b05 Mon Sep 17 00:00:00 2001 From: Riley Shaw Date: Tue, 27 Jul 2021 14:53:33 -0400 Subject: [PATCH 1/2] Fix #21972: Add `onResize` event to video elements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a simple fix for #21972 that adds support for the `onResize` media event. I created a separate `videoEventTypes` array since I doubt anyone will want to add `onResize` to an audio event. It would simplify the code a bit to just add `resize` to the `mediaEventTypes` array, if that’s preferred. Pre-commit checklist ([source](https://reactjs.org/docs/how-to-contribute.html#sending-a-pull-request)) ✅ Fork the repository and create your branch from `main`. ✅ Run `yarn` in the repository root. ✅ If you’ve fixed a bug or added code that should be tested, add tests! ✅ Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch TestName` is helpful in development. ✅ Run `yarn test --prod` to test in the production environment. ✅ If you need a debugger, run `yarn debug-test --watch TestName`, open chrome://inspect, and press “Inspect”. ✅ Format your code with prettier (`yarn prettier`). ✅ Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only check changed files. ✅ Run the Flow typechecks (`yarn flow`). ✅ If you haven’t already, complete the CLA. --- .../components/fixtures/media-events/index.js | 1 + .../src/__tests__/ReactDOMEventListener-test.js | 2 ++ .../__tests__/ReactDOMEventPropagation-test.js | 16 ++++++++++++++++ .../__snapshots__/ReactTestUtils-test.js.snap | 1 + .../react-dom/src/client/ReactDOMComponent.js | 9 +++++++++ packages/react-dom/src/events/DOMEventNames.js | 1 + .../react-dom/src/events/DOMEventProperties.js | 1 + .../react-dom/src/events/DOMPluginEventSystem.js | 4 ++++ .../src/events/ReactDOMEventListener.js | 1 + .../react-dom/src/events/TopLevelEventTypes.js | 1 + .../react-dom/src/test-utils/ReactTestUtils.js | 1 + 11 files changed, 38 insertions(+) diff --git a/fixtures/dom/src/components/fixtures/media-events/index.js b/fixtures/dom/src/components/fixtures/media-events/index.js index fda46dce8e069..cdb6147f86c88 100644 --- a/fixtures/dom/src/components/fixtures/media-events/index.js +++ b/fixtures/dom/src/components/fixtures/media-events/index.js @@ -21,6 +21,7 @@ export default class MediaEvents extends React.Component { onPlaying: false, onProgress: false, onRateChange: false, + onResize: false, onSeeked: false, onSeeking: false, onSuspend: false, diff --git a/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js b/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js index 42e73d58f1546..f41ca857946a1 100644 --- a/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js @@ -388,6 +388,7 @@ describe('ReactDOMEventListener', () => { onPlaying() {}, onProgress() {}, onRateChange() {}, + onResize() {}, onSeeked() {}, onSeeking() {}, onStalled() {}, @@ -430,6 +431,7 @@ describe('ReactDOMEventListener', () => { case 'playing': case 'progress': case 'ratechange': + case 'resize': case 'seeked': case 'seeking': case 'stalled': diff --git a/packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js b/packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js index 06fb657227842..7c28b7bb905b0 100644 --- a/packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js @@ -1095,6 +1095,22 @@ describe('ReactDOMEventListener', () => { }); }); + it('onResize', () => { + testEmulatedBubblingEvent({ + type: 'video', + reactEvent: 'onResize', + reactEventType: 'resize', + nativeEvent: 'resize', + dispatch(node) { + const e = new Event('resize', { + bubbles: false, + cancelable: true, + }); + node.dispatchEvent(e); + }, + }); + }); + it('onSeeked', () => { testEmulatedBubblingEvent({ type: 'video', diff --git a/packages/react-dom/src/__tests__/__snapshots__/ReactTestUtils-test.js.snap b/packages/react-dom/src/__tests__/__snapshots__/ReactTestUtils-test.js.snap index 9f37f55219be9..91b25eb20bc58 100644 --- a/packages/react-dom/src/__tests__/__snapshots__/ReactTestUtils-test.js.snap +++ b/packages/react-dom/src/__tests__/__snapshots__/ReactTestUtils-test.js.snap @@ -69,6 +69,7 @@ Array [ "progress", "rateChange", "reset", + "resize", "scroll", "seeked", "seeking", diff --git a/packages/react-dom/src/client/ReactDOMComponent.js b/packages/react-dom/src/client/ReactDOMComponent.js index 7820978957107..bd813087d1222 100644 --- a/packages/react-dom/src/client/ReactDOMComponent.js +++ b/packages/react-dom/src/client/ReactDOMComponent.js @@ -71,6 +71,7 @@ import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols'; import {enableTrustedTypesIntegration} from 'shared/ReactFeatureFlags'; import { + videoEventTypes, mediaEventTypes, listenToNonDelegatedEvent, } from '../events/DOMPluginEventSystem'; @@ -496,6 +497,10 @@ export function setInitialProperties( props = rawProps; break; case 'video': + for (let i = 0; i < videoEventTypes.length; i++) { + listenToNonDelegatedEvent(videoEventTypes[i], domElement); + } + // falls through case 'audio': // We listen to these events in case to ensure emulated bubble // listeners still fire for all the media events. @@ -885,6 +890,10 @@ export function diffHydratedProperties( listenToNonDelegatedEvent('load', domElement); break; case 'video': + for (let i = 0; i < videoEventTypes.length; i++) { + listenToNonDelegatedEvent(videoEventTypes[i], domElement); + } + // falls through case 'audio': // We listen to these events in case to ensure emulated bubble // listeners still fire for all the media events. diff --git a/packages/react-dom/src/events/DOMEventNames.js b/packages/react-dom/src/events/DOMEventNames.js index 2e14ddf7822bf..92310e5128e93 100644 --- a/packages/react-dom/src/events/DOMEventNames.js +++ b/packages/react-dom/src/events/DOMEventNames.js @@ -86,6 +86,7 @@ export type DOMEventName = | 'progress' | 'ratechange' | 'reset' + | 'resize' | 'scroll' | 'seeked' | 'seeking' diff --git a/packages/react-dom/src/events/DOMEventProperties.js b/packages/react-dom/src/events/DOMEventProperties.js index a9b22ae8a3e21..a4ed6fcd575c3 100644 --- a/packages/react-dom/src/events/DOMEventProperties.js +++ b/packages/react-dom/src/events/DOMEventProperties.js @@ -86,6 +86,7 @@ const simpleEventPluginEvents = [ 'progress', 'rateChange', 'reset', + 'resize', 'seeked', 'seeking', 'stalled', diff --git a/packages/react-dom/src/events/DOMPluginEventSystem.js b/packages/react-dom/src/events/DOMPluginEventSystem.js index 0583916988e06..aaf334877b24e 100644 --- a/packages/react-dom/src/events/DOMPluginEventSystem.js +++ b/packages/react-dom/src/events/DOMPluginEventSystem.js @@ -201,6 +201,9 @@ export const mediaEventTypes: Array = [ 'waiting', ]; +// List of events that need to be individually attached to video elements. +export const videoEventTypes: Array = ['resize']; + // We should not delegate these events to the container, but rather // set them on the actual target element itself. This is primarily // because these events do not consistently bubble in the DOM. @@ -216,6 +219,7 @@ export const nonDelegatedEvents: Set = new Set([ // and can occur on other elements too. Rather than duplicate that event, // we just take it from the media events array. ...mediaEventTypes, + ...videoEventTypes, ]); function executeDispatch( diff --git a/packages/react-dom/src/events/ReactDOMEventListener.js b/packages/react-dom/src/events/ReactDOMEventListener.js index f3a7b974dfe99..d688521726c0d 100644 --- a/packages/react-dom/src/events/ReactDOMEventListener.js +++ b/packages/react-dom/src/events/ReactDOMEventListener.js @@ -321,6 +321,7 @@ export function getEventPriority(domEventName: DOMEventName): * { case 'pointerup': case 'ratechange': case 'reset': + case 'resize': case 'seeked': case 'submit': case 'touchcancel': diff --git a/packages/react-dom/src/events/TopLevelEventTypes.js b/packages/react-dom/src/events/TopLevelEventTypes.js index 9b2a3e4f9a63b..447ab030358d1 100644 --- a/packages/react-dom/src/events/TopLevelEventTypes.js +++ b/packages/react-dom/src/events/TopLevelEventTypes.js @@ -71,6 +71,7 @@ export type TopLevelType = | 'progress' | 'ratechange' | 'reset' + | 'resize' | 'scroll' | 'seeked' | 'seeking' diff --git a/packages/react-dom/src/test-utils/ReactTestUtils.js b/packages/react-dom/src/test-utils/ReactTestUtils.js index f93c92a93767c..bc913d160b68c 100644 --- a/packages/react-dom/src/test-utils/ReactTestUtils.js +++ b/packages/react-dom/src/test-utils/ReactTestUtils.js @@ -642,6 +642,7 @@ const simulatedEventTypes = [ 'pointerUp', 'rateChange', 'reset', + 'resize', 'seeked', 'submit', 'touchCancel', From 3c336f015f73a1e7becda2d8f167c9e62cd3f6d5 Mon Sep 17 00:00:00 2001 From: Riley Shaw Date: Tue, 7 Sep 2021 17:10:18 -0400 Subject: [PATCH 2/2] Consolidate `videoEventTypes` array into `mediaEventTypes` --- packages/react-dom/src/client/ReactDOMComponent.js | 9 --------- packages/react-dom/src/events/DOMPluginEventSystem.js | 5 +---- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/packages/react-dom/src/client/ReactDOMComponent.js b/packages/react-dom/src/client/ReactDOMComponent.js index bd813087d1222..7820978957107 100644 --- a/packages/react-dom/src/client/ReactDOMComponent.js +++ b/packages/react-dom/src/client/ReactDOMComponent.js @@ -71,7 +71,6 @@ import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols'; import {enableTrustedTypesIntegration} from 'shared/ReactFeatureFlags'; import { - videoEventTypes, mediaEventTypes, listenToNonDelegatedEvent, } from '../events/DOMPluginEventSystem'; @@ -497,10 +496,6 @@ export function setInitialProperties( props = rawProps; break; case 'video': - for (let i = 0; i < videoEventTypes.length; i++) { - listenToNonDelegatedEvent(videoEventTypes[i], domElement); - } - // falls through case 'audio': // We listen to these events in case to ensure emulated bubble // listeners still fire for all the media events. @@ -890,10 +885,6 @@ export function diffHydratedProperties( listenToNonDelegatedEvent('load', domElement); break; case 'video': - for (let i = 0; i < videoEventTypes.length; i++) { - listenToNonDelegatedEvent(videoEventTypes[i], domElement); - } - // falls through case 'audio': // We listen to these events in case to ensure emulated bubble // listeners still fire for all the media events. diff --git a/packages/react-dom/src/events/DOMPluginEventSystem.js b/packages/react-dom/src/events/DOMPluginEventSystem.js index aaf334877b24e..7f7f77183726a 100644 --- a/packages/react-dom/src/events/DOMPluginEventSystem.js +++ b/packages/react-dom/src/events/DOMPluginEventSystem.js @@ -192,6 +192,7 @@ export const mediaEventTypes: Array = [ 'playing', 'progress', 'ratechange', + 'resize', 'seeked', 'seeking', 'stalled', @@ -201,9 +202,6 @@ export const mediaEventTypes: Array = [ 'waiting', ]; -// List of events that need to be individually attached to video elements. -export const videoEventTypes: Array = ['resize']; - // We should not delegate these events to the container, but rather // set them on the actual target element itself. This is primarily // because these events do not consistently bubble in the DOM. @@ -219,7 +217,6 @@ export const nonDelegatedEvents: Set = new Set([ // and can occur on other elements too. Rather than duplicate that event, // we just take it from the media events array. ...mediaEventTypes, - ...videoEventTypes, ]); function executeDispatch(