Compare commits

...
Sign in to create a new pull request.

10 commits

Author SHA1 Message Date
Michael Telatynski
6946b90b11
Iterate
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-12-05 13:27:34 +00:00
Michael Telatynski
c3f3c9364f
Fix MapMock
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-12-05 13:14:13 +00:00
Michael Telatynski
72f155640d
Make React compiler happy about some frankly non-issues
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-12-05 12:59:53 +00:00
Michael Telatynski
b597abf567
Fix mutation of external values in hooks
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-12-05 12:59:35 +00:00
Michael Telatynski
9443426edb
Fix usage of useRef as memoization
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-12-05 12:57:39 +00:00
Michael Telatynski
6c2334c029
Merge branch 't3chguy/useId' of https://github.com/vector-im/element-web into t3chguy/react-compiler-eslint 2024-12-05 12:37:04 +00:00
Michael Telatynski
eb1a09a912
Disable in tests
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-12-05 12:32:36 +00:00
Michael Telatynski
e730074e1b
Fix an easy one
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-12-05 12:31:33 +00:00
Michael Telatynski
c8c5ef5e6e
Enable react-compiler eslint
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-12-05 12:31:18 +00:00
Michael Telatynski
b61a2225b7
Switch to React18 useId
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-12-05 12:28:27 +00:00
17 changed files with 110 additions and 89 deletions

View file

@ -1,5 +1,5 @@
module.exports = { module.exports = {
plugins: ["matrix-org"], plugins: ["matrix-org", "eslint-plugin-react-compiler"],
extends: ["plugin:matrix-org/babel", "plugin:matrix-org/react", "plugin:matrix-org/a11y"], extends: ["plugin:matrix-org/babel", "plugin:matrix-org/react", "plugin:matrix-org/a11y"],
parserOptions: { parserOptions: {
project: ["./tsconfig.json"], project: ["./tsconfig.json"],
@ -170,6 +170,8 @@ module.exports = {
"jsx-a11y/role-supports-aria-props": "off", "jsx-a11y/role-supports-aria-props": "off",
"matrix-org/require-copyright-header": "error", "matrix-org/require-copyright-header": "error",
"react-compiler/react-compiler": "error",
}, },
overrides: [ overrides: [
{ {
@ -262,6 +264,7 @@ module.exports = {
// These are fine in tests // These are fine in tests
"no-restricted-globals": "off", "no-restricted-globals": "off",
"react-compiler/react-compiler": "off",
}, },
}, },
{ {

View file

@ -17,6 +17,7 @@ class MockMap extends EventEmitter {
setCenter = jest.fn(); setCenter = jest.fn();
setStyle = jest.fn(); setStyle = jest.fn();
fitBounds = jest.fn(); fitBounds = jest.fn();
remove = jest.fn();
} }
const MockMapInstance = new MockMap(); const MockMapInstance = new MockMap();

View file

@ -233,6 +233,7 @@
"eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-matrix-org": "^2.0.2", "eslint-plugin-matrix-org": "^2.0.2",
"eslint-plugin-react": "^7.28.0", "eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-compiler": "^19.0.0-beta-df7b47d-20241124",
"eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-unicorn": "^56.0.0", "eslint-plugin-unicorn": "^56.0.0",
"express": "^4.18.2", "express": "^4.18.2",

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details. Please see LICENSE files in the repository root for full details.
*/ */
import React, { forwardRef, useCallback, useContext, useEffect, useRef, useState } from "react"; import React, { forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
import { import {
ISearchResults, ISearchResults,
IThreadBundledRelationship, IThreadBundledRelationship,
@ -58,7 +58,7 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
const [results, setResults] = useState<ISearchResults | null>(null); const [results, setResults] = useState<ISearchResults | null>(null);
const aborted = useRef(false); const aborted = useRef(false);
// A map from room ID to permalink creator // A map from room ID to permalink creator
const permalinkCreators = useRef(new Map<string, RoomPermalinkCreator>()).current; const permalinkCreators = useMemo(() => new Map<string, RoomPermalinkCreator>(), []);
const innerRef = useRef<ScrollPanel | null>(); const innerRef = useRef<ScrollPanel | null>();
useEffect(() => { useEffect(() => {

View file

@ -58,11 +58,10 @@ const EffectsOverlay: FunctionComponent<IProps> = ({ roomWidth }) => {
if (canvas) canvas.height = UIStore.instance.windowHeight; if (canvas) canvas.height = UIStore.instance.windowHeight;
UIStore.instance.on(UI_EVENTS.Resize, resize); UIStore.instance.on(UI_EVENTS.Resize, resize);
const currentEffects = effectsRef.current; // this is not a react node ref, warning can be safely ignored
return () => { return () => {
dis.unregister(dispatcherRef); dis.unregister(dispatcherRef);
UIStore.instance.off(UI_EVENTS.Resize, resize); UIStore.instance.off(UI_EVENTS.Resize, resize);
// eslint-disable-next-line react-hooks/exhaustive-deps
const currentEffects = effectsRef.current; // this is not a react node ref, warning can be safely ignored
for (const effect in currentEffects) { for (const effect in currentEffects) {
const effectModule: ICanvasEffect = currentEffects.get(effect)!; const effectModule: ICanvasEffect = currentEffects.get(effect)!;
if (effectModule && effectModule.isRunning) { if (effectModule && effectModule.isRunning) {

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details. Please see LICENSE files in the repository root for full details.
*/ */
import React, { ForwardedRef, forwardRef, MutableRefObject, useRef } from "react"; import React, { ForwardedRef, forwardRef, MutableRefObject, useMemo } from "react";
import classNames from "classnames"; import classNames from "classnames";
import EditorStateTransfer from "../../../../utils/EditorStateTransfer"; import EditorStateTransfer from "../../../../utils/EditorStateTransfer";
@ -44,7 +44,7 @@ export default function EditWysiwygComposer({
className, className,
...props ...props
}: EditWysiwygComposerProps): JSX.Element { }: EditWysiwygComposerProps): JSX.Element {
const defaultContextValue = useRef(getDefaultContextValue({ editorStateTransfer })); const defaultContextValue = useMemo(() => getDefaultContextValue({ editorStateTransfer }), []);
const initialContent = useInitialContent(editorStateTransfer); const initialContent = useInitialContent(editorStateTransfer);
const isReady = !editorStateTransfer || initialContent !== undefined; const isReady = !editorStateTransfer || initialContent !== undefined;
@ -55,7 +55,7 @@ export default function EditWysiwygComposer({
} }
return ( return (
<ComposerContext.Provider value={defaultContextValue.current}> <ComposerContext.Provider value={defaultContextValue}>
<WysiwygComposer <WysiwygComposer
className={classNames("mx_EditWysiwygComposer", className)} className={classNames("mx_EditWysiwygComposer", className)}
initialContent={initialContent} initialContent={initialContent}

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details. Please see LICENSE files in the repository root for full details.
*/ */
import React, { ForwardedRef, forwardRef, MutableRefObject, useRef } from "react"; import React, { ForwardedRef, forwardRef, MutableRefObject, useMemo } from "react";
import { IEventRelation } from "matrix-js-sdk/src/matrix"; import { IEventRelation } from "matrix-js-sdk/src/matrix";
import { useWysiwygSendActionHandler } from "./hooks/useWysiwygSendActionHandler"; import { useWysiwygSendActionHandler } from "./hooks/useWysiwygSendActionHandler";
@ -52,10 +52,10 @@ export default function SendWysiwygComposer({
...props ...props
}: SendWysiwygComposerProps): JSX.Element { }: SendWysiwygComposerProps): JSX.Element {
const Composer = isRichTextEnabled ? WysiwygComposer : PlainTextComposer; const Composer = isRichTextEnabled ? WysiwygComposer : PlainTextComposer;
const defaultContextValue = useRef(getDefaultContextValue({ eventRelation: props.eventRelation })); const defaultContextValue = useMemo(() => getDefaultContextValue({ eventRelation: props.eventRelation }), []);
return ( return (
<ComposerContext.Provider value={defaultContextValue.current}> <ComposerContext.Provider value={defaultContextValue}>
<Composer <Composer
className="mx_SendWysiwygComposer" className="mx_SendWysiwygComposer"
leftComponent={e2eStatus && <E2EIcon status={e2eStatus} />} leftComponent={e2eStatus && <E2EIcon status={e2eStatus} />}

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details. Please see LICENSE files in the repository root for full details.
*/ */
import React, { ReactNode, createRef, useCallback, useEffect, useState } from "react"; import React, { ReactNode, createRef, useCallback, useEffect, useState, useId } from "react";
import EditIcon from "@vector-im/compound-design-tokens/assets/web/icons/edit"; import EditIcon from "@vector-im/compound-design-tokens/assets/web/icons/edit";
import UploadIcon from "@vector-im/compound-design-tokens/assets/web/icons/share"; import UploadIcon from "@vector-im/compound-design-tokens/assets/web/icons/share";
import DeleteIcon from "@vector-im/compound-design-tokens/assets/web/icons/delete"; import DeleteIcon from "@vector-im/compound-design-tokens/assets/web/icons/delete";
@ -16,7 +16,6 @@ import classNames from "classnames";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { mediaFromMxc } from "../../../customisations/Media"; import { mediaFromMxc } from "../../../customisations/Media";
import { chromeFileInputFix } from "../../../utils/BrowserWorkarounds"; import { chromeFileInputFix } from "../../../utils/BrowserWorkarounds";
import { useId } from "../../../utils/useId";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";
import BaseAvatar from "../avatars/BaseAvatar"; import BaseAvatar from "../avatars/BaseAvatar";
import Modal from "../../../Modal.tsx"; import Modal from "../../../Modal.tsx";

View file

@ -6,7 +6,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
import React, { ChangeEvent, JSX, useCallback, useMemo, useRef, useState } from "react"; import React, { ChangeEvent, JSX, useCallback, useMemo, useState } from "react";
import { import {
InlineField, InlineField,
ToggleControl, ToggleControl,
@ -39,12 +39,12 @@ import { useSettingValue } from "../../../hooks/useSettings";
*/ */
export function ThemeChoicePanel(): JSX.Element { export function ThemeChoicePanel(): JSX.Element {
const themeState = useTheme(); const themeState = useTheme();
const themeWatcher = useRef(new ThemeWatcher()); const themeWatcher = useMemo(() => new ThemeWatcher(), []);
const customThemeEnabled = useSettingValue<boolean>("feature_custom_themes"); const customThemeEnabled = useSettingValue<boolean>("feature_custom_themes");
return ( return (
<SettingsSubsection heading={_t("common|theme")} legacy={false} data-testid="themePanel"> <SettingsSubsection heading={_t("common|theme")} legacy={false} data-testid="themePanel">
{themeWatcher.current.isSystemThemeSupported() && ( {themeWatcher.isSystemThemeSupported() && (
<SystemTheme systemThemeActivated={themeState.systemThemeActivated} /> <SystemTheme systemThemeActivated={themeState.systemThemeActivated} />
)} )}
<ThemeSelectors theme={themeState.theme} disabled={themeState.systemThemeActivated} /> <ThemeSelectors theme={themeState.theme} disabled={themeState.systemThemeActivated} />

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details. Please see LICENSE files in the repository root for full details.
*/ */
import React, { ChangeEvent, ReactNode, useCallback, useEffect, useMemo, useState } from "react"; import React, { ChangeEvent, ReactNode, useCallback, useEffect, useMemo, useState, useId } from "react";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { EditInPlace, Alert, ErrorMessage } from "@vector-im/compound-web"; import { EditInPlace, Alert, ErrorMessage } from "@vector-im/compound-web";
import PopOutIcon from "@vector-im/compound-design-tokens/assets/web/icons/pop-out"; import PopOutIcon from "@vector-im/compound-design-tokens/assets/web/icons/pop-out";
@ -20,7 +20,6 @@ import { formatBytes } from "../../../utils/FormattingUtils";
import { useToastContext } from "../../../contexts/ToastContext"; import { useToastContext } from "../../../contexts/ToastContext";
import InlineSpinner from "../elements/InlineSpinner"; import InlineSpinner from "../elements/InlineSpinner";
import UserIdentifierCustomisations from "../../../customisations/UserIdentifier"; import UserIdentifierCustomisations from "../../../customisations/UserIdentifier";
import { useId } from "../../../utils/useId";
import CopyableText from "../elements/CopyableText"; import CopyableText from "../elements/CopyableText";
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext"; import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";

View file

@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details.
import React, { useCallback, useMemo, useState } from "react"; import React, { useCallback, useMemo, useState } from "react";
import { JoinRule, EventType, RoomState, Room } from "matrix-js-sdk/src/matrix"; import { JoinRule, EventType, RoomState, Room } from "matrix-js-sdk/src/matrix";
import { RoomPowerLevelsEventContent } from "matrix-js-sdk/src/types";
import { _t } from "../../../../../languageHandler"; import { _t } from "../../../../../languageHandler";
import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
@ -24,48 +25,49 @@ interface ElementCallSwitchProps {
const ElementCallSwitch: React.FC<ElementCallSwitchProps> = ({ room }) => { const ElementCallSwitch: React.FC<ElementCallSwitchProps> = ({ room }) => {
const isPublic = useMemo(() => room.getJoinRule() === JoinRule.Public, [room]); const isPublic = useMemo(() => room.getJoinRule() === JoinRule.Public, [room]);
const [content, events, maySend] = useRoomState( const [content, maySend] = useRoomState(
room, room,
useCallback( useCallback(
(state: RoomState) => { (state: RoomState) => {
const content = state?.getStateEvents(EventType.RoomPowerLevels, "")?.getContent(); const content = state
?.getStateEvents(EventType.RoomPowerLevels, "")
?.getContent<RoomPowerLevelsEventContent>();
return [ return [
content ?? {}, content ?? {},
content?.["events"] ?? {},
state?.maySendStateEvent(EventType.RoomPowerLevels, room.client.getSafeUserId()), state?.maySendStateEvent(EventType.RoomPowerLevels, room.client.getSafeUserId()),
]; ] as const;
}, },
[room.client], [room.client],
), ),
); );
const [elementCallEnabled, setElementCallEnabled] = useState<boolean>(() => { const [elementCallEnabled, setElementCallEnabled] = useState<boolean>(() => {
return events[ElementCall.MEMBER_EVENT_TYPE.name] === 0; return content.events?.[ElementCall.MEMBER_EVENT_TYPE.name] === 0;
}); });
const onChange = useCallback( const onChange = useCallback(
(enabled: boolean): void => { (enabled: boolean): void => {
setElementCallEnabled(enabled); setElementCallEnabled(enabled);
// Take a copy to avoid mutating the original
const newContent = { events: {}, ...content };
if (enabled) { if (enabled) {
const userLevel = events[EventType.RoomMessage] ?? content.users_default ?? 0; const userLevel = newContent.events[EventType.RoomMessage] ?? content.users_default ?? 0;
const moderatorLevel = content.kick ?? 50; const moderatorLevel = content.kick ?? 50;
events[ElementCall.CALL_EVENT_TYPE.name] = isPublic ? moderatorLevel : userLevel; newContent.events[ElementCall.CALL_EVENT_TYPE.name] = isPublic ? moderatorLevel : userLevel;
events[ElementCall.MEMBER_EVENT_TYPE.name] = userLevel; newContent.events[ElementCall.MEMBER_EVENT_TYPE.name] = userLevel;
} else { } else {
const adminLevel = events[EventType.RoomPowerLevels] ?? content.state_default ?? 100; const adminLevel = newContent.events[EventType.RoomPowerLevels] ?? content.state_default ?? 100;
events[ElementCall.CALL_EVENT_TYPE.name] = adminLevel; newContent.events[ElementCall.CALL_EVENT_TYPE.name] = adminLevel;
events[ElementCall.MEMBER_EVENT_TYPE.name] = adminLevel; newContent.events[ElementCall.MEMBER_EVENT_TYPE.name] = adminLevel;
} }
room.client.sendStateEvent(room.roomId, EventType.RoomPowerLevels, { room.client.sendStateEvent(room.roomId, EventType.RoomPowerLevels, newContent);
events: events,
...content,
});
}, },
[room.client, room.roomId, content, events, isPublic], [room.client, room.roomId, content, isPublic],
); );
const brand = SdkConfig.get("element_call").brand ?? DEFAULTS.element_call.brand; const brand = SdkConfig.get("element_call").brand ?? DEFAULTS.element_call.brand;

View file

@ -27,7 +27,7 @@ type Props = {
const MATCH_SYSTEM_THEME_ID = "MATCH_SYSTEM_THEME_ID"; const MATCH_SYSTEM_THEME_ID = "MATCH_SYSTEM_THEME_ID";
const QuickThemeSwitcher: React.FC<Props> = ({ requestClose }) => { const QuickThemeSwitcher: React.FC<Props> = ({ requestClose }) => {
const orderedThemes = useMemo(getOrderedThemes, []); const orderedThemes = useMemo(() => getOrderedThemes(), []);
const themeState = useTheme(); const themeState = useTheme();
const nonHighContrast = findNonHighContrastTheme(themeState.theme); const nonHighContrast = findNonHighContrastTheme(themeState.theme);

View file

@ -6,7 +6,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { ClientEvent, MatrixClient, MatrixEventEvent, Room } from "matrix-js-sdk/src/matrix"; import { ClientEvent, MatrixClient, MatrixEventEvent, Room } from "matrix-js-sdk/src/matrix";
import { throttle } from "lodash"; import { throttle } from "lodash";
@ -42,10 +42,8 @@ export function useUnreadThreadRooms(forceComputation: boolean): Result {
setResult(computeUnreadThreadRooms(mxClient, msc3946ProcessDynamicPredecessor, settingTACOnlyNotifs)); setResult(computeUnreadThreadRooms(mxClient, msc3946ProcessDynamicPredecessor, settingTACOnlyNotifs));
}, [mxClient, msc3946ProcessDynamicPredecessor, settingTACOnlyNotifs]); }, [mxClient, msc3946ProcessDynamicPredecessor, settingTACOnlyNotifs]);
// The exhautive deps lint rule can't compute dependencies here since it's not a plain inline func. const scheduleUpdate = useMemo(
// We make this as simple as possible so its only dep is doUpdate itself. () =>
// eslint-disable-next-line react-hooks/exhaustive-deps
const scheduleUpdate = useCallback(
throttle(doUpdate, MIN_UPDATE_INTERVAL_MS, { throttle(doUpdate, MIN_UPDATE_INTERVAL_MS, {
leading: false, leading: false,
trailing: true, trailing: true,

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details. Please see LICENSE files in the repository root for full details.
*/ */
import { ReactNode, createContext, useCallback, useContext, useEffect, useRef, useState } from "react"; import { ReactNode, createContext, useCallback, useContext, useEffect, useState, useMemo } from "react";
/** /**
* A ToastContext helps components display any kind of toast message and can be provided * A ToastContext helps components display any kind of toast message and can be provided
@ -33,19 +33,19 @@ export function useToastContext(): ToastRack {
* the ToastRack object that should be provided to the context * the ToastRack object that should be provided to the context
*/ */
export function useActiveToast(): [ReactNode | undefined, ToastRack] { export function useActiveToast(): [ReactNode | undefined, ToastRack] {
const toastRack = useRef(new ToastRack()); const toastRack = useMemo(() => new ToastRack(), []);
const [activeToast, setActiveToast] = useState<ReactNode | undefined>(toastRack.current.getActiveToast()); const [activeToast, setActiveToast] = useState<ReactNode | undefined>(toastRack.getActiveToast());
const updateCallback = useCallback(() => { const updateCallback = useCallback(() => {
setActiveToast(toastRack.current.getActiveToast()); setActiveToast(toastRack.getActiveToast());
}, [setActiveToast, toastRack]); }, [setActiveToast, toastRack]);
useEffect(() => { useEffect(() => {
toastRack.current.setCallback(updateCallback); toastRack.setCallback(updateCallback);
}, [toastRack, updateCallback]); }, [toastRack, updateCallback]);
return [activeToast, toastRack.current]; return [activeToast, toastRack];
} }
interface DisplayedToast { interface DisplayedToast {

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details. Please see LICENSE files in the repository root for full details.
*/ */
import { useEffect, useState } from "react"; import { useEffect, useMemo } from "react";
import type { Map as MapLibreMap } from "maplibre-gl"; import type { Map as MapLibreMap } from "maplibre-gl";
import { createMap } from "./map"; import { createMap } from "./map";
@ -26,29 +26,25 @@ interface UseMapProps {
*/ */
export const useMap = ({ interactive, bodyId, onError }: UseMapProps): MapLibreMap | undefined => { export const useMap = ({ interactive, bodyId, onError }: UseMapProps): MapLibreMap | undefined => {
const cli = useMatrixClientContext(); const cli = useMatrixClientContext();
const [map, setMap] = useState<MapLibreMap>();
useEffect( const map = useMemo(() => {
() => {
try { try {
setMap(createMap(cli, !!interactive, bodyId, onError)); return createMap(cli, !!interactive, bodyId, onError);
} catch (error) { } catch (error) {
console.error("Error encountered in useMap", error); console.error("Error encountered in useMap", error);
if (error instanceof Error) { if (error instanceof Error) {
onError?.(error); onError?.(error);
} }
} }
}, [bodyId, cli, interactive, onError]);
// cleanup
useEffect(() => {
if (!map) return;
return () => { return () => {
if (map) {
map.remove(); map.remove();
setMap(undefined);
}
}; };
}, }, [map]);
// map is excluded as a dependency
// eslint-disable-next-line react-hooks/exhaustive-deps
[interactive, bodyId, onError],
);
return map; return map;
}; };

View file

@ -1,16 +0,0 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2024 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import React from "react";
const getUniqueId = (() => {
return () => `:r${Math.random()}:`;
})();
// Replace this with React's own useId once we switch to React 18
export const useId = (): string => React.useMemo(getUniqueId, []);

View file

@ -56,7 +56,7 @@
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.2.tgz#278b6b13664557de95b8f35b90d96785850bb56e" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.2.tgz#278b6b13664557de95b8f35b90d96785850bb56e"
integrity sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg== integrity sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==
"@babel/core@^7.0.0", "@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.18.5", "@babel/core@^7.21.3", "@babel/core@^7.23.9": "@babel/core@^7.0.0", "@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.18.5", "@babel/core@^7.21.3", "@babel/core@^7.23.9", "@babel/core@^7.24.4":
version "7.26.0" version "7.26.0"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40"
integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==
@ -303,6 +303,13 @@
dependencies: dependencies:
"@babel/types" "^7.25.8" "@babel/types" "^7.25.8"
"@babel/parser@^7.24.4":
version "7.26.3"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234"
integrity sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==
dependencies:
"@babel/types" "^7.26.3"
"@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.2": "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.2":
version "7.26.2" version "7.26.2"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.2.tgz#fd7b6f487cfea09889557ef5d4eeb9ff9a5abd11" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.2.tgz#fd7b6f487cfea09889557ef5d4eeb9ff9a5abd11"
@ -1150,6 +1157,14 @@
"@babel/helper-string-parser" "^7.25.9" "@babel/helper-string-parser" "^7.25.9"
"@babel/helper-validator-identifier" "^7.25.9" "@babel/helper-validator-identifier" "^7.25.9"
"@babel/types@^7.26.3":
version "7.26.3"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0"
integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==
dependencies:
"@babel/helper-string-parser" "^7.25.9"
"@babel/helper-validator-identifier" "^7.25.9"
"@bcoe/v8-coverage@^0.2.3": "@bcoe/v8-coverage@^0.2.3":
version "0.2.3" version "0.2.3"
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
@ -5628,6 +5643,18 @@ eslint-plugin-matrix-org@^2.0.2:
resolved "https://registry.yarnpkg.com/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-2.0.2.tgz#95b86b0f16704ab19740f7c3c62eae69e20365e6" resolved "https://registry.yarnpkg.com/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-2.0.2.tgz#95b86b0f16704ab19740f7c3c62eae69e20365e6"
integrity sha512-cQy5Rjeq6uyu1mLXlPZwEJdyM0NmclrnEz68y792FSuuxzMyJNNYLGDQ5CkYW8H+PrD825HUFZ34pNXnjMOzOw== integrity sha512-cQy5Rjeq6uyu1mLXlPZwEJdyM0NmclrnEz68y792FSuuxzMyJNNYLGDQ5CkYW8H+PrD825HUFZ34pNXnjMOzOw==
eslint-plugin-react-compiler@^19.0.0-beta-df7b47d-20241124:
version "19.0.0-beta-df7b47d-20241124"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.0.0-beta-df7b47d-20241124.tgz#468751d3a8a6781189405ee56b39b80545306df8"
integrity sha512-82PfnllC8jP/68KdLAbpWuYTcfmtGLzkqy2IW85WopKMTr+4rdQpp+lfliQ/QE79wWrv/dRoADrk3Pdhq25nTw==
dependencies:
"@babel/core" "^7.24.4"
"@babel/parser" "^7.24.4"
"@babel/plugin-transform-private-methods" "^7.25.9"
hermes-parser "^0.25.1"
zod "^3.22.4"
zod-validation-error "^3.0.3"
eslint-plugin-react-hooks@^5.0.0: eslint-plugin-react-hooks@^5.0.0:
version "5.0.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz#72e2eefbac4b694f5324154619fee44f5f60f101" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz#72e2eefbac4b694f5324154619fee44f5f60f101"
@ -6574,6 +6601,18 @@ he@^1.2.0:
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
hermes-estree@0.25.1:
version "0.25.1"
resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.25.1.tgz#6aeec17d1983b4eabf69721f3aa3eb705b17f480"
integrity sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==
hermes-parser@^0.25.1:
version "0.25.1"
resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.25.1.tgz#5be0e487b2090886c62bd8a11724cd766d5f54d1"
integrity sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==
dependencies:
hermes-estree "0.25.1"
highlight.js@^11.3.1: highlight.js@^11.3.1:
version "11.10.0" version "11.10.0"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.10.0.tgz#6e3600dc4b33d6dc23d5bd94fbf72405f5892b92" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.10.0.tgz#6e3600dc4b33d6dc23d5bd94fbf72405f5892b92"