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.
This commit is contained in:
Valere
2026-09-02 09:58:34 +02:00
parent 0dca5835f6
commit bc6015eff2
2 changed files with 61 additions and 18 deletions
+19 -1
View File
@@ -31,7 +31,13 @@ import { useTheme } from "./useTheme";
import { ProcessorProvider } from "./livekit/TrackProcessorContext"; import { ProcessorProvider } from "./livekit/TrackProcessorContext";
import { type AppViewModel } from "./state/AppViewModel"; import { type AppViewModel } from "./state/AppViewModel";
import { MediaDevicesContext } from "./MediaDevicesContext"; import { MediaDevicesContext } from "./MediaDevicesContext";
import { getUrlParams, HeaderStyle, useUrlParams } from "./UrlParams"; import {
getUrlParams,
HeaderStyle,
UrlParamsProvider,
useUrlParams,
useUrlParamsFromLocation,
} from "./UrlParams";
import { AppBar } from "./AppBar"; import { AppBar } from "./AppBar";
import { i18n } from "./utils/i18n"; import { i18n } from "./utils/i18n";
import { useRootElement } from "./RootElementContext"; import { useRootElement } from "./RootElementContext";
@@ -42,6 +48,16 @@ interface SimpleProviderProps {
children: JSX.Element; 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<SimpleProviderProps> = ({ children }) => {
const urlParams = useUrlParamsFromLocation();
return <UrlParamsProvider value={urlParams}>{children}</UrlParamsProvider>;
};
const BackgroundProvider: FC<SimpleProviderProps> = ({ children }) => { const BackgroundProvider: FC<SimpleProviderProps> = ({ children }) => {
const { pathname } = useLocation(); const { pathname } = useLocation();
const { background } = useUrlParams(); const { background } = useUrlParams();
@@ -102,6 +118,7 @@ export const App: FC<Props> = ({ vm }) => {
return ( return (
<I18nextProvider i18n={i18n}> <I18nextProvider i18n={i18n}>
<BrowserRouter> <BrowserRouter>
<LocationUrlParamsProvider>
<BackgroundProvider> <BackgroundProvider>
<ThemeProvider> <ThemeProvider>
<TooltipProvider> <TooltipProvider>
@@ -115,6 +132,7 @@ export const App: FC<Props> = ({ vm }) => {
</TooltipProvider> </TooltipProvider>
</ThemeProvider> </ThemeProvider>
</BackgroundProvider> </BackgroundProvider>
</LocationUrlParamsProvider>
</BrowserRouter> </BrowserRouter>
</I18nextProvider> </I18nextProvider>
); );
+29 -4
View File
@@ -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. 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 { useLocation } from "react-router-dom";
import { logger } from "matrix-js-sdk/lib/logger"; import { logger } from "matrix-js-sdk/lib/logger";
import { import {
@@ -519,11 +519,36 @@ export const computeUrlParams = (search = "", hash = ""): UrlParams => {
}; };
}; };
const UrlParamsContext = createContext<UrlParams | null>(null);
/** /**
* Hook to simplify use of getUrlParams. * Supplies the parameters Element Call should run with.
* @returns The app parameters for the current URL *
* 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(); const { search, hash } = useLocation();
return useMemo(() => getUrlParams(search, hash), [search, hash]); return useMemo(() => getUrlParams(search, hash), [search, hash]);
}; };