Fix various dialogs failing to open due to containing linked text (#34304)
* Wrap Dialog in LinkedTextContent * actually use originalMxModuleApi * lint * fmt
This commit is contained in:
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2026 Element Creations Ltd.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// @vitest-environment happy-dom
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||||
|
import { LinkedText } from "@element-hq/web-shared-components";
|
||||||
|
import { screen } from "test-utils-rtl";
|
||||||
|
import { flushPromises, stubClient } from "test-utils";
|
||||||
|
import type { I18nApi } from "@element-hq/web-shared-components";
|
||||||
|
|
||||||
|
import Modal from "./Modal";
|
||||||
|
import { type ModuleApi } from "./modules/Api";
|
||||||
|
|
||||||
|
function LinkedTextDialog({ onFinished }: { onFinished(): void }): React.JSX.Element {
|
||||||
|
return <LinkedText>Check out https://matrix.org for more info</LinkedText>;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("Modal", () => {
|
||||||
|
let originalMxModuleApi: ModuleApi;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
stubClient();
|
||||||
|
// Required for the i18n context around the dialog to work.
|
||||||
|
originalMxModuleApi = window.mxModuleApi;
|
||||||
|
window.mxModuleApi = { i18n: {} as I18nApi } as ModuleApi;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
Modal.forceCloseAllModals();
|
||||||
|
window.mxModuleApi = originalMxModuleApi;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("provides LinkedTextContext to dialogs rendered in the separate dialog root", async () => {
|
||||||
|
Modal.createDialog(LinkedTextDialog);
|
||||||
|
await flushPromises();
|
||||||
|
expect(screen.getByRole("link")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
+36
-31
@@ -12,7 +12,7 @@ import { createRoot, type Root } from "react-dom/client";
|
|||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { TypedEventEmitter } from "matrix-js-sdk/src/matrix";
|
import { TypedEventEmitter } from "matrix-js-sdk/src/matrix";
|
||||||
import { Glass, TooltipProvider } from "@vector-im/compound-web";
|
import { Glass, TooltipProvider } from "@vector-im/compound-web";
|
||||||
import { I18nContext } from "@element-hq/web-shared-components";
|
import { I18nContext, LinkedTextContext } from "@element-hq/web-shared-components";
|
||||||
|
|
||||||
import defaultDispatcher from "./dispatcher/dispatcher";
|
import defaultDispatcher from "./dispatcher/dispatcher";
|
||||||
import AsyncWrapper from "./AsyncWrapper";
|
import AsyncWrapper from "./AsyncWrapper";
|
||||||
@@ -20,6 +20,7 @@ import { type Defaultize } from "./@types/common";
|
|||||||
import { type ActionPayload } from "./dispatcher/payloads";
|
import { type ActionPayload } from "./dispatcher/payloads";
|
||||||
import { filterBoolean } from "./utils/arrays.ts";
|
import { filterBoolean } from "./utils/arrays.ts";
|
||||||
import { SDKContext } from "./contexts/SDKContext.ts";
|
import { SDKContext } from "./contexts/SDKContext.ts";
|
||||||
|
import { LinkedTextConfiguration } from "./Linkify";
|
||||||
|
|
||||||
const DIALOG_CONTAINER_ID = "mx_Dialog_Container";
|
const DIALOG_CONTAINER_ID = "mx_Dialog_Container";
|
||||||
const STATIC_DIALOG_CONTAINER_ID = "mx_Dialog_StaticContainer";
|
const STATIC_DIALOG_CONTAINER_ID = "mx_Dialog_StaticContainer";
|
||||||
@@ -439,22 +440,24 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
|||||||
const staticDialog = (
|
const staticDialog = (
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<SDKContext.Provider value={window.mxSdkContext}>
|
<SDKContext.Provider value={window.mxSdkContext}>
|
||||||
{/* Provide I18nContext for shared-components used inside dialogs rendered in a separate root. */}
|
{/* Provide I18nContext and LinkedTextContext for shared-components used inside dialogs rendered in a separate root. */}
|
||||||
<I18nContext.Provider value={window.mxModuleApi.i18n}>
|
<I18nContext.Provider value={window.mxModuleApi.i18n}>
|
||||||
<TooltipProvider>
|
<LinkedTextContext.Provider value={LinkedTextConfiguration}>
|
||||||
<div className={classes}>
|
<TooltipProvider>
|
||||||
<Glass className="mx_Dialog_border">
|
<div className={classes}>
|
||||||
<div className="mx_Dialog">{this.staticModal.elem}</div>
|
<Glass className="mx_Dialog_border">
|
||||||
</Glass>
|
<div className="mx_Dialog">{this.staticModal.elem}</div>
|
||||||
{/* We break the rule here as this is a mouse-only interaction */}
|
</Glass>
|
||||||
{/* oxlint-disable-next-line jsx-a11y/click-events-have-key-events */}
|
{/* We break the rule here as this is a mouse-only interaction */}
|
||||||
<div
|
{/* oxlint-disable-next-line jsx-a11y/click-events-have-key-events */}
|
||||||
data-testid="dialog-background"
|
<div
|
||||||
className="mx_Dialog_background mx_Dialog_staticBackground"
|
data-testid="dialog-background"
|
||||||
onClick={this.onBackgroundClick}
|
className="mx_Dialog_background mx_Dialog_staticBackground"
|
||||||
/>
|
onClick={this.onBackgroundClick}
|
||||||
</div>
|
/>
|
||||||
</TooltipProvider>
|
</div>
|
||||||
|
</TooltipProvider>
|
||||||
|
</LinkedTextContext.Provider>
|
||||||
</I18nContext.Provider>
|
</I18nContext.Provider>
|
||||||
</SDKContext.Provider>
|
</SDKContext.Provider>
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
@@ -475,22 +478,24 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
|||||||
const dialog = (
|
const dialog = (
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<SDKContext.Provider value={window.mxSdkContext}>
|
<SDKContext.Provider value={window.mxSdkContext}>
|
||||||
{/* Provide I18nContext for shared-components used inside dialogs rendered in a separate root. */}
|
{/* Provide I18nContext and LinkedTextContext for shared-components used inside dialogs rendered in a separate root. */}
|
||||||
<I18nContext.Provider value={window.mxModuleApi.i18n}>
|
<I18nContext.Provider value={window.mxModuleApi.i18n}>
|
||||||
<TooltipProvider>
|
<LinkedTextContext.Provider value={LinkedTextConfiguration}>
|
||||||
<div className={classes}>
|
<TooltipProvider>
|
||||||
<Glass className="mx_Dialog_border">
|
<div className={classes}>
|
||||||
<div className="mx_Dialog">{modal.elem}</div>
|
<Glass className="mx_Dialog_border">
|
||||||
</Glass>
|
<div className="mx_Dialog">{modal.elem}</div>
|
||||||
{/* We break the rule here as this is a mouse-only interaction */}
|
</Glass>
|
||||||
{/* oxlint-disable-next-line jsx-a11y/click-events-have-key-events */}
|
{/* We break the rule here as this is a mouse-only interaction */}
|
||||||
<div
|
{/* oxlint-disable-next-line jsx-a11y/click-events-have-key-events */}
|
||||||
data-testid="dialog-background"
|
<div
|
||||||
className="mx_Dialog_background"
|
data-testid="dialog-background"
|
||||||
onClick={this.onBackgroundClick}
|
className="mx_Dialog_background"
|
||||||
/>
|
onClick={this.onBackgroundClick}
|
||||||
</div>
|
/>
|
||||||
</TooltipProvider>
|
</div>
|
||||||
|
</TooltipProvider>
|
||||||
|
</LinkedTextContext.Provider>
|
||||||
</I18nContext.Provider>
|
</I18nContext.Provider>
|
||||||
</SDKContext.Provider>
|
</SDKContext.Provider>
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
|
|||||||
Reference in New Issue
Block a user