From b127ca0cd560ba97647d42dcb707004770ee6fb4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 22 Oct 2024 14:24:01 +0100 Subject: [PATCH] Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/elements/PersistedElement.tsx | 33 +++++++++---------- src/components/views/messages/TextualBody.tsx | 1 - src/utils/exportUtils/HtmlExport.tsx | 10 ++++-- .../views/rooms/MessageComposer-test.tsx | 4 +-- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/components/views/elements/PersistedElement.tsx b/src/components/views/elements/PersistedElement.tsx index 3ab3e51fc47..cdf3cf0c1f8 100644 --- a/src/components/views/elements/PersistedElement.tsx +++ b/src/components/views/elements/PersistedElement.tsx @@ -6,7 +6,7 @@ Please see LICENSE files in the repository root for full details. */ import React, { MutableRefObject, ReactNode } from "react"; -import { createRoot } from "react-dom/client"; +import { createRoot, Root } from "react-dom/client"; import { isNullOrUndefined } from "matrix-js-sdk/src/utils"; import { TooltipProvider } from "@vector-im/compound-web"; @@ -24,7 +24,7 @@ export const getPersistKey = (appId: string): string => "widget_" + appId; // We contain all persisted elements within a master container to allow them all to be within the same // CSS stacking context, and thus be able to control their z-indexes relative to each other. function getOrCreateMasterContainer(): HTMLDivElement { - let container = getContainer("mx_PersistedElement_container"); + let container = document.getElementById("mx_PersistedElement_container") as HTMLDivElement; if (!container) { container = document.createElement("div"); container.id = "mx_PersistedElement_container"; @@ -34,18 +34,10 @@ function getOrCreateMasterContainer(): HTMLDivElement { return container; } -function getContainer(containerId: string): HTMLDivElement { - return document.getElementById(containerId) as HTMLDivElement; -} - function getOrCreateContainer(containerId: string): HTMLDivElement { - let container = getContainer(containerId); - - if (!container) { - container = document.createElement("div"); - container.id = containerId; - getOrCreateMasterContainer().appendChild(container); - } + const container = document.createElement("div"); + container.id = containerId; + getOrCreateMasterContainer().appendChild(container); return container; } @@ -83,6 +75,8 @@ export default class PersistedElement extends React.Component { private childContainer?: HTMLDivElement; private child?: HTMLDivElement; + private static rootMap: Record = {}; + public constructor(props: IProps) { super(props); @@ -106,14 +100,15 @@ export default class PersistedElement extends React.Component { * @param {string} persistKey Key used to uniquely identify this PersistedElement */ public static destroyElement(persistKey: string): void { - const container = getContainer("mx_persistedElement_" + persistKey); - if (container) { - container.remove(); + const pair = PersistedElement.rootMap[persistKey]; + if (pair) { + pair[0].unmount(); + pair[1].remove(); } } public static isMounted(persistKey: string): boolean { - return Boolean(getContainer("mx_persistedElement_" + persistKey)); + return Boolean(PersistedElement.rootMap[persistKey]); } private collectChildContainer = (ref: HTMLDivElement): void => { @@ -176,7 +171,9 @@ export default class PersistedElement extends React.Component { ); - const root = createRoot(getOrCreateContainer("mx_persistedElement_" + this.props.persistKey)); + const container = getOrCreateContainer("mx_persistedElement_" + this.props.persistKey); + const root = createRoot(container); + PersistedElement.rootMap[this.props.persistKey] = [root, container]; root.render(content); } diff --git a/src/components/views/messages/TextualBody.tsx b/src/components/views/messages/TextualBody.tsx index a6681545146..6cfeb683b08 100644 --- a/src/components/views/messages/TextualBody.tsx +++ b/src/components/views/messages/TextualBody.tsx @@ -7,7 +7,6 @@ Please see LICENSE files in the repository root for full details. */ import React, { createRef, SyntheticEvent, MouseEvent } from "react"; -import ReactDOM from "react-dom"; import { MsgType } from "matrix-js-sdk/src/matrix"; import { TooltipProvider } from "@vector-im/compound-web"; diff --git a/src/utils/exportUtils/HtmlExport.tsx b/src/utils/exportUtils/HtmlExport.tsx index ea339116a39..58fbc7f06da 100644 --- a/src/utils/exportUtils/HtmlExport.tsx +++ b/src/utils/exportUtils/HtmlExport.tsx @@ -13,6 +13,7 @@ import { renderToStaticMarkup } from "react-dom/server"; import { logger } from "matrix-js-sdk/src/logger"; import escapeHtml from "escape-html"; import { TooltipProvider } from "@vector-im/compound-web"; +import { defer } from "matrix-js-sdk/src/utils"; import Exporter from "./Exporter"; import { mediaFromMxc } from "../../customisations/Media"; @@ -268,7 +269,7 @@ export default class HTMLExporter extends Exporter { return wantsDateSeparator(prevEvent.getDate() || undefined, event.getDate() || undefined); } - public getEventTile(mxEv: MatrixEvent, continuation: boolean): JSX.Element { + public getEventTile(mxEv: MatrixEvent, continuation: boolean, ref?: () => void): JSX.Element { return (
@@ -292,6 +293,7 @@ export default class HTMLExporter extends Exporter { layout={Layout.Group} showReadReceipts={false} getRelationsForEvent={this.getRelationsForEvent} + ref={ref} /> @@ -303,7 +305,10 @@ export default class HTMLExporter extends Exporter { const avatarUrl = this.getAvatarURL(mxEv); const hasAvatar = !!avatarUrl; if (hasAvatar) await this.saveAvatarIfNeeded(mxEv); - const EventTile = this.getEventTile(mxEv, continuation); + // We have to wait for the component to be rendered before we can get the markup + // so pass a deferred as a ref to the component. + const deferred = defer(); + const EventTile = this.getEventTile(mxEv, continuation, deferred.resolve); let eventTileMarkup: string; if ( @@ -316,6 +321,7 @@ export default class HTMLExporter extends Exporter { const tempElement = document.createElement("div"); const tempRoot = createRoot(tempElement); tempRoot.render(EventTile); + await deferred.promise; eventTileMarkup = tempElement.innerHTML; tempRoot.unmount(); } else { diff --git a/test/unit-tests/components/views/rooms/MessageComposer-test.tsx b/test/unit-tests/components/views/rooms/MessageComposer-test.tsx index 1d097b26b0b..b70b8de3e26 100644 --- a/test/unit-tests/components/views/rooms/MessageComposer-test.tsx +++ b/test/unit-tests/components/views/rooms/MessageComposer-test.tsx @@ -445,7 +445,7 @@ describe("MessageComposer", () => { const messageText = "Test Text"; await SettingsStore.setValue("feature_wysiwyg_composer", null, SettingLevel.DEVICE, true); const { renderResult, rawComponent } = wrapAndRender({ room }); - const { unmount, rerender } = renderResult; + const { unmount } = renderResult; await flushPromises(); @@ -475,7 +475,7 @@ describe("MessageComposer", () => { }); // ensure the correct state is re-loaded - rerender(rawComponent); + render(rawComponent); await waitFor(() => expect(screen.getByRole("textbox")).toHaveTextContent(messageText)); }, 10000); });