Update react monorepo to v19 (major) (#28914)
* Update react monorepo to v19 * Import JSX explicitly for React 19 compatibility Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update usages of refs for React 19 compatibility Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update react imports Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Avoid legacy contexts as much as possible Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Avoid deprecated React symbols Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Stash Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update usages of refs for React 19 compatibility 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> * Switch pillify to use a html-react-parser approach rather than DOM muddling Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate react html parsing Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate react html parsing Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate html parsing Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Memoize the EventContentBody component Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate html parsing 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> * Simplify Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Discard changes to src/Linkify.tsx * Discard changes to src/components/views/messages/TextualBody.tsx * Discard changes to src/settings/handlers/AbstractLocalStorageSettingsHandler.ts * Iterate 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> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Prepare for React 19 upgrade Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove stale comment Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
13
package.json
13
package.json
@@ -69,9 +69,10 @@
|
||||
"postinstall": "patch-package"
|
||||
},
|
||||
"resolutions": {
|
||||
"**/pretty-format/react-is": "19.0.0",
|
||||
"@playwright/test": "1.51.1",
|
||||
"@types/react": "18.3.18",
|
||||
"@types/react-dom": "18.3.5",
|
||||
"@types/react": "19.0.10",
|
||||
"@types/react-dom": "19.0.4",
|
||||
"oidc-client-ts": "3.2.0",
|
||||
"jwt-decode": "4.0.0",
|
||||
"caniuse-lite": "1.0.30001707",
|
||||
@@ -141,10 +142,10 @@
|
||||
"posthog-js": "1.157.2",
|
||||
"qrcode": "1.5.4",
|
||||
"re-resizable": "6.11.2",
|
||||
"react": "^18.3.1",
|
||||
"react": "^19.0.0",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-blurhash": "^0.3.0",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-focus-lock": "^2.5.1",
|
||||
"react-string-replace": "^1.1.1",
|
||||
"react-transition-group": "^4.4.1",
|
||||
@@ -211,9 +212,9 @@
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"@types/pako": "^2.0.0",
|
||||
"@types/qrcode": "^1.3.5",
|
||||
"@types/react": "18.3.18",
|
||||
"@types/react": "19.0.10",
|
||||
"@types/react-beautiful-dnd": "^13.0.0",
|
||||
"@types/react-dom": "18.3.5",
|
||||
"@types/react-dom": "19.0.4",
|
||||
"@types/react-transition-group": "^4.4.0",
|
||||
"@types/sanitize-html": "2.15.0",
|
||||
"@types/semver": "^7.5.8",
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
diff --git a/node_modules/@types/react/index.d.ts b/node_modules/@types/react/index.d.ts
|
||||
index 6ea73ef..cb51757 100644
|
||||
--- a/node_modules/@types/react/index.d.ts
|
||||
+++ b/node_modules/@types/react/index.d.ts
|
||||
@@ -151,7 +151,7 @@ declare namespace React {
|
||||
/**
|
||||
* The current value of the ref.
|
||||
*/
|
||||
- readonly current: T | null;
|
||||
+ current: T;
|
||||
}
|
||||
|
||||
interface DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES {
|
||||
@@ -186,7 +186,7 @@ declare namespace React {
|
||||
* @see {@link RefObject}
|
||||
*/
|
||||
|
||||
- type Ref<T> = RefCallback<T> | RefObject<T> | null;
|
||||
+ type Ref<T> = RefCallback<T> | RefObject<T | null> | null;
|
||||
/**
|
||||
* A legacy implementation of refs where you can pass a string to a ref prop.
|
||||
*
|
||||
@@ -300,7 +300,7 @@ declare namespace React {
|
||||
*
|
||||
* @see {@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
|
||||
*/
|
||||
- ref?: LegacyRef<T> | undefined;
|
||||
+ ref?: LegacyRef<T | null> | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1234,7 +1234,7 @@ declare namespace React {
|
||||
*
|
||||
* @see {@link ForwardRefRenderFunction}
|
||||
*/
|
||||
- type ForwardedRef<T> = ((instance: T | null) => void) | MutableRefObject<T | null> | null;
|
||||
+ type ForwardedRef<T> = ((instance: T | null) => void) | RefObject<T | null> | null;
|
||||
|
||||
/**
|
||||
* The type of the function passed to {@link forwardRef}. This is considered different
|
||||
@@ -1565,7 +1565,7 @@ declare namespace React {
|
||||
[propertyName: string]: any;
|
||||
}
|
||||
|
||||
- function createRef<T>(): RefObject<T>;
|
||||
+ function createRef<T>(): RefObject<T | null>;
|
||||
|
||||
/**
|
||||
* The type of the component returned from {@link forwardRef}.
|
||||
@@ -1989,7 +1989,7 @@ declare namespace React {
|
||||
* @version 16.8.0
|
||||
* @see {@link https://react.dev/reference/react/useRef}
|
||||
*/
|
||||
- function useRef<T>(initialValue: T): MutableRefObject<T>;
|
||||
+ function useRef<T>(initialValue: T): RefObject<T>;
|
||||
// convenience overload for refs given as a ref prop as they typically start with a null value
|
||||
/**
|
||||
* `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument
|
||||
@@ -2004,7 +2004,7 @@ declare namespace React {
|
||||
* @version 16.8.0
|
||||
* @see {@link https://react.dev/reference/react/useRef}
|
||||
*/
|
||||
- function useRef<T>(initialValue: T | null): RefObject<T>;
|
||||
+ function useRef<T>(initialValue: T | null): RefObject<T | null>;
|
||||
// convenience overload for potentially undefined initialValue / call with 0 arguments
|
||||
// has a default to stop it from defaulting to {} instead
|
||||
/**
|
||||
@@ -2017,7 +2017,7 @@ declare namespace React {
|
||||
* @version 16.8.0
|
||||
* @see {@link https://react.dev/reference/react/useRef}
|
||||
*/
|
||||
- function useRef<T = undefined>(initialValue?: undefined): MutableRefObject<T | undefined>;
|
||||
+ function useRef<T>(initialValue: T | undefined): RefObject<T | undefined>;
|
||||
/**
|
||||
* The signature is identical to `useEffect`, but it fires synchronously after all DOM mutations.
|
||||
* Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside
|
||||
31
patches/@types+react+19.0.10.patch
Normal file
31
patches/@types+react+19.0.10.patch
Normal file
@@ -0,0 +1,31 @@
|
||||
diff --git a/node_modules/@types/react/index.d.ts b/node_modules/@types/react/index.d.ts
|
||||
index 2272032..18bd20a 100644
|
||||
--- a/node_modules/@types/react/index.d.ts
|
||||
+++ b/node_modules/@types/react/index.d.ts
|
||||
@@ -134,7 +134,7 @@ declare namespace React {
|
||||
props: P,
|
||||
) => ReactNode | Promise<ReactNode>)
|
||||
// constructor signature must match React.Component
|
||||
- | (new(props: P) => Component<any, any>);
|
||||
+ | (new(props: P, context?: any) => Component<any, any>);
|
||||
|
||||
/**
|
||||
* Created by {@link createRef}, or {@link useRef} when passed `null`.
|
||||
@@ -941,7 +941,7 @@ declare namespace React {
|
||||
context: unknown;
|
||||
|
||||
// Keep in sync with constructor signature of JSXElementConstructor and ComponentClass.
|
||||
- constructor(props: P);
|
||||
+ constructor(props: P, context?: unknown);
|
||||
|
||||
// We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
|
||||
// See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
|
||||
@@ -1113,7 +1113,7 @@ declare namespace React {
|
||||
*/
|
||||
interface ComponentClass<P = {}, S = ComponentState> extends StaticLifecycle<P, S> {
|
||||
// constructor signature must match React.Component
|
||||
- new(props: P): Component<P, S>;
|
||||
+ new(props: P, context?: any): Component<P, S>;
|
||||
/**
|
||||
* Ignored by React.
|
||||
* @deprecated Only kept in types for backwards compatibility. Will be removed in a future major release.
|
||||
22
patches/react-blurhash+0.3.0.patch
Normal file
22
patches/react-blurhash+0.3.0.patch
Normal file
@@ -0,0 +1,22 @@
|
||||
diff --git a/node_modules/react-blurhash/dist/index.d.ts b/node_modules/react-blurhash/dist/index.d.ts
|
||||
index 3adbd0a..32e8c13 100644
|
||||
--- a/node_modules/react-blurhash/dist/index.d.ts
|
||||
+++ b/node_modules/react-blurhash/dist/index.d.ts
|
||||
@@ -19,7 +19,7 @@ declare class Blurhash extends React.PureComponent<Props$1> {
|
||||
resolutionY: number;
|
||||
};
|
||||
componentDidUpdate(): void;
|
||||
- render(): JSX.Element;
|
||||
+ render(): React.JSX.Element;
|
||||
}
|
||||
|
||||
declare type Props = React.CanvasHTMLAttributes<HTMLCanvasElement> & {
|
||||
@@ -37,7 +37,7 @@ declare class BlurhashCanvas extends React.PureComponent<Props> {
|
||||
componentDidUpdate(): void;
|
||||
handleRef: (canvas: HTMLCanvasElement) => void;
|
||||
draw: () => void;
|
||||
- render(): JSX.Element;
|
||||
+ render(): React.JSX.Element;
|
||||
}
|
||||
|
||||
export { Blurhash, BlurhashCanvas };
|
||||
@@ -43,6 +43,7 @@ test.describe("Pills", () => {
|
||||
|
||||
// go back to the message room and try to click on the pill text, as a user would
|
||||
await app.viewRoomByName(messageRoom);
|
||||
await expect(page).toHaveURL(new RegExp(`/#/room/${messageRoomId}`));
|
||||
const pillText = page.locator(".mx_EventTile_body .mx_Pill .mx_Pill_text");
|
||||
await expect(pillText).toHaveCSS("pointer-events", "none");
|
||||
await pillText.click({ force: true }); // force is to ensure we bypass pointer-events
|
||||
|
||||
5
src/@types/react.d.ts
vendored
5
src/@types/react.d.ts
vendored
@@ -18,4 +18,9 @@ declare module "react" {
|
||||
|
||||
// Fix lazy types - https://stackoverflow.com/a/71017028
|
||||
function lazy<T extends ComponentType<any>>(factory: () => Promise<{ default: T }>): T;
|
||||
|
||||
// Standardize defaultProps for FunctionComponent so we can write generics assuming `defaultProps` exists on ComponentType
|
||||
interface FunctionComponent {
|
||||
defaultProps?: unknown;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type JSX, type LegacyRef, type ReactNode } from "react";
|
||||
import React, { type JSX, type Key, type LegacyRef, type ReactNode } from "react";
|
||||
import sanitizeHtml, { type IOptions } from "sanitize-html";
|
||||
import classNames from "classnames";
|
||||
import katex from "katex";
|
||||
@@ -239,7 +239,7 @@ class HtmlHighlighter extends BaseHighlighter<string> {
|
||||
|
||||
const emojiToHtmlSpan = (emoji: string): string =>
|
||||
`<span class='mx_Emoji' title='${unicodeToShortcode(emoji)}'>${emoji}</span>`;
|
||||
const emojiToJsxSpan = (emoji: string, key: number): JSX.Element => (
|
||||
const emojiToJsxSpan = (emoji: string, key: Key): JSX.Element => (
|
||||
<span key={key} className="mx_Emoji" title={unicodeToShortcode(emoji)}>
|
||||
{emoji}
|
||||
</span>
|
||||
|
||||
@@ -321,7 +321,7 @@ async function attemptOidcNativeLogin(queryParams: QueryDict): Promise<boolean>
|
||||
} catch (error) {
|
||||
logger.error("Failed to login via OIDC", error);
|
||||
|
||||
await onFailedDelegatedAuthLogin(getOidcErrorMessage(error as Error));
|
||||
onFailedDelegatedAuthLogin(getOidcErrorMessage(error as Error));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -468,7 +468,7 @@ type TryAgainFunction = () => void;
|
||||
* @param description error description
|
||||
* @param tryAgain OPTIONAL function to call on try again button from error dialog
|
||||
*/
|
||||
async function onFailedDelegatedAuthLogin(description: string | ReactNode, tryAgain?: TryAgainFunction): Promise<void> {
|
||||
function onFailedDelegatedAuthLogin(description: string | ReactNode, tryAgain?: TryAgainFunction): void {
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("auth|oidc|error_title"),
|
||||
description,
|
||||
|
||||
@@ -212,7 +212,7 @@ export const RovingTabIndexProvider: React.FC<IProps> = ({
|
||||
scrollIntoView,
|
||||
onKeyDown,
|
||||
}) => {
|
||||
const [state, dispatch] = useReducer<Reducer<IState, Action>>(reducer, {
|
||||
const [state, dispatch] = useReducer<IState, [Action]>(reducer, {
|
||||
nodes: [],
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { type ReactElement } from "react";
|
||||
import { type ReactElement, type RefAttributes, type HTMLAttributes } from "react";
|
||||
import { type Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import CommandProvider from "./CommandProvider";
|
||||
@@ -31,7 +31,7 @@ export interface ICompletion {
|
||||
type?: "at-room" | "command" | "community" | "room" | "user";
|
||||
completion: string;
|
||||
completionId?: string;
|
||||
component: ReactElement;
|
||||
component: ReactElement<RefAttributes<HTMLElement> & HTMLAttributes<HTMLElement>>;
|
||||
range: ISelectionRange;
|
||||
command?: string;
|
||||
suffix?: string;
|
||||
|
||||
@@ -21,8 +21,6 @@ export type IProps<T extends keyof JSX.IntrinsicElements> = Omit<AutoHideScrollb
|
||||
// scroll horizontally rather than vertically. This should only be used on components
|
||||
// with no vertical scroll opportunity.
|
||||
verticalScrollsHorizontally?: boolean;
|
||||
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
interface IState {
|
||||
|
||||
@@ -165,12 +165,6 @@ interface IProps {
|
||||
initialScreenAfterLogin?: IScreen;
|
||||
// displayname, if any, to set on the device when logging in/registering.
|
||||
defaultDeviceDisplayName?: string;
|
||||
|
||||
// Used by tests, this function is called when session initialisation starts
|
||||
// with a promise that resolves or rejects once the initialiation process
|
||||
// has finished, so that tests can wait for this to avoid them executing over
|
||||
// each other.
|
||||
initPromiseCallback?: (p: Promise<void>) => void;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
@@ -291,9 +285,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
*/
|
||||
private startInitSession = (): void => {
|
||||
const initProm = this.initSession();
|
||||
if (this.props.initPromiseCallback) {
|
||||
this.props.initPromiseCallback(initProm);
|
||||
}
|
||||
|
||||
initProm.catch((err) => {
|
||||
// TODO: show an error screen, rather than a spinner of doom
|
||||
@@ -1002,10 +993,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
// Wait for the first sync to complete so that if a room does have an alias,
|
||||
// it would have been retrieved.
|
||||
if (!this.firstSyncComplete) {
|
||||
if (!this.firstSyncPromise) {
|
||||
logger.warn("Cannot view a room before first sync. room_id:", roomInfo.room_id);
|
||||
return;
|
||||
}
|
||||
await this.firstSyncPromise.promise;
|
||||
}
|
||||
|
||||
@@ -1116,8 +1103,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
private viewUser(userId: string, subAction: string): void {
|
||||
// Wait for the first sync so that `getRoom` gives us a room object if it's
|
||||
// in the sync response
|
||||
const waitForSync = this.firstSyncPromise ? this.firstSyncPromise.promise : Promise.resolve();
|
||||
waitForSync.then(() => {
|
||||
this.firstSyncPromise.promise.then(() => {
|
||||
if (subAction === "chat") {
|
||||
this.chatCreateOrReuse(userId);
|
||||
return;
|
||||
@@ -1480,11 +1466,17 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
* (useful for setting listeners)
|
||||
*/
|
||||
private onWillStartClient(): void {
|
||||
// reset the 'have completed first sync' flag,
|
||||
// since we're about to start the client and therefore about
|
||||
// to do the first sync
|
||||
// Reset the 'have completed first sync' flag,
|
||||
// since we're about to start the client and therefore about to do the first sync
|
||||
// We resolve the existing promise with the new one to update any existing listeners
|
||||
if (!this.firstSyncComplete) {
|
||||
const firstSyncPromise = defer<void>();
|
||||
this.firstSyncPromise.resolve(firstSyncPromise.promise);
|
||||
this.firstSyncPromise = firstSyncPromise;
|
||||
} else {
|
||||
this.firstSyncPromise = defer();
|
||||
}
|
||||
this.firstSyncComplete = false;
|
||||
this.firstSyncPromise = defer();
|
||||
const cli = MatrixClientPeg.safeGet();
|
||||
|
||||
// Allow the JS SDK to reap timeline events. This reduces the amount of
|
||||
|
||||
@@ -27,14 +27,14 @@ export class Tab<T extends string> {
|
||||
* @param {string} id The tab's ID.
|
||||
* @param {string} label The untranslated tab label.
|
||||
* @param {string|JSX.Element} icon An SVG element to use for the tab icon. Can also be a string for legacy icons, in which case it is the class for the tab icon. This should be a simple mask.
|
||||
* @param {React.ReactNode} body The JSX for the tab container.
|
||||
* @param {JSX.Element} body The JSX for the tab container.
|
||||
* @param {string} screenName The screen name to report to Posthog.
|
||||
*/
|
||||
public constructor(
|
||||
public readonly id: T,
|
||||
public readonly label: TranslationKey,
|
||||
public readonly icon: string | JSX.Element | null,
|
||||
public readonly body: React.ReactNode,
|
||||
public readonly body: JSX.Element,
|
||||
public readonly screenName?: ScreenName,
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { createContext, type Dispatch, type ReducerAction, type ReducerState } from "react";
|
||||
import { createContext, type Dispatch, type Reducer, type ReducerState } from "react";
|
||||
|
||||
import type { AuthHeaderReducer } from "./AuthHeaderProvider";
|
||||
|
||||
type ReducerAction<R extends Reducer<any, any>> = R extends Reducer<any, infer A> ? A : never;
|
||||
|
||||
interface AuthHeaderContextType {
|
||||
state: ReducerState<AuthHeaderReducer>;
|
||||
dispatch: Dispatch<ReducerAction<AuthHeaderReducer>>;
|
||||
|
||||
@@ -25,7 +25,7 @@ interface AuthHeaderAction {
|
||||
export type AuthHeaderReducer = Reducer<ComponentProps<typeof AuthHeaderModifier>[], AuthHeaderAction>;
|
||||
|
||||
export function AuthHeaderProvider({ children }: PropsWithChildren): JSX.Element {
|
||||
const [state, dispatch] = useReducer<AuthHeaderReducer>(
|
||||
const [state, dispatch] = useReducer<ComponentProps<typeof AuthHeaderModifier>[], [AuthHeaderAction]>(
|
||||
(state: ComponentProps<typeof AuthHeaderModifier>[], action: AuthHeaderAction) => {
|
||||
switch (action.type) {
|
||||
case AuthHeaderActionType.Add:
|
||||
|
||||
@@ -18,6 +18,7 @@ import { CardContext } from "../right_panel/context";
|
||||
import UserIdentifierCustomisations from "../../../customisations/UserIdentifier";
|
||||
import { useRoomMemberProfile } from "../../../hooks/room/useRoomMemberProfile";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext.tsx";
|
||||
|
||||
interface IProps extends Omit<React.ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url"> {
|
||||
member: RoomMember | null;
|
||||
@@ -47,6 +48,7 @@ function MemberAvatar(
|
||||
}: IProps,
|
||||
ref: Ref<HTMLElement>,
|
||||
): JSX.Element {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
const card = useContext(CardContext);
|
||||
|
||||
const member = useRoomMemberProfile({
|
||||
@@ -60,7 +62,7 @@ function MemberAvatar(
|
||||
let imageUrl: string | null | undefined;
|
||||
if (member?.name) {
|
||||
if (member.getMxcAvatarUrl()) {
|
||||
imageUrl = mediaFromMxc(member.getMxcAvatarUrl() ?? "").getThumbnailOfSourceHttp(
|
||||
imageUrl = mediaFromMxc(member.getMxcAvatarUrl() ?? "", cli).getThumbnailOfSourceHttp(
|
||||
parseInt(size, 10),
|
||||
parseInt(size, 10),
|
||||
resizeMethod,
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef } from "react";
|
||||
import React, { createRef, type RefObject } from "react";
|
||||
import { type DialogContent, type DialogProps } from "@matrix-org/react-sdk-module-api/lib/components/DialogContent";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { type ModuleApi } from "@matrix-org/react-sdk-module-api/lib/ModuleApi";
|
||||
@@ -27,10 +27,10 @@ interface IState extends IScrollableBaseState {
|
||||
// nothing special
|
||||
}
|
||||
|
||||
export class ModuleUiDialog<P extends DialogProps, C extends DialogContent<P>> extends ScrollableBaseModal<
|
||||
IProps<P, C>,
|
||||
IState
|
||||
> {
|
||||
export class ModuleUiDialog<
|
||||
P extends DialogProps = DialogProps,
|
||||
C extends DialogContent<P> = DialogContent<P>,
|
||||
> extends ScrollableBaseModal<IProps<P, C>, IState> {
|
||||
private contentRef = createRef<C>();
|
||||
|
||||
public constructor(props: IProps<P, C>) {
|
||||
@@ -74,6 +74,11 @@ export class ModuleUiDialog<P extends DialogProps, C extends DialogContent<P>> e
|
||||
...dialogProps,
|
||||
} as unknown as P;
|
||||
|
||||
return <div className="mx_ModuleUiDialog">{this.props.contentFactory(contentProps, this.contentRef)}</div>;
|
||||
// XXX: we have to fudge the types here a little as the react-sdk-module-api lacks React 19 support
|
||||
return (
|
||||
<div className="mx_ModuleUiDialog">
|
||||
{this.props.contentFactory(contentProps, this.contentRef as RefObject<C>)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,12 +135,19 @@ const AccessibleButton = forwardRef(function <T extends ElementType = typeof def
|
||||
placement = "right",
|
||||
onTooltipOpenChange,
|
||||
disableTooltip,
|
||||
role = "button",
|
||||
tabIndex = 0,
|
||||
...restProps
|
||||
}: ButtonProps<T>,
|
||||
ref: Ref<HTMLElementTagNameMap[T]>,
|
||||
): JSX.Element {
|
||||
const newProps = restProps as RenderedElementProps<T>;
|
||||
newProps["aria-label"] = newProps["aria-label"] ?? title;
|
||||
const newProps = {
|
||||
...restProps,
|
||||
tabIndex,
|
||||
role,
|
||||
"aria-label": restProps["aria-label"] ?? title,
|
||||
} as RenderedElementProps<T>;
|
||||
|
||||
if (disabled) {
|
||||
newProps["aria-disabled"] = true;
|
||||
newProps["disabled"] = true;
|
||||
@@ -222,10 +229,6 @@ const AccessibleButton = forwardRef(function <T extends ElementType = typeof def
|
||||
});
|
||||
|
||||
// Type assertion required due to forwardRef type workaround in react.d.ts
|
||||
(AccessibleButton as FunctionComponent).defaultProps = {
|
||||
role: "button",
|
||||
tabIndex: 0,
|
||||
};
|
||||
(AccessibleButton as FunctionComponent).displayName = "AccessibleButton";
|
||||
|
||||
interface RefProp<T extends ElementType> {
|
||||
|
||||
@@ -6,7 +6,14 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type JSX, type ChangeEvent, type ContextType, createRef, type SyntheticEvent } from "react";
|
||||
import React, {
|
||||
type JSX,
|
||||
type ToggleEvent,
|
||||
type ChangeEvent,
|
||||
type ContextType,
|
||||
createRef,
|
||||
type SyntheticEvent,
|
||||
} from "react";
|
||||
import { type MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { type RoomCanonicalAliasEventContent } from "matrix-js-sdk/src/types";
|
||||
@@ -278,7 +285,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
|
||||
});
|
||||
};
|
||||
|
||||
private onLocalAliasesToggled = (event: ChangeEvent<HTMLDetailsElement>): void => {
|
||||
private onLocalAliasesToggled = (event: ToggleEvent<HTMLDetailsElement>): void => {
|
||||
// expanded
|
||||
if (event.currentTarget.open) {
|
||||
// if local aliases haven't been preloaded yet at component mount
|
||||
|
||||
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ReactElement, useCallback, useEffect, useState } from "react";
|
||||
import React, { type JSX, type ReactElement, useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { type NonEmptyArray } from "../../../../../@types/common";
|
||||
import { _t, getCurrentLanguage } from "../../../../../languageHandler";
|
||||
|
||||
@@ -198,7 +198,7 @@ export const options: Opts = {
|
||||
rel: "noreferrer noopener",
|
||||
},
|
||||
|
||||
ignoreTags: ["pre", "code"],
|
||||
ignoreTags: ["a", "pre", "code"],
|
||||
|
||||
className: "linkified",
|
||||
|
||||
|
||||
@@ -9,15 +9,20 @@ Please see LICENSE files in the repository root for full details.
|
||||
import React, { type JSX, type ReactNode } from "react";
|
||||
|
||||
/**
|
||||
* Joins an array into one value with a joiner. E.g. join(["hello", "world"], " ") -> <span>hello world</span>
|
||||
* Joins an array into one value with a joiner. E.g. join(["hello", "world"], " ") -> <>hello world</>
|
||||
* @param array the array of element to join
|
||||
* @param joiner the string/JSX.Element to join with
|
||||
* @returns the joined array
|
||||
*/
|
||||
export function jsxJoin(array: ReactNode[], joiner?: string | JSX.Element): JSX.Element {
|
||||
const newArray: ReactNode[] = [];
|
||||
array.forEach((element, index) => {
|
||||
newArray.push(element, index === array.length - 1 ? null : joiner);
|
||||
});
|
||||
return <span>{newArray}</span>;
|
||||
return (
|
||||
<>
|
||||
{array.map((element, index) => (
|
||||
<React.Fragment key={index}>
|
||||
{element}
|
||||
{index === array.length - 1 ? null : joiner}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import { type IWidget } from "matrix-widget-api";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { type Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||
import { getCallBehaviourWellKnown } from "../utils/WellKnownUtils";
|
||||
import WidgetUtils from "../utils/WidgetUtils";
|
||||
import { type IStoredLayout, WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
|
||||
@@ -37,7 +36,7 @@ function getWidgetBuildUrl(room: Room): string | undefined {
|
||||
return SdkConfig.get().widget_build_url;
|
||||
}
|
||||
|
||||
const wellKnown = getCallBehaviourWellKnown(MatrixClientPeg.safeGet());
|
||||
const wellKnown = getCallBehaviourWellKnown(room.client);
|
||||
if (isDm && wellKnown?.ignore_dm) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ export const mockClientMethodsCrypto = (): Partial<
|
||||
> => ({
|
||||
isKeyBackupKeyStored: jest.fn(),
|
||||
getCrossSigningCacheCallbacks: jest.fn().mockReturnValue({ getCrossSigningKeyCache: jest.fn() }),
|
||||
secretStorage: { hasKey: jest.fn() },
|
||||
secretStorage: { hasKey: jest.fn(), isStored: jest.fn().mockResolvedValue(null) },
|
||||
getCrypto: jest.fn().mockReturnValue({
|
||||
getUserDeviceInfo: jest.fn(),
|
||||
getCrossSigningStatus: jest.fn().mockResolvedValue({
|
||||
|
||||
@@ -7,8 +7,6 @@ exports[`TextForEvent textForJoinRulesEvent() returns correct JSX message when r
|
||||
<AccessibleButton
|
||||
kind="link_inline"
|
||||
onClick={[Function]}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
View settings
|
||||
</AccessibleButton>
|
||||
|
||||
@@ -33,6 +33,10 @@ const EMOJI_SHORTCODES = [
|
||||
// to simply assert that the final completion with the colon is the exact emoji.
|
||||
const TOO_SHORT_EMOJI_SHORTCODE = [{ emojiShortcode: ":o", expectedEmoji: "⭕️" }];
|
||||
|
||||
interface CompletionComponentProps {
|
||||
title: string;
|
||||
}
|
||||
|
||||
describe("EmojiProvider", function () {
|
||||
const testRoom = mkStubRoom(undefined, undefined, undefined);
|
||||
stubClient();
|
||||
@@ -69,8 +73,8 @@ describe("EmojiProvider", function () {
|
||||
|
||||
const ep = new EmojiProvider(testRoom);
|
||||
const completionsList = await ep.getCompletions(":heart", { beginning: true, start: 0, end: 6 });
|
||||
expect(completionsList[0]?.component?.props.title).toEqual(":heartpulse:");
|
||||
expect(completionsList[1]?.component?.props.title).toEqual(":heart_eyes:");
|
||||
expect((completionsList[0]?.component?.props as CompletionComponentProps).title).toEqual(":heartpulse:");
|
||||
expect((completionsList[1]?.component?.props as CompletionComponentProps).title).toEqual(":heart_eyes:");
|
||||
});
|
||||
|
||||
it("Exact match in recently used takes the lead", async function () {
|
||||
@@ -83,8 +87,8 @@ describe("EmojiProvider", function () {
|
||||
const ep = new EmojiProvider(testRoom);
|
||||
const completionsList = await ep.getCompletions(":heart", { beginning: true, start: 0, end: 6 });
|
||||
|
||||
expect(completionsList[0]?.component?.props.title).toEqual(":heart:");
|
||||
expect(completionsList[1]?.component?.props.title).toEqual(":heartpulse:");
|
||||
expect(completionsList[2]?.component?.props.title).toEqual(":heart_eyes:");
|
||||
expect((completionsList[0]?.component?.props as CompletionComponentProps).title).toEqual(":heart:");
|
||||
expect((completionsList[1]?.component?.props as CompletionComponentProps).title).toEqual(":heartpulse:");
|
||||
expect((completionsList[2]?.component?.props as CompletionComponentProps).title).toEqual(":heart_eyes:");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -63,12 +63,12 @@ describe("AutocompleteInput", () => {
|
||||
|
||||
const input = getEditorInput();
|
||||
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
fireEvent.focus(input);
|
||||
fireEvent.change(input, { target: { value: "user" } });
|
||||
await waitFor(() => expect(mockProvider.getCompletions).toHaveBeenCalledTimes(1));
|
||||
});
|
||||
|
||||
await waitFor(() => expect(mockProvider.getCompletions).toHaveBeenCalledTimes(1));
|
||||
expect(screen.getByTestId("autocomplete-matches").childNodes).toHaveLength(mockCompletion.length);
|
||||
});
|
||||
|
||||
@@ -152,12 +152,12 @@ describe("AutocompleteInput", () => {
|
||||
|
||||
const input = getEditorInput();
|
||||
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
fireEvent.focus(input);
|
||||
fireEvent.change(input, { target: { value: "user" } });
|
||||
await waitFor(() => expect(mockProvider.getCompletions).toHaveBeenCalledTimes(1));
|
||||
});
|
||||
|
||||
await waitFor(() => expect(mockProvider.getCompletions).toHaveBeenCalledTimes(1));
|
||||
expect(screen.getAllByTestId("custom-suggestion-element")).toHaveLength(mockCompletion.length);
|
||||
});
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ describe("<MatrixChat />", () => {
|
||||
startup: jest.fn(),
|
||||
},
|
||||
login: jest.fn(),
|
||||
loginFlows: jest.fn(),
|
||||
loginFlows: jest.fn().mockResolvedValue({ flows: [] }),
|
||||
isGuest: jest.fn().mockReturnValue(false),
|
||||
clearStores: jest.fn(),
|
||||
setGuest: jest.fn(),
|
||||
@@ -165,12 +165,9 @@ describe("<MatrixChat />", () => {
|
||||
isNameResolvable: true,
|
||||
warning: "",
|
||||
};
|
||||
let initPromise: Promise<void> | undefined;
|
||||
let defaultProps: ComponentProps<typeof MatrixChat>;
|
||||
const getComponent = (props: Partial<ComponentProps<typeof MatrixChat>> = {}) => {
|
||||
// MatrixChat does many questionable things which bomb tests in modern React mode,
|
||||
// we'll want to refactor and break up MatrixChat before turning off legacyRoot mode
|
||||
return render(<MatrixChat {...defaultProps} {...props} />, { legacyRoot: true });
|
||||
return render(<MatrixChat {...defaultProps} {...props} />);
|
||||
};
|
||||
|
||||
// make test results readable
|
||||
@@ -220,6 +217,8 @@ describe("<MatrixChat />", () => {
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
localStorage.clear();
|
||||
jest.restoreAllMocks();
|
||||
defaultProps = {
|
||||
config: {
|
||||
brand: "Test",
|
||||
@@ -235,10 +234,8 @@ describe("<MatrixChat />", () => {
|
||||
onNewScreen: jest.fn(),
|
||||
onTokenLoginCompleted: jest.fn(),
|
||||
realQueryParams: {},
|
||||
initPromiseCallback: (p: Promise<void>) => (initPromise = p),
|
||||
};
|
||||
|
||||
initPromise = undefined;
|
||||
mockClient = getMockClientWithEventEmitter(getMockClientMethods());
|
||||
jest.spyOn(MatrixJs, "createClient").mockReturnValue(mockClient);
|
||||
|
||||
@@ -257,18 +254,9 @@ describe("<MatrixChat />", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Wait for the promise that MatrixChat gives us to complete so that we know
|
||||
// it's finished running its login code. We either need to do this or make the
|
||||
// login code abort halfway through once the test finishes testing whatever it
|
||||
// needs to test. If we do nothing, the login code will just continue running
|
||||
// and interfere with the subsequent tests.
|
||||
await initPromise;
|
||||
|
||||
// @ts-ignore
|
||||
DMRoomMap.setShared(null);
|
||||
|
||||
jest.restoreAllMocks();
|
||||
|
||||
// emit a loggedOut event so that all of the Store singletons forget about their references to the mock client
|
||||
// (must be sync otherwise the next test will start before it happens)
|
||||
act(() => defaultDispatcher.dispatch({ action: Action.OnLoggedOut }, true));
|
||||
@@ -313,7 +301,6 @@ describe("<MatrixChat />", () => {
|
||||
state: state,
|
||||
};
|
||||
|
||||
const userId = "@alice:server.org";
|
||||
const deviceId = "test-device-id";
|
||||
const accessToken = "test-access-token-from-oidc";
|
||||
|
||||
@@ -335,8 +322,6 @@ describe("<MatrixChat />", () => {
|
||||
const dialog = await screen.findByRole("dialog");
|
||||
|
||||
expect(within(dialog).getByText(errorMessage)).toBeInTheDocument();
|
||||
// just check we're back on welcome page
|
||||
await expect(screen.findByTestId("mx_welcome_screen")).resolves.toBeInTheDocument();
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -518,6 +503,9 @@ describe("<MatrixChat />", () => {
|
||||
it("should set logged in and start MatrixClient", async () => {
|
||||
getComponent({ realQueryParams });
|
||||
|
||||
defaultDispatcher.dispatch({
|
||||
action: "will_start_client",
|
||||
});
|
||||
// client successfully started
|
||||
await waitFor(() =>
|
||||
expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({ action: "client_started" }),
|
||||
@@ -597,9 +585,7 @@ describe("<MatrixChat />", () => {
|
||||
// wait for logged in view to load
|
||||
await screen.findByLabelText("User menu");
|
||||
|
||||
expect(screen.queryByRole("progressbar")).not.toBeInTheDocument();
|
||||
const h1Element = screen.getByRole("heading", { level: 1 });
|
||||
expect(h1Element).toHaveTextContent(`Welcome Ernie`);
|
||||
await screen.findByRole("heading", { level: 1, name: "Welcome Ernie" });
|
||||
});
|
||||
|
||||
describe("clean up drafts", () => {
|
||||
@@ -612,9 +598,6 @@ describe("<MatrixChat />", () => {
|
||||
localStorage.setItem(`mx_cider_state_${roomId}`, "fake_content");
|
||||
mockClient.getRoom.mockImplementation((id) => [room].find((room) => room.roomId === id) || null);
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
it("should clean up drafts", async () => {
|
||||
Date.now = jest.fn(() => timestamp);
|
||||
localStorage.setItem(`mx_cider_state_${roomId}`, "fake_content");
|
||||
@@ -1113,8 +1096,6 @@ describe("<MatrixChat />", () => {
|
||||
"org.matrix.e2e_cross_signing",
|
||||
);
|
||||
|
||||
await flushPromises();
|
||||
|
||||
// logged in
|
||||
await screen.findByLabelText("User menu");
|
||||
});
|
||||
@@ -1210,7 +1191,6 @@ describe("<MatrixChat />", () => {
|
||||
};
|
||||
|
||||
let loginClient!: ReturnType<typeof getMockClientWithEventEmitter>;
|
||||
const userId = "@alice:server.org";
|
||||
const deviceId = "test-device-id";
|
||||
const accessToken = "test-access-token";
|
||||
const clientLoginResponse = {
|
||||
@@ -1304,6 +1284,7 @@ describe("<MatrixChat />", () => {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("should clear storage", async () => {
|
||||
const localStorageClearSpy = jest.spyOn(localStorage.__proto__, "clear");
|
||||
|
||||
@@ -1349,6 +1330,9 @@ describe("<MatrixChat />", () => {
|
||||
|
||||
it("should continue to post login setup when no session is found in local storage", async () => {
|
||||
getComponent({ realQueryParams });
|
||||
defaultDispatcher.dispatch({
|
||||
action: "will_start_client",
|
||||
});
|
||||
|
||||
// logged in but waiting for sync screen
|
||||
await screen.findByText("Logout");
|
||||
@@ -1604,8 +1588,13 @@ describe("<MatrixChat />", () => {
|
||||
});
|
||||
await flushPromises();
|
||||
mockClient.emit(CryptoEvent.KeyBackupFailed, "error code");
|
||||
await waitFor(() => expect(spy).toHaveBeenCalledTimes(1));
|
||||
expect((spy.mock.lastCall![0] as any)._payload._result).toEqual(expect.objectContaining({ __test: true }));
|
||||
await waitFor(() =>
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
_payload: expect.objectContaining({ _result: expect.objectContaining({ __test: true }) }),
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it("should show the recovery method removed dialog", async () => {
|
||||
@@ -1622,8 +1611,13 @@ describe("<MatrixChat />", () => {
|
||||
});
|
||||
await flushPromises();
|
||||
mockClient.emit(CryptoEvent.KeyBackupFailed, "error code");
|
||||
await waitFor(() => expect(spy).toHaveBeenCalledTimes(1));
|
||||
expect((spy.mock.lastCall![0] as any)._payload._result).toEqual(expect.objectContaining({ __test: true }));
|
||||
await waitFor(() =>
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
_payload: expect.objectContaining({ _result: expect.objectContaining({ __test: true }) }),
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -148,6 +148,8 @@ describe("PipContainer", () => {
|
||||
WidgetStore.instance.addVirtualWidget(call.widget, room.roomId);
|
||||
WidgetMessagingStore.instance.storeMessaging(widget, room.roomId, {
|
||||
stop: () => {},
|
||||
hasCapability: jest.fn(),
|
||||
feedStateUpdate: jest.fn().mockResolvedValue(undefined),
|
||||
} as unknown as ClientWidgetApi);
|
||||
|
||||
await call.start();
|
||||
@@ -271,7 +273,10 @@ describe("PipContainer", () => {
|
||||
Parameters<ClientWidgetApi["transport"]["send"]>
|
||||
>()
|
||||
.mockResolvedValue({});
|
||||
const mockMessaging = { transport: { send: sendSpy }, stop: () => {} } as unknown as ClientWidgetApi;
|
||||
const mockMessaging = {
|
||||
transport: { send: sendSpy },
|
||||
stop: () => {},
|
||||
} as unknown as ClientWidgetApi;
|
||||
WidgetMessagingStore.instance.storeMessaging(new Widget(widget), room.roomId, mockMessaging);
|
||||
await user.click(screen.getByRole("button", { name: "Leave" }));
|
||||
expect(sendSpy).toHaveBeenCalledWith(ElementWidgetActions.HangupCall, {});
|
||||
|
||||
@@ -108,9 +108,7 @@ exports[`MessagePanel should handle lots of membership events quickly 1`] = `
|
||||
<span
|
||||
class="mx_TextualEvent mx_GenericEventListSummary_summary"
|
||||
>
|
||||
<span>
|
||||
@user:id made no changes 100 times
|
||||
</span>
|
||||
@user:id made no changes 100 times
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -197,7 +197,7 @@ describe("<TextualBody />", () => {
|
||||
const { container } = getComponent({ mxEvent: ev });
|
||||
const content = container.querySelector(".mx_EventTile_body");
|
||||
expect(content.innerHTML).toMatchInlineSnapshot(
|
||||
`"Chat with <bdi><a class="mx_Pill mx_UserPill mx_UserPill_me" href="https://matrix.to/#/@user:example.com"><span aria-label="Profile picture" aria-hidden="true" data-testid="avatar-img" data-type="round" data-color="2" class="_avatar_1qbcf_8 mx_BaseAvatar" style="--cpd-avatar-size: 16px;"><img loading="lazy" alt="" src="mxc://avatar.url/image.png" referrerpolicy="no-referrer" class="_image_1qbcf_41" data-type="round" width="16px" height="16px"></span><span class="mx_Pill_text">Member</span></a></bdi>"`,
|
||||
`"Chat with <bdi><a class="mx_Pill mx_UserPill mx_UserPill_me" href="https://matrix.to/#/@user:example.com"><span aria-label="Profile picture" aria-hidden="true" data-testid="avatar-img" data-type="round" data-color="2" class="_avatar_1qbcf_8 mx_BaseAvatar" style="--cpd-avatar-size: 16px;"><img loading="lazy" alt="" referrerpolicy="no-referrer" class="_image_1qbcf_41" data-type="round" width="16px" height="16px" src="mxc://avatar.url/image.png"></span><span class="mx_Pill_text">Member</span></a></bdi>"`,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -510,9 +510,9 @@ exports[`<TextualBody /> renders plain-text m.text correctly linkification get a
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<TextualBody /> renders plain-text m.text correctly should pillify a permalink to a message in the same room with the label »Message from Member« 1`] = `"Visit <bdi><a class="mx_Pill mx_EventPill" href="https://matrix.to/#/!room1:example.com/%event_id%"><span aria-label="Profile picture" aria-hidden="true" data-testid="avatar-img" data-type="round" data-color="2" class="_avatar_1qbcf_8 mx_BaseAvatar" style="--cpd-avatar-size: 16px;"><img loading="lazy" alt="" src="mxc://avatar.url/image.png" referrerpolicy="no-referrer" class="_image_1qbcf_41" data-type="round" width="16px" height="16px"></span><span class="mx_Pill_text">Message from Member</span></a></bdi>"`;
|
||||
exports[`<TextualBody /> renders plain-text m.text correctly should pillify a permalink to a message in the same room with the label »Message from Member« 1`] = `"Visit <bdi><a class="mx_Pill mx_EventPill" href="https://matrix.to/#/!room1:example.com/%event_id%"><span aria-label="Profile picture" aria-hidden="true" data-testid="avatar-img" data-type="round" data-color="2" class="_avatar_1qbcf_8 mx_BaseAvatar" style="--cpd-avatar-size: 16px;"><img loading="lazy" alt="" referrerpolicy="no-referrer" class="_image_1qbcf_41" data-type="round" width="16px" height="16px" src="mxc://avatar.url/image.png"></span><span class="mx_Pill_text">Message from Member</span></a></bdi>"`;
|
||||
|
||||
exports[`<TextualBody /> renders plain-text m.text correctly should pillify a permalink to an event in another room with the label »Message in Room 2« 1`] = `"Visit <bdi><a class="mx_Pill mx_EventPill" href="https://matrix.to/#/!room2:example.com/%event_id%"><span aria-label="Avatar" aria-hidden="true" data-testid="avatar-img" data-type="round" data-color="2" class="_avatar_1qbcf_8 mx_BaseAvatar" style="--cpd-avatar-size: 16px;"><img loading="lazy" alt="" src="mxc://avatar.url/room.png" referrerpolicy="no-referrer" class="_image_1qbcf_41" data-type="round" width="16px" height="16px"></span><span class="mx_Pill_text">Message in Room 2</span></a></bdi>"`;
|
||||
exports[`<TextualBody /> renders plain-text m.text correctly should pillify a permalink to an event in another room with the label »Message in Room 2« 1`] = `"Visit <bdi><a class="mx_Pill mx_EventPill" href="https://matrix.to/#/!room2:example.com/%event_id%"><span aria-label="Avatar" aria-hidden="true" data-testid="avatar-img" data-type="round" data-color="2" class="_avatar_1qbcf_8 mx_BaseAvatar" style="--cpd-avatar-size: 16px;"><img loading="lazy" alt="" referrerpolicy="no-referrer" class="_image_1qbcf_41" data-type="round" width="16px" height="16px" src="mxc://avatar.url/room.png"></span><span class="mx_Pill_text">Message in Room 2</span></a></bdi>"`;
|
||||
|
||||
exports[`<TextualBody /> renders plain-text m.text correctly should pillify a permalink to an unknown message in the same room with the label »Message« 1`] = `
|
||||
<div
|
||||
|
||||
@@ -91,7 +91,7 @@ exports[`<PollHistory /> renders a list of active polls when there are polls in
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
aria-labelledby=":rc:"
|
||||
aria-labelledby=":ra:"
|
||||
class="mx_PollListItem_content"
|
||||
>
|
||||
<span>
|
||||
@@ -116,7 +116,7 @@ exports[`<PollHistory /> renders a list of active polls when there are polls in
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
aria-labelledby=":rh:"
|
||||
aria-labelledby=":rf:"
|
||||
class="mx_PollListItem_content"
|
||||
>
|
||||
<span>
|
||||
|
||||
@@ -467,7 +467,7 @@ describe("<UserInfo />", () => {
|
||||
|
||||
await expect(screen.findByRole("button", { name: "Deactivate user" })).resolves.toBeInTheDocument();
|
||||
if (screen.queryAllByRole("progressbar").length) {
|
||||
await waitForElementToBeRemoved(() => screen.queryAllByRole("progressbar"));
|
||||
await act(() => waitForElementToBeRemoved(() => screen.queryAllByRole("progressbar")));
|
||||
}
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ exports[`<UserInfo /> with crypto enabled renders <BasicUserInfo /> 1`] = `
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
aria-labelledby=":r6m:"
|
||||
aria-labelledby=":r6i:"
|
||||
class="_icon-button_m2erp_8 _subtle-bg_m2erp_29"
|
||||
data-testid="base-card-close-button"
|
||||
role="button"
|
||||
@@ -305,7 +305,7 @@ exports[`<UserInfo /> with crypto enabled should render a deactivate button for
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
aria-labelledby=":r70:"
|
||||
aria-labelledby=":r6s:"
|
||||
class="_icon-button_m2erp_8 _subtle-bg_m2erp_29"
|
||||
data-testid="base-card-close-button"
|
||||
role="button"
|
||||
@@ -401,21 +401,13 @@ exports[`<UserInfo /> with crypto enabled should render a deactivate button for
|
||||
class="mx_Flex mx_UserInfo_verification"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: center; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<svg
|
||||
class="_icon_11k6c_18"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
style="width: 24px; height: 24px;"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
<p
|
||||
class="_typography_6v6n8_153 _font-body-sm-regular_6v6n8_31 mx_UserInfo_verification_unavailable"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M12 4.031a8 8 0 1 0 8 8 1 1 0 0 1 2 0c0 5.523-4.477 10-10 10s-10-4.477-10-10 4.477-10 10-10a1 1 0 1 1 0 2"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
(
|
||||
User verification unavailable
|
||||
)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -55,7 +55,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
|
||||
style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
|
||||
>
|
||||
<svg
|
||||
aria-labelledby=":r166:"
|
||||
aria-labelledby=":r15i:"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -71,7 +71,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
|
||||
<button
|
||||
aria-disabled="true"
|
||||
aria-label="There's no one here to call"
|
||||
aria-labelledby=":r16b:"
|
||||
aria-labelledby=":r15n:"
|
||||
class="_icon-button_m2erp_8"
|
||||
role="button"
|
||||
style="--cpd-icon-button-size: 32px;"
|
||||
@@ -96,7 +96,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
|
||||
</button>
|
||||
<button
|
||||
aria-label="Threads"
|
||||
aria-labelledby=":r16g:"
|
||||
aria-labelledby=":r15s:"
|
||||
class="_icon-button_m2erp_8"
|
||||
role="button"
|
||||
style="--cpd-icon-button-size: 32px;"
|
||||
@@ -122,7 +122,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
|
||||
</button>
|
||||
<button
|
||||
aria-label="Room info"
|
||||
aria-labelledby=":r16l:"
|
||||
aria-labelledby=":r161:"
|
||||
class="_icon-button_m2erp_8"
|
||||
role="button"
|
||||
style="--cpd-icon-button-size: 32px;"
|
||||
|
||||
@@ -84,12 +84,12 @@ describe("<AddPrivilegedUsers />", () => {
|
||||
// Find some suggestions and select them.
|
||||
const autocompleteInput = getByTestId("autocomplete-input");
|
||||
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
fireEvent.focus(autocompleteInput);
|
||||
fireEvent.change(autocompleteInput, { target: { value: "u" } });
|
||||
await waitFor(() => expect(provider.mock.instances[0].getCompletions).toHaveBeenCalledTimes(1));
|
||||
});
|
||||
|
||||
await waitFor(() => expect(provider.mock.instances[0].getCompletions).toHaveBeenCalledTimes(1));
|
||||
const matchOne = getByTestId("autocomplete-suggestion-item-@user_1:host.local");
|
||||
const matchTwo = getByTestId("autocomplete-suggestion-item-@user_2:host.local");
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
flushPromises,
|
||||
getMockClientWithEventEmitter,
|
||||
mkPusher,
|
||||
mockClientMethodsCrypto,
|
||||
mockClientMethodsServer,
|
||||
mockClientMethodsUser,
|
||||
mockPlatformPeg,
|
||||
@@ -124,10 +125,11 @@ describe("<SessionManagerTab />", () => {
|
||||
|
||||
const mockCrypto = mocked({
|
||||
getDeviceVerificationStatus: jest.fn(),
|
||||
getUserDeviceInfo: jest.fn(),
|
||||
getUserDeviceInfo: jest.fn().mockResolvedValue(new Map()),
|
||||
requestDeviceVerification: jest.fn().mockResolvedValue(mockVerificationRequest),
|
||||
supportsSecretsForQrLogin: jest.fn().mockReturnValue(false),
|
||||
isCrossSigningReady: jest.fn().mockReturnValue(true),
|
||||
getVerificationRequestsToDeviceInProgress: jest.fn().mockReturnValue([]),
|
||||
} as unknown as CryptoApi);
|
||||
|
||||
let mockClient!: MockedObject<MatrixClient>;
|
||||
@@ -203,6 +205,7 @@ describe("<SessionManagerTab />", () => {
|
||||
mockClient = getMockClientWithEventEmitter({
|
||||
...mockClientMethodsUser(aliceId),
|
||||
...mockClientMethodsServer(),
|
||||
...mockClientMethodsCrypto(),
|
||||
getCrypto: jest.fn().mockReturnValue(mockCrypto),
|
||||
getDevices: jest.fn(),
|
||||
getDeviceId: jest.fn().mockReturnValue(deviceId),
|
||||
|
||||
@@ -224,7 +224,7 @@ exports[`ThreadsActivityCentre should close the release announcement when the TA
|
||||
<div
|
||||
data-radix-popper-content-wrapper=""
|
||||
dir="ltr"
|
||||
style="position: fixed; left: 0px; top: 0px; transform: translate(0px, -8px); min-width: max-content; --radix-popper-available-width: 0px; --radix-popper-available-height: -8px; --radix-popper-anchor-width: 0px; --radix-popper-anchor-height: 0px; --radix-popper-transform-origin: 0% 0px;"
|
||||
style="position: fixed; left: 0px; top: 0px; transform: translate(0px, -8px); min-width: max-content; --radix-popper-transform-origin: 0% 0px; --radix-popper-available-width: 0px; --radix-popper-available-height: -8px; --radix-popper-anchor-width: 0px; --radix-popper-anchor-height: 0px;"
|
||||
>
|
||||
<div
|
||||
aria-labelledby="radix-:r1c:"
|
||||
|
||||
@@ -1,48 +1,72 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`FormattingUtils formatList should return expected sentence in ReactNode when given 2 React children 1`] = `
|
||||
<span>
|
||||
<span>
|
||||
a
|
||||
</span>
|
||||
and
|
||||
<span>
|
||||
b
|
||||
</span>
|
||||
</span>
|
||||
<React.Fragment>
|
||||
<React.Fragment>
|
||||
<span>
|
||||
a
|
||||
</span>
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
and
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
<span>
|
||||
b
|
||||
</span>
|
||||
</React.Fragment>
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
||||
exports[`FormattingUtils formatList should return expected sentence in ReactNode when given more React children 1`] = `
|
||||
<span>
|
||||
<span>
|
||||
a
|
||||
</span>
|
||||
,
|
||||
<span>
|
||||
b
|
||||
</span>
|
||||
,
|
||||
<span>
|
||||
c
|
||||
</span>
|
||||
and
|
||||
<span>
|
||||
d
|
||||
</span>
|
||||
</span>
|
||||
<React.Fragment>
|
||||
<React.Fragment>
|
||||
<span>
|
||||
a
|
||||
</span>
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
,
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
<span>
|
||||
b
|
||||
</span>
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
,
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
<span>
|
||||
c
|
||||
</span>
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
and
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
<span>
|
||||
d
|
||||
</span>
|
||||
</React.Fragment>
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
||||
exports[`FormattingUtils formatList should return expected sentence in ReactNode when using itemLimit 1`] = `
|
||||
<span>
|
||||
<span>
|
||||
<span>
|
||||
a
|
||||
</span>
|
||||
,
|
||||
<span>
|
||||
b
|
||||
</span>
|
||||
</span>
|
||||
<React.Fragment>
|
||||
<React.Fragment>
|
||||
<span>
|
||||
a
|
||||
</span>
|
||||
,
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
<span>
|
||||
b
|
||||
</span>
|
||||
</React.Fragment>
|
||||
</React.Fragment>
|
||||
and 2 others
|
||||
</span>
|
||||
`;
|
||||
|
||||
@@ -253,8 +253,9 @@ describe("export", function () {
|
||||
},
|
||||
setProgressText,
|
||||
);
|
||||
const imageRegex = /<img.+ src="mxc:\/\/test.org" alt="image\.png"\/?>/;
|
||||
expect(imageRegex.test(renderToString(exporter.getEventTile(mkImageEvent(), true)))).toBeTruthy();
|
||||
expect(renderToString(exporter.getEventTile(mkImageEvent(), true))).toMatch(
|
||||
/<img.+ alt="image\.png" src="mxc:\/\/test.org"\/?>/,
|
||||
);
|
||||
});
|
||||
|
||||
const invalidExportOptions: [string, IExportOptions][] = [
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -116,7 +116,7 @@ describe("Permalinks", function () {
|
||||
|
||||
it("should gracefully handle invalid MXIDs", () => {
|
||||
const roomId = "!fake:example.org";
|
||||
const alice50 = makeMemberWithPL(roomId, "@alice:pl_50:org", 50);
|
||||
const alice50 = makeMemberWithPL(roomId, "@alice:pl-50:org", 50);
|
||||
const room = mockRoom(roomId, [alice50]);
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
|
||||
62
yarn.lock
62
yarn.lock
@@ -3376,10 +3376,10 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-dom@18.3.5":
|
||||
version "18.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.5.tgz#45f9f87398c5dcea085b715c58ddcf1faf65f716"
|
||||
integrity sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==
|
||||
"@types/react-dom@19.0.4":
|
||||
version "19.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.0.4.tgz#bedba97f9346bd4c0fe5d39e689713804ec9ac89"
|
||||
integrity sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==
|
||||
|
||||
"@types/react-redux@^7.1.20":
|
||||
version "7.1.34"
|
||||
@@ -3404,12 +3404,11 @@
|
||||
"@types/prop-types" "*"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@18.3.18":
|
||||
version "18.3.18"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.18.tgz#9b382c4cd32e13e463f97df07c2ee3bbcd26904b"
|
||||
integrity sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==
|
||||
"@types/react@*", "@types/react@19.0.10":
|
||||
version "19.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.10.tgz#d0c66dafd862474190fe95ce11a68de69ed2b0eb"
|
||||
integrity sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/retry@0.12.0":
|
||||
@@ -8936,7 +8935,7 @@ long@^5.2.0:
|
||||
resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1"
|
||||
integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==
|
||||
|
||||
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||
loose-envify@^1.0.0, loose-envify@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
@@ -10856,13 +10855,12 @@ react-clientside-effect@^1.2.7:
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.13"
|
||||
|
||||
react-dom@^18.3.1:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
|
||||
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
|
||||
react-dom@^19.0.0:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57"
|
||||
integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
scheduler "^0.23.2"
|
||||
scheduler "^0.25.0"
|
||||
|
||||
react-focus-lock@^2.5.1:
|
||||
version "2.13.6"
|
||||
@@ -10876,21 +10874,21 @@ react-focus-lock@^2.5.1:
|
||||
use-callback-ref "^1.3.3"
|
||||
use-sidecar "^1.1.3"
|
||||
|
||||
react-is@19.0.0, react-is@^17.0.1, react-is@^18.0.0:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.0.0.tgz#d6669fd389ff022a9684f708cf6fa4962d1fea7a"
|
||||
integrity sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==
|
||||
|
||||
react-is@^16.13.1, react-is@^16.7.0:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-is@^17.0.1, react-is@^17.0.2:
|
||||
react-is@^17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||
|
||||
react-is@^18.0.0:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
|
||||
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
|
||||
|
||||
react-lifecycles-compat@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
@@ -10968,12 +10966,10 @@ react-virtualized@^9.22.5:
|
||||
prop-types "^15.7.2"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
react@^18.3.1:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
|
||||
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
react@^19.0.0:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd"
|
||||
integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
|
||||
|
||||
read-cache@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -11411,12 +11407,10 @@ saxes@^6.0.0:
|
||||
dependencies:
|
||||
xmlchars "^2.2.0"
|
||||
|
||||
scheduler@^0.23.2:
|
||||
version "0.23.2"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
|
||||
integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
scheduler@^0.25.0:
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015"
|
||||
integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==
|
||||
|
||||
schema-utils@^3.0.0:
|
||||
version "3.3.0"
|
||||
|
||||
Reference in New Issue
Block a user