diff --git a/packages/embeds/embed-core/src/EmbedElement.test.ts b/packages/embeds/embed-core/src/EmbedElement.test.ts index 86f7616646..57c7f83034 100644 --- a/packages/embeds/embed-core/src/EmbedElement.test.ts +++ b/packages/embeds/embed-core/src/EmbedElement.test.ts @@ -6,6 +6,7 @@ import type { Mock } from "vitest"; import { EmbedElement } from "./EmbedElement"; import inlineHTML from "./Inline/inlineHtml"; +import { EMBED_DARK_THEME_CLASS, EMBED_LIGHT_THEME_CLASS } from "./constants"; import { getColorSchemeDarkQuery } from "./ui-utils"; (function defineEmbedTestElement() { @@ -269,8 +270,8 @@ describe("EmbedElement", () => { }, getSkeletonData: vi.fn(), }); - expect(element.classList.contains("dark")).toBe(true); - expect(element.classList.contains("light")).toBe(false); + expect(element.classList.contains(EMBED_DARK_THEME_CLASS)).toBe(true); + expect(element.classList.contains(EMBED_LIGHT_THEME_CLASS)).toBe(false); }); it("should update theme class when system preference changes as long as embed theme is not set", () => { @@ -279,8 +280,8 @@ describe("EmbedElement", () => { }); getColorSchemeDarkQuery().dispatchEvent(buildMediaQueryListEvent({ type: "change", matches: true })); - expect(element.classList.contains("dark")).toBe(true); - expect(element.classList.contains("light")).toBe(false); + expect(element.classList.contains(EMBED_DARK_THEME_CLASS)).toBe(true); + expect(element.classList.contains(EMBED_LIGHT_THEME_CLASS)).toBe(false); }); it("should not update theme on system color scheme change when embed theme is set", () => { @@ -291,7 +292,7 @@ describe("EmbedElement", () => { getSkeletonData: vi.fn(), }); getColorSchemeDarkQuery().dispatchEvent(buildMediaQueryListEvent({ type: "change", matches: true })); - expect(element.classList.contains("light")).toBe(true); + expect(element.classList.contains(EMBED_LIGHT_THEME_CLASS)).toBe(true); }); }); diff --git a/packages/embeds/embed-core/src/EmbedElement.ts b/packages/embeds/embed-core/src/EmbedElement.ts index 1cc3a72c41..6c018313d5 100644 --- a/packages/embeds/embed-core/src/EmbedElement.ts +++ b/packages/embeds/embed-core/src/EmbedElement.ts @@ -1,3 +1,4 @@ +import { EMBED_DARK_THEME_CLASS, EMBED_LIGHT_THEME_CLASS } from "./constants"; import type { EmbedThemeConfig, AllPossibleLayouts, BookerLayouts, EmbedPageType } from "./types"; import { getThemeClassForEmbed, @@ -157,9 +158,7 @@ export class EmbedElement extends HTMLElement { this.isModal = data.isModal; this.layout = this.getLayout(); this.theme = this.dataset.theme as EmbedThemeConfig | null; - this.themeClass = getThemeClassForEmbed({ theme: this.theme }); - this.classList.add(this.themeClass); - + this.setTheme(this.theme); this.getSkeletonData = data.getSkeletonData; this.boundResizeHandler = this.resizeHandler.bind(this); this.boundPrefersDarkThemeChangedHandler = this.prefersDarkThemeChangedHandler.bind(this); @@ -197,20 +196,26 @@ export class EmbedElement extends HTMLElement { skeletonEl.innerHTML = skeletonContent; } + public setTheme(theme: EmbedThemeConfig | null) { + const allPossibleThemeClasses = [EMBED_DARK_THEME_CLASS, EMBED_LIGHT_THEME_CLASS]; + + const newThemeClass = getThemeClassForEmbed({ theme }); + + if (newThemeClass === this.themeClass) { + return; + } + this.themeClass = newThemeClass; + this.classList.remove(...allPossibleThemeClasses); + this.classList.add(this.themeClass); + } + public prefersDarkThemeChangedHandler(e: MediaQueryListEvent) { const isDarkPreferred = e.matches; - const allPossibleThemeClasses = ["dark", "light"]; if (isThemePreferenceProvided(this.theme)) { // User has provided a theme preference, so we stick to that and don't react to system theme change return; } - const newThemeClass = getThemeClassForEmbed({ - theme: isDarkPreferred ? "dark" : "light", - }); - if (newThemeClass !== this.themeClass) { - this.classList.remove(...allPossibleThemeClasses); - this.classList.add(newThemeClass); - } + this.setTheme(isDarkPreferred ? "dark" : "light"); } connectedCallback() { // Make sure to show the loader initially. diff --git a/packages/embeds/embed-core/src/addAppCssVars.ts b/packages/embeds/embed-core/src/addAppCssVars.ts index 19b66322ae..3259a77b76 100644 --- a/packages/embeds/embed-core/src/addAppCssVars.ts +++ b/packages/embeds/embed-core/src/addAppCssVars.ts @@ -1,3 +1,5 @@ +import { EMBED_DARK_THEME_CLASS } from "./constants"; + export const addAppCssVars = () => { const calElements = ["cal-floating-button", "cal-modal-box", "cal-inline"]; try { @@ -148,7 +150,7 @@ export const addAppCssVars = () => { --cal-brand-text: hsla(0, 0%, 100%, 1); /* white */ } - ${calElements.map((element) => `${element}.dark`).join(",")} { + ${calElements.map((element) => `${element}.${EMBED_DARK_THEME_CLASS}`).join(",")} { /* Background Standard */ --cal-bg-emphasis: hsla(0, 0%, 25%, 1); /* stone-700 */ --cal-bg: hsla(0, 0%, 6%, 1); /* stone-950 */ diff --git a/packages/embeds/embed-core/src/constants.ts b/packages/embeds/embed-core/src/constants.ts index 880df0c5a0..ef3d089037 100644 --- a/packages/embeds/embed-core/src/constants.ts +++ b/packages/embeds/embed-core/src/constants.ts @@ -10,3 +10,8 @@ if (EMBED_MODAL_IFRAME_SLOT_STALE_TIME > EMBED_MODAL_IFRAME_FORCE_RELOAD_THRESHO "EMBED_MODAL_IFRAME_SLOT_STALE_TIME must be less than EMBED_MODAL_IFRAME_FORCE_RELOAD_THRESHOLD_MS" ); } + +// These classes are applied to Embed Elements and thus are in the same scope as the embedding webpage. +// So, these classes need to be unique to us, to avoid accidental override +export const EMBED_LIGHT_THEME_CLASS = "cal-element-embed-light"; +export const EMBED_DARK_THEME_CLASS = "cal-element-embed-dark"; diff --git a/packages/embeds/embed-core/src/ui-utils.ts b/packages/embeds/embed-core/src/ui-utils.ts index 7cf95d87e9..db703765d8 100644 --- a/packages/embeds/embed-core/src/ui-utils.ts +++ b/packages/embeds/embed-core/src/ui-utils.ts @@ -1,3 +1,4 @@ +import { EMBED_DARK_THEME_CLASS, EMBED_LIGHT_THEME_CLASS } from "./constants"; import type { AllPossibleLayouts, EmbedThemeConfig } from "./types"; export function getMaxHeightForModal() { @@ -32,7 +33,7 @@ function detectColorScheme() { } function getClassBasedOnTheme(theme: EmbedThemeConfig | undefined | null) { - return theme ?? "light"; + return theme === "dark" ? EMBED_DARK_THEME_CLASS : EMBED_LIGHT_THEME_CLASS; } export function isThemePreferenceProvided(theme: EmbedThemeConfig | undefined | null) {