From f5a94ce7023eb96f55138f90119e5f14d604402e Mon Sep 17 00:00:00 2001 From: "Timo K." Date: Tue, 8 Sep 2026 15:10:35 +0200 Subject: [PATCH] Offer a component host only the configuration it can use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ElementCallConfiguration` was every URL parameter, which put the widget plumbing (widgetId, parentUrl, isWidget), the user's identity, the homeserver, the analytics and Sentry settings, and the standalone app's shared room secret in front of a host that has no business setting any of them — the component reads none of those. It is now the behavioural configuration a widget's URL can carry plus the two properties a host has a say in: the theme and the background. The background is now actually applied to the component's root, which it was not before. Co-Authored-By: Claude Fable 5.1 --- component/index.tsx | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/component/index.tsx b/component/index.tsx index 62aaaf774..1d9969a2d 100644 --- a/component/index.tsx +++ b/component/index.tsx @@ -38,6 +38,7 @@ import { type ReactNode, type Ref, useEffect, + useLayoutEffect, useMemo, useState, } from "react"; @@ -55,13 +56,16 @@ import { CallView } from "../src/room/CallView"; import { ErrorPage } from "../src/FullScreenView"; import { ClientProvider } from "../src/ClientContext"; import { HostBridgeProvider } from "../src/HostBridge"; -import { RootElementProvider } from "../src/RootElementContext"; +import { RootElementProvider, useRootElement } from "../src/RootElementContext"; import { configurationForIntent, componentProperties, + type UrlConfiguration, type UrlParams, UrlParamsProvider, + type UrlProperties, UserIntent, + useUrlParams, } from "../src/UrlParams"; import { MediaDevicesContext } from "../src/MediaDevicesContext"; import { MediaDevices } from "../src/state/MediaDevices"; @@ -100,8 +104,16 @@ export { /** * How Element Call should behave. Everything is optional; anything left out * takes the default that {@link ElementCallProps.intent} implies. + * + * This is the behaviour a widget can be configured with through its URL, plus + * the two facts about the call a host has a say in: the theme to start in and + * the background. The rest of what a widget's URL carries — who the user is, + * how to reach the homeserver, where to report analytics, the shared secret of + * a room that is encrypted with one — a component host supplies by other + * routes, or not at all. */ -export type ElementCallConfiguration = Partial; +export type ElementCallConfiguration = Partial & + Partial>; export interface ElementCallProps { /** @@ -178,9 +190,14 @@ export async function initializeElementCall( }); } -/** Applies the theme to the container, before it is painted. */ +/** Applies the theme and background to the container, before it is painted. */ const Decoration: FC<{ children: JSX.Element }> = ({ children }) => { useTheme(); + const { background } = useUrlParams(); + const rootElement = useRootElement(); + useLayoutEffect(() => { + rootElement.setAttribute("data-background", background); + }, [rootElement, background]); return children; };