fix: update wysiwyg color on theme change (#10618)

This commit is contained in:
David Luzar
2026-01-07 12:55:33 +01:00
committed by GitHub
parent 87faa5d3da
commit cc6c29c0b9
2 changed files with 72 additions and 0 deletions
@@ -8,7 +8,10 @@ import {
KEYS,
FONT_FAMILY,
TEXT_ALIGN,
THEME,
VERTICAL_ALIGN,
applyDarkModeFilter,
tinycolor,
} from "@excalidraw/common";
import type {
@@ -22,6 +25,7 @@ import { Keyboard, Pointer, UI } from "../tests/helpers/ui";
import { getTextEditor, updateTextEditor } from "../tests/queries/dom";
import {
GlobalTestState,
act,
render,
screen,
unmountComponent,
@@ -1662,4 +1666,60 @@ describe("textWysiwyg", () => {
expect(h.elements[1].angle).toBe(30);
});
});
describe("Test theme change", () => {
const { h } = window;
// Helper to compare colors (browser may return rgb format)
const colorsAreEqual = (color1: string, color2: string) => {
return tinycolor(color1).toHex() === tinycolor(color2).toHex();
};
beforeEach(async () => {
await render(
<Excalidraw
handleKeyboardGlobally={true}
initialData={{
appState: {
theme: THEME.LIGHT,
},
}}
/>,
);
API.setElements([]);
});
it("should update textarea color when theme changes to dark mode and back", async () => {
const originalColor = "#ff0000";
const textElement = API.createElement({
type: "text",
text: "test",
strokeColor: originalColor,
});
API.setElements([textElement]);
mouse.doubleClickOn(textElement as ExcalidrawTextElement);
const editor = await getTextEditor({ waitForEditor: true });
expect(colorsAreEqual(editor.style.color, originalColor)).toBe(true);
act(() => {
h.setState({ theme: THEME.DARK });
// Trigger element mutation to fire onChange callback
h.app.scene.mutateElement(textElement, {});
});
expect(
colorsAreEqual(editor.style.color, applyDarkModeFilter(originalColor)),
).toBe(true);
act(() => {
h.setState({ theme: THEME.LIGHT });
h.app.scene.mutateElement(textElement, {});
});
expect(colorsAreEqual(editor.style.color, originalColor)).toBe(true);
});
});
});
@@ -132,7 +132,11 @@ export const textWysiwyg = ({
return false;
};
let LAST_THEME = app.state.theme;
const updateWysiwygStyle = () => {
LAST_THEME = app.state.theme;
const appState = app.state;
const updatedTextElement = app.scene.getElement<ExcalidrawTextElement>(id);
@@ -598,6 +602,7 @@ export const textWysiwyg = ({
window.removeEventListener("blur", handleSubmit);
window.removeEventListener("beforeunload", handleSubmit);
unbindUpdate();
unsubOnChange();
unbindOnScroll();
editable.remove();
@@ -696,6 +701,13 @@ export const textWysiwyg = ({
}
};
// FIXME after we start emitting updates from Store for appState.theme
const unsubOnChange = app.onChangeEmitter.on((elements) => {
if (app.state.theme !== LAST_THEME) {
updateWysiwygStyle();
}
});
// handle updates of textElement properties of editing element
const unbindUpdate = app.scene.onUpdate(() => {
updateWysiwygStyle();