mirror of
https://github.com/element-hq/element-web.git
synced 2026-01-16 23:01:06 +00:00
Fix bundled font or custom font not applied after theme switch (#31591)
Some checks failed
Build / Build on macos-14 (push) Waiting to run
Build / Build on ubuntu-24.04 (push) Waiting to run
Build / Build on windows-2022 (push) Waiting to run
Build and Deploy develop / Build & Deploy develop.element.io (push) Waiting to run
Deploy documentation / GitHub Pages (push) Waiting to run
Deploy documentation / deploy (push) Blocked by required conditions
Shared Component Visual Tests / Run Visual Tests (push) Waiting to run
Static Analysis / Typescript Syntax Check (push) Waiting to run
Static Analysis / i18n Check (push) Waiting to run
Static Analysis / Rethemendex Check (push) Waiting to run
Static Analysis / ESLint (push) Waiting to run
Static Analysis / Style Lint (push) Waiting to run
Static Analysis / Workflow Lint (push) Waiting to run
Static Analysis / Analyse Dead Code (push) Waiting to run
Localazy Upload / upload (push) Has been cancelled
Some checks failed
Build / Build on macos-14 (push) Waiting to run
Build / Build on ubuntu-24.04 (push) Waiting to run
Build / Build on windows-2022 (push) Waiting to run
Build and Deploy develop / Build & Deploy develop.element.io (push) Waiting to run
Deploy documentation / GitHub Pages (push) Waiting to run
Deploy documentation / deploy (push) Blocked by required conditions
Shared Component Visual Tests / Run Visual Tests (push) Waiting to run
Static Analysis / Typescript Syntax Check (push) Waiting to run
Static Analysis / i18n Check (push) Waiting to run
Static Analysis / Rethemendex Check (push) Waiting to run
Static Analysis / ESLint (push) Waiting to run
Static Analysis / Style Lint (push) Waiting to run
Static Analysis / Workflow Lint (push) Waiting to run
Static Analysis / Analyse Dead Code (push) Waiting to run
Localazy Upload / upload (push) Has been cancelled
* refactor: transform `FontWater.onAction` to switch * fix: reload font after switching theme Fix #26248 #31588 When a theme is swiched, `clearCustomTheme` remove all css variables. After the styles are re-applied but the custom fonts or emoji are not re-applied. * test: add test for `Action.ReloadFont` * test: add missing tests for existing actions * test(e2e): add tests to ensure that font and emoji stay unchanged * Revert "fix: reload font after switching theme" This reverts commit2b0071af21. * Revert "refactor: transform `FontWater.onAction` to switch" This reverts commit4119158609. * Revert "test: add test for `Action.ReloadFont`" This reverts commit31b3b224cd. * fix: don't remove custom emoji and cpd font when clearing custom theme Fix #26248 #31588 When a theme is swiched, `clearCustomTheme` remove all css variables. After the styles are re-applied but the custom fonts or emoji are not re-applied. This fix avoid the custom font and emoji to be removed. * test: add tests
This commit is contained in:
parent
4bd1d4144f
commit
be7be39d0f
7 changed files with 113 additions and 4 deletions
|
|
@ -56,4 +56,35 @@ test.describe("Appearance user settings tab", () => {
|
|||
// Assert that the font-family value was removed
|
||||
await expect(page.locator("body")).toHaveCSS("font-family", '""');
|
||||
});
|
||||
|
||||
test(
|
||||
"should keep same font and emoji when switching theme",
|
||||
{ tag: "@screenshot" },
|
||||
async ({ page, app, user, util }) => {
|
||||
const roomId = await util.createAndDisplayRoom();
|
||||
await app.client.sendMessage(roomId, { body: "Message with 🦡", msgtype: "m.text" });
|
||||
|
||||
await app.settings.openUserSettings("Appearance");
|
||||
const tab = page.getByTestId("mx_AppearanceUserSettingsTab");
|
||||
await tab.getByRole("button", { name: "Show advanced" }).click();
|
||||
await tab.getByRole("switch", { name: "Use bundled emoji font" }).click();
|
||||
await tab.getByRole("switch", { name: "Use a system font" }).click();
|
||||
|
||||
await app.closeDialog();
|
||||
await expect(page).toMatchScreenshot("window-before-switch.png", {
|
||||
mask: [page.locator(".mx_MessageTimestamp")],
|
||||
});
|
||||
|
||||
// Switch to dark theme
|
||||
await app.settings.openUserSettings("Appearance");
|
||||
await util.getMatchSystemThemeSwitch().click();
|
||||
await util.getDarkTheme().click();
|
||||
|
||||
await app.closeDialog();
|
||||
// Font and emoji should remain the same after theme switch
|
||||
await expect(page).toMatchScreenshot("window-after-switch.png", {
|
||||
mask: [page.locator(".mx_MessageTimestamp")],
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -150,9 +150,10 @@ class Helpers {
|
|||
/**
|
||||
* Create and display a room named Test Room
|
||||
*/
|
||||
async createAndDisplayRoom() {
|
||||
await this.app.client.createRoom({ name: "Test Room" });
|
||||
async createAndDisplayRoom(): Promise<string> {
|
||||
const roomId = await this.app.client.createRoom({ name: "Test Room" });
|
||||
await this.app.viewRoomByName("Test Room");
|
||||
return roomId;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
10
src/theme.ts
10
src/theme.ts
|
|
@ -26,6 +26,7 @@ import { logger } from "matrix-js-sdk/src/logger";
|
|||
import { _t } from "./languageHandler";
|
||||
import SettingsStore from "./settings/SettingsStore";
|
||||
import ThemeWatcher from "./settings/watchers/ThemeWatcher";
|
||||
import { FontWatcher } from "./settings/watchers/FontWatcher";
|
||||
|
||||
export const DEFAULT_THEME = "light";
|
||||
const HIGH_CONTRAST_THEMES: Record<string, string> = {
|
||||
|
|
@ -126,10 +127,15 @@ export function getOrderedThemes(): ITheme[] {
|
|||
}
|
||||
|
||||
function clearCustomTheme(): void {
|
||||
// remove all css variables, we assume these are there because of the custom theme
|
||||
// remove all css variables (except font and emoji variables), we assume these are there because of the custom theme
|
||||
const inlineStyleProps = Object.values(document.body.style);
|
||||
for (const prop of inlineStyleProps) {
|
||||
if (typeof prop === "string" && prop.startsWith("--")) {
|
||||
if (
|
||||
typeof prop === "string" &&
|
||||
prop.startsWith("--") &&
|
||||
prop !== FontWatcher.FONT_FAMILY_CUSTOM_PROPERTY &&
|
||||
prop !== FontWatcher.EMOJI_FONT_FAMILY_CUSTOM_PROPERTY
|
||||
) {
|
||||
document.body.style.removeProperty(prop);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
*/
|
||||
|
||||
import { sleep } from "matrix-js-sdk/src/utils";
|
||||
import { waitFor } from "jest-matrix-react";
|
||||
|
||||
import SettingsStore from "../../../../src/settings/SettingsStore";
|
||||
import { SettingLevel } from "../../../../src/settings/SettingLevel";
|
||||
|
|
@ -155,5 +156,33 @@ describe("FontWatcher", function () {
|
|||
// baseFontSize should be cleared
|
||||
expect(SettingsStore.getValue("baseFontSizeV2")).toBe(0);
|
||||
});
|
||||
|
||||
it("should trigger migration when dispatched", async () => {
|
||||
await watcher!.start();
|
||||
|
||||
await SettingsStore.setValue("baseFontSizeV2", null, SettingLevel.DEVICE, 18);
|
||||
defaultDispatcher.fire(Action.MigrateBaseFontSize);
|
||||
|
||||
await waitFor(() => {
|
||||
// 18px - 16px (default browser font size) = 2px
|
||||
expect(SettingsStore.getValue("fontSizeDelta")).toBe(2);
|
||||
// baseFontSizeV2 should be cleared
|
||||
expect(SettingsStore.getValue("baseFontSizeV2")).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should update root font size with positive delta", async () => {
|
||||
await new FontWatcher().start();
|
||||
|
||||
defaultDispatcher.dispatch({
|
||||
action: Action.UpdateFontSizeDelta,
|
||||
delta: 2,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
const rootFontSize = document.querySelector<HTMLElement>(":root")!.style.fontSize;
|
||||
expect(rootFontSize).toContain("2px");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
*/
|
||||
|
||||
import SettingsStore from "../../src/settings/SettingsStore";
|
||||
import { FontWatcher } from "../../src/settings/watchers/FontWatcher";
|
||||
import { enumerateThemes, getOrderedThemes, setTheme } from "../../src/theme";
|
||||
|
||||
describe("theme", () => {
|
||||
|
|
@ -223,4 +224,45 @@ describe("theme", () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("clearCustomTheme", () => {
|
||||
beforeEach(() => {
|
||||
// Reset document state
|
||||
document.body.style.cssText = "";
|
||||
document.head.querySelectorAll("style[title^='custom-theme-']").forEach((el) => el.remove());
|
||||
});
|
||||
|
||||
it("should not remove font family custom properties", async () => {
|
||||
// Mock theme elements
|
||||
const lightTheme = {
|
||||
dataset: { mxTheme: "light" },
|
||||
disabled: true,
|
||||
href: "fake URL",
|
||||
onload: (): void => void 0,
|
||||
} as unknown as HTMLStyleElement;
|
||||
|
||||
const removePropertySpy = jest.fn();
|
||||
const styleObject = {
|
||||
0: FontWatcher.FONT_FAMILY_CUSTOM_PROPERTY,
|
||||
1: FontWatcher.EMOJI_FONT_FAMILY_CUSTOM_PROPERTY,
|
||||
2: "--custom-color",
|
||||
length: 3,
|
||||
removeProperty: removePropertySpy,
|
||||
};
|
||||
jest.spyOn(document.body, "style", "get").mockReturnValue(styleObject as any);
|
||||
jest.spyOn(document, "querySelectorAll").mockReturnValue([lightTheme] as any);
|
||||
|
||||
// Trigger clearCustomTheme via setTheme
|
||||
await new Promise((resolve) => {
|
||||
setTheme("light").then(resolve);
|
||||
lightTheme.onload!({} as Event);
|
||||
});
|
||||
|
||||
// Check that font properties were NOT removed
|
||||
expect(removePropertySpy).not.toHaveBeenCalledWith(FontWatcher.FONT_FAMILY_CUSTOM_PROPERTY);
|
||||
expect(removePropertySpy).not.toHaveBeenCalledWith(FontWatcher.EMOJI_FONT_FAMILY_CUSTOM_PROPERTY);
|
||||
// But custom color should be removed
|
||||
expect(removePropertySpy).toHaveBeenCalledWith("--custom-color");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue