- `lotusHostControls=1`: body.lotus-host-controls hides EC's footer (position absolute + visibility hidden, still in the DOM so a host on an engine without Capability Delegation can click its screenshare button). - With lotusTheme/lotusTransparent, `:root` color-scheme follows the theme, so the transparent frame gets no opaque backdrop. Together these replace the CSS the host injected into this frame. Also fixes unreadable tile name tags in the light theme: the Lotus near-black canvas override now applies to dark themes only (it sat behind light-theme dark text). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
93 lines
3.7 KiB
TypeScript
93 lines
3.7 KiB
TypeScript
/*
|
|
Copyright 2024 New Vector Ltd.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
Please see LICENSE in the repository root for full details.
|
|
*/
|
|
|
|
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
import { WidgetApiToWidgetAction } from "matrix-widget-api";
|
|
import { type IThemeChangeActionRequest } from "matrix-widget-api";
|
|
import { logger } from "matrix-js-sdk/lib/logger";
|
|
|
|
import { getUrlParams } from "./UrlParams";
|
|
import { widget } from "./widget";
|
|
import { lotusFlag } from "./lotus/lotusWidget";
|
|
|
|
export const useTheme = (): void => {
|
|
const [requestedTheme, setRequestedTheme] = useState(
|
|
() => getUrlParams().theme,
|
|
);
|
|
const previousTheme = useRef<string | null>(document.body.classList.item(0));
|
|
|
|
useEffect(() => {
|
|
if (widget) {
|
|
const onThemeChange = (
|
|
ev: CustomEvent<IThemeChangeActionRequest>,
|
|
): void => {
|
|
ev.preventDefault();
|
|
if ("name" in ev.detail.data && typeof ev.detail.data.name === "string")
|
|
setRequestedTheme(ev.detail.data.name);
|
|
widget!.api.transport.reply(ev.detail, {});
|
|
};
|
|
|
|
widget.lazyActions.on(WidgetApiToWidgetAction.ThemeChange, onThemeChange);
|
|
return (): void => {
|
|
widget!.lazyActions.off(
|
|
WidgetApiToWidgetAction.ThemeChange,
|
|
onThemeChange,
|
|
);
|
|
};
|
|
}
|
|
}, []);
|
|
|
|
useLayoutEffect(() => {
|
|
// If no theme has been explicitly requested we default to dark
|
|
const theme = requestedTheme?.includes("light") ? "light" : "dark";
|
|
const themeHighContrast = requestedTheme?.includes("high-contrast")
|
|
? "-hc"
|
|
: "";
|
|
const themeString = "cpd-theme-" + theme + themeHighContrast;
|
|
if (themeString !== previousTheme.current) {
|
|
document.body.classList.remove(
|
|
"cpd-theme-light",
|
|
"cpd-theme-dark",
|
|
"cpd-theme-light-hc",
|
|
"cpd-theme-dark-hc",
|
|
);
|
|
document.body.classList.add(themeString);
|
|
previousTheme.current = themeString;
|
|
}
|
|
document.body.classList.remove("no-theme");
|
|
// [lotus #5] Native theming hooks, opted in by the host via URL flags, so
|
|
// it no longer has to inject CSS into the iframe after load.
|
|
const lotusTransparent = lotusFlag("lotusTransparent");
|
|
const lotusTheme = lotusFlag("lotusTheme");
|
|
if (lotusTransparent) document.body.classList.add("lotus-transparent");
|
|
// [lotus #21] The two flags are only meaningful together: a transparent
|
|
// canvas with no matching theme leaves text/icon colours computed against
|
|
// the default dark canvas token while the real pixels behind them are
|
|
// whatever the host painted. If a host sets lotusTransparent without
|
|
// lotusTheme, warn and apply lotusTheme anyway rather than silently
|
|
// risking unreadable UI.
|
|
if (lotusTransparent && !lotusTheme) {
|
|
logger.warn(
|
|
"[lotus] lotusTransparent is set without lotusTheme; applying " +
|
|
"lotusTheme anyway since the two flags are only meaningful together.",
|
|
);
|
|
}
|
|
if (lotusTheme || lotusTransparent) {
|
|
document.body.classList.add("lotus-theme");
|
|
// [cinny #43] The frame's root colour scheme must match the host's, or
|
|
// the browser paints an opaque backdrop behind the transparent frame.
|
|
// (The host used to inject `:root { color-scheme }` for this.)
|
|
document.documentElement.style.colorScheme = theme;
|
|
}
|
|
// [cinny #43] The host draws its own call bar: hide EC's footer, but keep
|
|
// it in the DOM (the host still clicks its screenshare button on engines
|
|
// without Capability Delegation). Replaces the host's injected styles.
|
|
if (lotusFlag("lotusHostControls"))
|
|
document.body.classList.add("lotus-host-controls");
|
|
}, [previousTheme, requestedTheme]);
|
|
};
|