Switch ModalManager to the React 18 createRoot API (#28336)
* Remove boilerplate around dispatcher and settings watchers Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Move state update listeners from constructor to componentDidMount Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Switch ModalManager to the React 18 createRoot API Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
38e5eeea00
commit
502cc91dfe
9 changed files with 66 additions and 60 deletions
|
@ -8,9 +8,9 @@ Please see LICENSE files in the repository root for full details.
|
|||
*/
|
||||
|
||||
import React, { StrictMode } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { createRoot, Root } from "react-dom/client";
|
||||
import classNames from "classnames";
|
||||
import { IDeferred, defer, sleep } from "matrix-js-sdk/src/utils";
|
||||
import { IDeferred, defer } from "matrix-js-sdk/src/utils";
|
||||
import { TypedEventEmitter } from "matrix-js-sdk/src/matrix";
|
||||
import { Glass, TooltipProvider } from "@vector-im/compound-web";
|
||||
|
||||
|
@ -69,6 +69,16 @@ type HandlerMap = {
|
|||
|
||||
type ModalCloseReason = "backgroundClick";
|
||||
|
||||
function getOrCreateContainer(id: string): HTMLDivElement {
|
||||
let container = document.getElementById(id) as HTMLDivElement | null;
|
||||
if (!container) {
|
||||
container = document.createElement("div");
|
||||
container.id = id;
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMap> {
|
||||
private counter = 0;
|
||||
// The modal to prioritise over all others. If this is set, only show
|
||||
|
@ -83,28 +93,22 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
|||
// Neither the static nor priority modal will be in this list.
|
||||
private modals: IModal<any>[] = [];
|
||||
|
||||
private static getOrCreateContainer(): HTMLElement {
|
||||
let container = document.getElementById(DIALOG_CONTAINER_ID);
|
||||
|
||||
if (!container) {
|
||||
container = document.createElement("div");
|
||||
container.id = DIALOG_CONTAINER_ID;
|
||||
document.body.appendChild(container);
|
||||
private static root?: Root;
|
||||
private static getOrCreateRoot(): Root {
|
||||
if (!ModalManager.root) {
|
||||
const container = getOrCreateContainer(DIALOG_CONTAINER_ID);
|
||||
ModalManager.root = createRoot(container);
|
||||
}
|
||||
|
||||
return container;
|
||||
return ModalManager.root;
|
||||
}
|
||||
|
||||
private static getOrCreateStaticContainer(): HTMLElement {
|
||||
let container = document.getElementById(STATIC_DIALOG_CONTAINER_ID);
|
||||
|
||||
if (!container) {
|
||||
container = document.createElement("div");
|
||||
container.id = STATIC_DIALOG_CONTAINER_ID;
|
||||
document.body.appendChild(container);
|
||||
private static staticRoot?: Root;
|
||||
private static getOrCreateStaticRoot(): Root {
|
||||
if (!ModalManager.staticRoot) {
|
||||
const container = getOrCreateContainer(STATIC_DIALOG_CONTAINER_ID);
|
||||
ModalManager.staticRoot = createRoot(container);
|
||||
}
|
||||
|
||||
return container;
|
||||
return ModalManager.staticRoot;
|
||||
}
|
||||
|
||||
public constructor() {
|
||||
|
@ -389,19 +393,14 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
|||
}
|
||||
|
||||
private async reRender(): Promise<void> {
|
||||
// TODO: We should figure out how to remove this weird sleep. It also makes testing harder
|
||||
//
|
||||
// await next tick because sometimes ReactDOM can race with itself and cause the modal to wrongly stick around
|
||||
await sleep(0);
|
||||
|
||||
if (this.modals.length === 0 && !this.priorityModal && !this.staticModal) {
|
||||
// If there is no modal to render, make all of Element available
|
||||
// to screen reader users again
|
||||
dis.dispatch({
|
||||
action: "aria_unhide_main_app",
|
||||
});
|
||||
ReactDOM.unmountComponentAtNode(ModalManager.getOrCreateContainer());
|
||||
ReactDOM.unmountComponentAtNode(ModalManager.getOrCreateStaticContainer());
|
||||
ModalManager.getOrCreateRoot().render(<></>);
|
||||
ModalManager.getOrCreateStaticRoot().render(<></>);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -432,10 +431,10 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
|||
</StrictMode>
|
||||
);
|
||||
|
||||
ReactDOM.render(staticDialog, ModalManager.getOrCreateStaticContainer());
|
||||
ModalManager.getOrCreateStaticRoot().render(staticDialog);
|
||||
} else {
|
||||
// This is safe to call repeatedly if we happen to do that
|
||||
ReactDOM.unmountComponentAtNode(ModalManager.getOrCreateStaticContainer());
|
||||
ModalManager.getOrCreateStaticRoot().render(<></>);
|
||||
}
|
||||
|
||||
const modal = this.getCurrentModal();
|
||||
|
@ -461,10 +460,10 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
|||
</StrictMode>
|
||||
);
|
||||
|
||||
setTimeout(() => ReactDOM.render(dialog, ModalManager.getOrCreateContainer()), 0);
|
||||
ModalManager.getOrCreateRoot().render(dialog);
|
||||
} else {
|
||||
// This is safe to call repeatedly if we happen to do that
|
||||
ReactDOM.unmountComponentAtNode(ModalManager.getOrCreateContainer());
|
||||
ModalManager.getOrCreateRoot().render(<></>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue