diff --git a/packages/embeds/embed-core/playground.ts b/packages/embeds/embed-core/playground.ts index c490f25967..ff5c9b7a50 100644 --- a/packages/embeds/embed-core/playground.ts +++ b/packages/embeds/embed-core/playground.ts @@ -55,6 +55,7 @@ if (only === "all" || only === "ns:second") { iframeAttrs: { id: "cal-booking-place-second-iframe", }, + theme: "auto", }, }, ]); diff --git a/packages/embeds/embed-core/src/embed-iframe.ts b/packages/embeds/embed-core/src/embed-iframe.ts index 8f09414430..974db94e85 100644 --- a/packages/embeds/embed-core/src/embed-iframe.ts +++ b/packages/embeds/embed-core/src/embed-iframe.ts @@ -8,10 +8,10 @@ import type { Message } from "./embed"; import { sdkActionManager } from "./sdk-event"; type Theme = "dark" | "light"; - +export type EmbedThemeConfig = Theme | "auto"; export type UiConfig = { hideEventTypeDetails?: boolean; - theme?: Theme | "auto"; + theme?: EmbedThemeConfig; styles?: EmbedStyles & EmbedNonStylesConfig; //TODO: Extract from tailwind the list of all custom variables and support them in auto-completion as well as runtime validation. Followup with listing all variables in Embed Snippet Generator UI. cssVarsPerTheme?: Record>; @@ -31,7 +31,7 @@ const embedStore = { reactNonStylesStateSetters: {} as Record, parentInformedAboutContentHeight: false, windowLoadEventFired: false, - setTheme: undefined as ((arg0: string) => void) | undefined, + setTheme: undefined as ((arg0: EmbedThemeConfig) => void) | undefined, theme: undefined as UiConfig["theme"], uiConfig: undefined as Omit | undefined, setUiConfig: undefined as ((arg0: UiConfig) => void) | undefined, @@ -170,14 +170,14 @@ function isValidNamespace(ns: string | null | undefined) { export const useEmbedTheme = () => { const router = useRouter(); - const [theme, setTheme] = useState(embedStore.theme || (router.query.theme as string)); + const [theme, setTheme] = useState(embedStore.theme || (router.query.theme as typeof embedStore.theme)); useEffect(() => { router.events.on("routeChangeComplete", () => { sdkActionManager?.fire("__routeChanged", {}); }); }, [router.events]); embedStore.setTheme = setTheme; - return theme === "auto" ? null : theme; + return theme; }; export const useEmbedUiConfig = () => { @@ -434,7 +434,7 @@ if (isBrowser) { // Exposes certain global variables/fns that are used by the app to get interface with the embed. embedInit(); const url = new URL(document.URL); - embedStore.theme = (window?.getEmbedTheme?.() || "auto") as UiConfig["theme"]; + embedStore.theme = window?.getEmbedTheme?.() as UiConfig["theme"]; if (url.searchParams.get("prerender") !== "true" && window?.isEmbed?.()) { log("Initializing embed-iframe"); // HACK diff --git a/packages/embeds/embed-core/src/embed.ts b/packages/embeds/embed-core/src/embed.ts index 28dcd02f40..a457d1d39a 100644 --- a/packages/embeds/embed-core/src/embed.ts +++ b/packages/embeds/embed-core/src/embed.ts @@ -2,7 +2,7 @@ import { FloatingButton } from "./FloatingButton/FloatingButton"; import { Inline } from "./Inline/inline"; import { ModalBox } from "./ModalBox/ModalBox"; -import type { InterfaceWithParent, interfaceWithParent, UiConfig } from "./embed-iframe"; +import type { InterfaceWithParent, interfaceWithParent, UiConfig, EmbedThemeConfig } from "./embed-iframe"; import css from "./embed.css"; import type { EventData, EventDataMap } from "./sdk-action-manager"; import { SdkActionManager } from "./sdk-action-manager"; @@ -129,6 +129,7 @@ type PrefillAndIframeAttrsConfig = Record & { id?: string; }; + theme?: EmbedThemeConfig; }; export class Cal { diff --git a/packages/lib/hooks/useTheme.tsx b/packages/lib/hooks/useTheme.tsx index b697d6fd28..b7c4c09104 100644 --- a/packages/lib/hooks/useTheme.tsx +++ b/packages/lib/hooks/useTheme.tsx @@ -21,8 +21,10 @@ export default function useTheme(themeToSet?: Maybe) { return; } - // Embed theme takes precedence over theme configured in app. If embedTheme isn't set that is it's in 'Auto' mode, then it would use the theme configured in appearance. - const finalThemeToSet = embedTheme || themeToSet; + // Embed theme takes precedence over theme configured in app. + // If embedTheme isn't set i.e. it's not explicitly configured with a theme, then it would use the theme configured in appearance. + // If embedTheme is set to "auto" then we consider it as null which then uses system theme. + const finalThemeToSet = embedTheme ? (embedTheme === "auto" ? null : embedTheme) : themeToSet; if (!finalThemeToSet || finalThemeToSet === activeTheme) return;