From bc6015eff2454b0735b78d4a3f0c1e61522a6791 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 2 Sep 2026 09:58:34 +0200 Subject: [PATCH] Supply Element Call's parameters through a context Element Call's parameters come from its URL, which works while it owns the page but leaves an embedder with nowhere to put them. Add a context so they can be provided directly, falling back to parsing window.location when no provider is present. This also decouples the thirteen consumers from react-router: useUrlParams called useLocation, so each of them required a router ancestor, which the embedded build will not have. The standalone and widget builds keep their URL-derived behaviour via useUrlParamsFromLocation, provided in App. No functional change. --- src/App.tsx | 46 ++++++++++++++++++++++++++++++++-------------- src/UrlParams.ts | 33 +++++++++++++++++++++++++++++---- 2 files changed, 61 insertions(+), 18 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 55703f4c0..511577dee 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -31,7 +31,13 @@ import { useTheme } from "./useTheme"; import { ProcessorProvider } from "./livekit/TrackProcessorContext"; import { type AppViewModel } from "./state/AppViewModel"; import { MediaDevicesContext } from "./MediaDevicesContext"; -import { getUrlParams, HeaderStyle, useUrlParams } from "./UrlParams"; +import { + getUrlParams, + HeaderStyle, + UrlParamsProvider, + useUrlParams, + useUrlParamsFromLocation, +} from "./UrlParams"; import { AppBar } from "./AppBar"; import { i18n } from "./utils/i18n"; import { useRootElement } from "./RootElementContext"; @@ -42,6 +48,16 @@ interface SimpleProviderProps { children: JSX.Element; } +/** + * Supplies the URL-derived params to the rest of the app. Only the standalone + * and widget builds own the URL, so this lives here in the app shell rather + * than alongside the context itself. + */ +const LocationUrlParamsProvider: FC = ({ children }) => { + const urlParams = useUrlParamsFromLocation(); + return {children}; +}; + const BackgroundProvider: FC = ({ children }) => { const { pathname } = useLocation(); const { background } = useUrlParams(); @@ -102,19 +118,21 @@ export const App: FC = ({ vm }) => { return ( - - - - - {header === HeaderStyle.AppBar ? ( - {content} - ) : ( - content - )} - - - - + + + + + + {header === HeaderStyle.AppBar ? ( + {content} + ) : ( + content + )} + + + + + ); diff --git a/src/UrlParams.ts b/src/UrlParams.ts index 805cab710..dd83a4966 100644 --- a/src/UrlParams.ts +++ b/src/UrlParams.ts @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ -import { useMemo } from "react"; +import { createContext, use, useMemo } from "react"; import { useLocation } from "react-router-dom"; import { logger } from "matrix-js-sdk/lib/logger"; import { @@ -519,11 +519,36 @@ export const computeUrlParams = (search = "", hash = ""): UrlParams => { }; }; +const UrlParamsContext = createContext(null); + /** - * Hook to simplify use of getUrlParams. - * @returns The app parameters for the current URL + * Supplies the parameters Element Call should run with. + * + * The standalone and widget builds derive these from the URL, but an embedder + * has no URL of its own to put them in, so it provides them directly instead. + * + * TODO: `UrlParams` is no longer an accurate name now that these need not come + * from a URL. Renaming it touches every consumer, so it is left until the rest + * of the de-globalisation work has settled. */ -export const useUrlParams = (): UrlParams => { +export const UrlParamsProvider = UrlParamsContext.Provider; + +/** + * The parameters Element Call is running with. + * + * Falls back to parsing `window.location` when no provider is present, so that + * tests and stories keep working without one. + */ +export const useUrlParams = (): UrlParams => + use(UrlParamsContext) ?? getUrlParams(); + +/** + * Derives {@link UrlParams} from the current router location. + * + * Only meaningful when Element Call owns the URL; embedders provide the params + * directly through {@link UrlParamsProvider}. + */ +export const useUrlParamsFromLocation = (): UrlParams => { const { search, hash } = useLocation(); return useMemo(() => getUrlParams(search, hash), [search, hash]); };