From 3b375ee3952f98278d235fe3fad04ee836169a62 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 22 May 2023 15:48:01 +0200 Subject: [PATCH] [Glitch] Upgrade to React 18 Port 8d6aea33260dedeacb3d22ac1a6d2f9cc3856a5e to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/components/column.jsx | 10 ++++++---- .../flavours/glitch/components/dropdown_menu.jsx | 11 ++++++----- .../flavours/glitch/components/scrollable_list.jsx | 10 ++++++---- .../flavours/glitch/containers/media_container.jsx | 4 ++-- .../features/compose/components/dropdown_menu.jsx | 13 +++++++------ .../compose/components/emoji_picker_dropdown.jsx | 10 +++++----- .../compose/components/language_dropdown.jsx | 7 ++++--- app/javascript/flavours/glitch/main.jsx | 5 +++-- app/javascript/flavours/glitch/packs/admin.jsx | 10 ++++++---- app/javascript/flavours/glitch/packs/public.jsx | 5 +++-- app/javascript/flavours/glitch/packs/share.jsx | 7 ++++--- app/javascript/flavours/glitch/utils/dom_helpers.js | 4 ---- 12 files changed, 52 insertions(+), 44 deletions(-) diff --git a/app/javascript/flavours/glitch/components/column.jsx b/app/javascript/flavours/glitch/components/column.jsx index 47293ef18e..fce6a6c408 100644 --- a/app/javascript/flavours/glitch/components/column.jsx +++ b/app/javascript/flavours/glitch/components/column.jsx @@ -3,6 +3,8 @@ import PropTypes from 'prop-types'; import { supportsPassiveEvents } from 'detect-passive-events'; import { scrollTop } from '../scroll'; +const listenerOptions = supportsPassiveEvents ? { passive: true } : false; + export default class Column extends React.PureComponent { static propTypes = { @@ -37,17 +39,17 @@ export default class Column extends React.PureComponent { componentDidMount () { if (this.props.bindToDocument) { - document.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : false); + document.addEventListener('wheel', this.handleWheel, listenerOptions); } else { - this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : false); + this.node.addEventListener('wheel', this.handleWheel, listenerOptions); } } componentWillUnmount () { if (this.props.bindToDocument) { - document.removeEventListener('wheel', this.handleWheel); + document.removeEventListener('wheel', this.handleWheel, listenerOptions); } else { - this.node.removeEventListener('wheel', this.handleWheel); + this.node.removeEventListener('wheel', this.handleWheel, listenerOptions); } } diff --git a/app/javascript/flavours/glitch/components/dropdown_menu.jsx b/app/javascript/flavours/glitch/components/dropdown_menu.jsx index 3f17bc1299..901c7fe22f 100644 --- a/app/javascript/flavours/glitch/components/dropdown_menu.jsx +++ b/app/javascript/flavours/glitch/components/dropdown_menu.jsx @@ -7,7 +7,7 @@ import { supportsPassiveEvents } from 'detect-passive-events'; import classNames from 'classnames'; import { CircularProgress } from 'flavours/glitch/components/loading_indicator'; -const listenerOptions = supportsPassiveEvents ? { passive: true } : false; +const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true; let id = 0; class DropdownMenu extends React.PureComponent { @@ -35,12 +35,13 @@ class DropdownMenu extends React.PureComponent { handleDocumentClick = e => { if (this.node && !this.node.contains(e.target)) { this.props.onClose(); + e.stopPropagation(); } }; componentDidMount () { - document.addEventListener('click', this.handleDocumentClick, false); - document.addEventListener('keydown', this.handleKeyDown, false); + document.addEventListener('click', this.handleDocumentClick, { capture: true }); + document.addEventListener('keydown', this.handleKeyDown, { capture: true }); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); if (this.focusedItem && this.props.openedViaKeyboard) { @@ -49,8 +50,8 @@ class DropdownMenu extends React.PureComponent { } componentWillUnmount () { - document.removeEventListener('click', this.handleDocumentClick, false); - document.removeEventListener('keydown', this.handleKeyDown, false); + document.removeEventListener('click', this.handleDocumentClick, { capture: true }); + document.removeEventListener('keydown', this.handleKeyDown, { capture: true }); document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions); } diff --git a/app/javascript/flavours/glitch/components/scrollable_list.jsx b/app/javascript/flavours/glitch/components/scrollable_list.jsx index 13701bcd3e..69925321bd 100644 --- a/app/javascript/flavours/glitch/components/scrollable_list.jsx +++ b/app/javascript/flavours/glitch/components/scrollable_list.jsx @@ -15,6 +15,8 @@ import { connect } from 'react-redux'; const MOUSE_IDLE_DELAY = 300; +const listenerOptions = supportsPassiveEvents ? { passive: true } : false; + const mapStateToProps = (state, { scrollKey }) => { return { preventScroll: scrollKey === state.getIn(['dropdown_menu', 'scroll_key']), @@ -237,20 +239,20 @@ class ScrollableList extends PureComponent { attachScrollListener () { if (this.props.bindToDocument) { document.addEventListener('scroll', this.handleScroll); - document.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : undefined); + document.addEventListener('wheel', this.handleWheel, listenerOptions); } else { this.node.addEventListener('scroll', this.handleScroll); - this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : undefined); + this.node.addEventListener('wheel', this.handleWheel, listenerOptions); } } detachScrollListener () { if (this.props.bindToDocument) { document.removeEventListener('scroll', this.handleScroll); - document.removeEventListener('wheel', this.handleWheel); + document.removeEventListener('wheel', this.handleWheel, listenerOptions); } else { this.node.removeEventListener('scroll', this.handleScroll); - this.node.removeEventListener('wheel', this.handleWheel); + this.node.removeEventListener('wheel', this.handleWheel, listenerOptions); } } diff --git a/app/javascript/flavours/glitch/containers/media_container.jsx b/app/javascript/flavours/glitch/containers/media_container.jsx index 06db0a0030..99e1ed55c3 100644 --- a/app/javascript/flavours/glitch/containers/media_container.jsx +++ b/app/javascript/flavours/glitch/containers/media_container.jsx @@ -1,5 +1,5 @@ import React, { PureComponent, Fragment } from 'react'; -import ReactDOM from 'react-dom'; +import { createPortal } from 'react-dom'; import PropTypes from 'prop-types'; import { IntlProvider, addLocaleData } from 'react-intl'; import { fromJS } from 'immutable'; @@ -95,7 +95,7 @@ export default class MediaContainer extends PureComponent { }), }); - return ReactDOM.createPortal( + return createPortal( , component, ); diff --git a/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.jsx b/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.jsx index 786f593070..28f316619c 100644 --- a/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.jsx @@ -2,12 +2,12 @@ import PropTypes from 'prop-types'; import React from 'react'; import classNames from 'classnames'; +import { supportsPassiveEvents } from 'detect-passive-events'; // Components. import { Icon } from 'flavours/glitch/components/icon'; -// Utils. -import { withPassive } from 'flavours/glitch/utils/dom_helpers'; +const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true; // The component. export default class ComposerOptionsDropdownContent extends React.PureComponent { @@ -41,6 +41,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent handleDocumentClick = (e) => { if (this.node && !this.node.contains(e.target)) { this.props.onClose(); + e.stopPropagation(); } }; @@ -51,8 +52,8 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent // On mounting, we add our listeners. componentDidMount () { - document.addEventListener('click', this.handleDocumentClick, false); - document.addEventListener('touchend', this.handleDocumentClick, withPassive); + document.addEventListener('click', this.handleDocumentClick, { capture: true }); + document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); if (this.focusedItem) { this.focusedItem.focus({ preventScroll: true }); } else { @@ -62,8 +63,8 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent // On unmounting, we remove our listeners. componentWillUnmount () { - document.removeEventListener('click', this.handleDocumentClick, false); - document.removeEventListener('touchend', this.handleDocumentClick, withPassive); + document.removeEventListener('click', this.handleDocumentClick, { capture: true }); + document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions); } handleClick = (e) => { diff --git a/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.jsx b/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.jsx index 7526899305..68ff37b80e 100644 --- a/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.jsx @@ -28,7 +28,7 @@ const messages = defineMessages({ let EmojiPicker, Emoji; // load asynchronously -const listenerOptions = supportsPassiveEvents ? { passive: true } : false; +const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true; const backgroundImageFn = () => `${assetHost}/emoji/sheet_13.png`; @@ -79,12 +79,12 @@ class ModifierPickerMenu extends React.PureComponent { }; attachListeners () { - document.addEventListener('click', this.handleDocumentClick, false); + document.addEventListener('click', this.handleDocumentClick, { capture: true }); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); } removeListeners () { - document.removeEventListener('click', this.handleDocumentClick, false); + document.removeEventListener('click', this.handleDocumentClick, { capture: true }); document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions); } @@ -177,7 +177,7 @@ class EmojiPickerMenuImpl extends React.PureComponent { }; componentDidMount () { - document.addEventListener('click', this.handleDocumentClick, false); + document.addEventListener('click', this.handleDocumentClick, { capture: true }); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); // Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need @@ -192,7 +192,7 @@ class EmojiPickerMenuImpl extends React.PureComponent { } componentWillUnmount () { - document.removeEventListener('click', this.handleDocumentClick, false); + document.removeEventListener('click', this.handleDocumentClick, { capture: true }); document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions); } diff --git a/app/javascript/flavours/glitch/features/compose/components/language_dropdown.jsx b/app/javascript/flavours/glitch/features/compose/components/language_dropdown.jsx index 05614de011..2d4ae72d40 100644 --- a/app/javascript/flavours/glitch/features/compose/components/language_dropdown.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/language_dropdown.jsx @@ -15,7 +15,7 @@ const messages = defineMessages({ clear: { id: 'emoji_button.clear', defaultMessage: 'Clear' }, }); -const listenerOptions = supportsPassiveEvents ? { passive: true } : false; +const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true; class LanguageDropdownMenu extends React.PureComponent { @@ -39,11 +39,12 @@ class LanguageDropdownMenu extends React.PureComponent { handleDocumentClick = e => { if (this.node && !this.node.contains(e.target)) { this.props.onClose(); + e.stopPropagation(); } }; componentDidMount () { - document.addEventListener('click', this.handleDocumentClick, false); + document.addEventListener('click', this.handleDocumentClick, { capture: true }); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); // Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need @@ -57,7 +58,7 @@ class LanguageDropdownMenu extends React.PureComponent { } componentWillUnmount () { - document.removeEventListener('click', this.handleDocumentClick, false); + document.removeEventListener('click', this.handleDocumentClick, { capture: true }); document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions); } diff --git a/app/javascript/flavours/glitch/main.jsx b/app/javascript/flavours/glitch/main.jsx index 1ac7d579ec..63195518be 100644 --- a/app/javascript/flavours/glitch/main.jsx +++ b/app/javascript/flavours/glitch/main.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import { setupBrowserNotifications } from 'flavours/glitch/actions/notifications'; import Mastodon from 'flavours/glitch/containers/mastodon'; import { store } from 'flavours/glitch/store'; @@ -18,7 +18,8 @@ function main() { const mountNode = document.getElementById('mastodon'); const props = JSON.parse(mountNode.getAttribute('data-props')); - ReactDOM.render(, mountNode); + const root = createRoot(mountNode); + root.render(); store.dispatch(setupBrowserNotifications()); if (process.env.NODE_ENV === 'production' && me && 'serviceWorker' in navigator) { diff --git a/app/javascript/flavours/glitch/packs/admin.jsx b/app/javascript/flavours/glitch/packs/admin.jsx index 7544ae4e97..7b0917df85 100644 --- a/app/javascript/flavours/glitch/packs/admin.jsx +++ b/app/javascript/flavours/glitch/packs/admin.jsx @@ -1,7 +1,7 @@ import 'packs/public-path'; import ready from 'flavours/glitch/ready'; import React from 'react'; -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; ready(() => { [].forEach.call(document.querySelectorAll('[data-admin-component]'), element => { @@ -10,11 +10,13 @@ ready(() => { import('flavours/glitch/containers/admin_component').then(({ default: AdminComponent }) => { return import('flavours/glitch/components/admin/' + componentName).then(({ default: Component }) => { - ReactDOM.render(( + const root = createRoot(element); + + root.render ( - - ), element); + , + ); }); }).catch(error => { console.error(error); diff --git a/app/javascript/flavours/glitch/packs/public.jsx b/app/javascript/flavours/glitch/packs/public.jsx index 34a8f35133..7bb85fd2f9 100644 --- a/app/javascript/flavours/glitch/packs/public.jsx +++ b/app/javascript/flavours/glitch/packs/public.jsx @@ -11,7 +11,7 @@ import { delegate } from '@rails/ujs'; import emojify from 'flavours/glitch/features/emoji/emoji'; import { getLocale } from 'locales'; import React from 'react'; -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import { createBrowserHistory } from 'history'; const messages = defineMessages({ @@ -130,7 +130,8 @@ function main() { const content = document.createElement('div'); - ReactDOM.render(, content); + const root = createRoot(content); + root.render(); document.body.appendChild(content); scrollToDetailedStatus(); }) diff --git a/app/javascript/flavours/glitch/packs/share.jsx b/app/javascript/flavours/glitch/packs/share.jsx index 47a51a5b01..a835058ac8 100644 --- a/app/javascript/flavours/glitch/packs/share.jsx +++ b/app/javascript/flavours/glitch/packs/share.jsx @@ -1,9 +1,9 @@ import 'packs/public-path'; import { loadPolyfills } from 'flavours/glitch/polyfills'; +import ready from 'flavours/glitch/ready'; import ComposeContainer from 'flavours/glitch/containers/compose_container'; import React from 'react'; -import ReactDOM from 'react-dom'; -import ready from 'flavours/glitch/ready'; +import { createRoot } from 'react-dom/client'; function loaded() { const mountNode = document.getElementById('mastodon-compose'); @@ -13,7 +13,8 @@ function loaded() { if(!attr) return; const props = JSON.parse(attr); - ReactDOM.render(, mountNode); + const root = createRoot(mountNode); + root.render(); } } diff --git a/app/javascript/flavours/glitch/utils/dom_helpers.js b/app/javascript/flavours/glitch/utils/dom_helpers.js index d94aeb9d47..d9796954a3 100644 --- a/app/javascript/flavours/glitch/utils/dom_helpers.js +++ b/app/javascript/flavours/glitch/utils/dom_helpers.js @@ -1,10 +1,6 @@ // Package imports. import { supportsPassiveEvents } from 'detect-passive-events'; -// This will either be a passive lister options object (if passive -// events are supported), or `false`. -export const withPassive = supportsPassiveEvents ? { passive: true } : false; - // Focuses the root element. export function focusRoot () { let e;