Make the theme a prop, next to the language

The theme is state — what Element Call should look like right now — and
so belongs beside `language` as a prop, not on the imperative handle
(where it was a request, `setTheme`, because the internal host bridge
speaks the widget API and a widget's host sends theme changes as
requests) and not in the configuration (where `config.theme` only ever
set the starting theme).

The `theme` prop feeds the same channel the rest of Element Call listens
to for a host's theme, replayed so that whatever subscribes after the
host has set it still hears the current one. Changing it re-themes the
container and nothing else; unlike the language, it is per component.
`setTheme` and `config.theme` are gone, and the harness gets a theme
picker in place of its per-pane buttons.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Timo K.
2026-09-08 17:02:24 +02:00
co-authored by Claude Fable 5.1
parent f994586eeb
commit b722cc277e
5 changed files with 89 additions and 48 deletions
+16 -15
View File
@@ -94,9 +94,10 @@ interface LogEntry {
const Pane: FC<{
session: Session;
roomId: string;
theme: string | undefined;
language: string | undefined;
log: (pane: string, message: string) => void;
}> = ({ session, roomId, language, log }): ReactNode => {
}> = ({ session, roomId, theme, language, log }): ReactNode => {
const [mounted, setMounted] = useState(true);
const bridge = useMemo(
@@ -139,20 +140,6 @@ const Pane: FC<{
<button onClick={(): void => setMounted((m) => !m)}>
{mounted ? "Unmount" : "Mount"}
</button>
<button
onClick={(): void =>
ask("setTheme(light)", async (h) => await h.setTheme("light"))
}
>
Light
</button>
<button
onClick={(): void =>
ask("setTheme(dark)", async (h) => await h.setTheme("dark"))
}
>
Dark
</button>
<button
onClick={(): void =>
ask(
@@ -178,6 +165,7 @@ const Pane: FC<{
client={session.client}
roomId={roomId}
hostBridge={bridge}
theme={theme}
language={language}
/>
)}
@@ -235,6 +223,7 @@ export const Harness: FC = (): ReactNode => {
// The host's language setting, which Element Call follows. Undefined means
// the host has none and Element Call uses the browser's.
const [language, setLanguage] = useState<string | undefined>(undefined);
const [theme, setTheme] = useState<string | undefined>(undefined);
const log = useCallback((pane: string, message: string): void => {
setEntries((entries) =>
@@ -333,6 +322,17 @@ export const Harness: FC = (): ReactNode => {
<button onClick={(): void => setDialogOpen(true)}>
Open a host dialog
</button>
<label>
Theme{" "}
<select
value={theme ?? ""}
onChange={(e): void => setTheme(e.target.value || undefined)}
>
<option value="">Element Call&apos;s choice</option>
<option value="light">light</option>
<option value="dark">dark</option>
</select>
</label>
<label>
Language{" "}
<select
@@ -356,6 +356,7 @@ export const Harness: FC = (): ReactNode => {
key={session.label}
session={session}
roomId={state.roomId}
theme={theme}
language={language}
log={log}
/>