diff --git a/packages/excalidraw/wysiwyg/textWysiwyg.test.tsx b/packages/excalidraw/wysiwyg/textWysiwyg.test.tsx
index e4d290a92f..2a9001f1d9 100644
--- a/packages/excalidraw/wysiwyg/textWysiwyg.test.tsx
+++ b/packages/excalidraw/wysiwyg/textWysiwyg.test.tsx
@@ -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(
+ ,
+ );
+ 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);
+ });
+ });
});
diff --git a/packages/excalidraw/wysiwyg/textWysiwyg.tsx b/packages/excalidraw/wysiwyg/textWysiwyg.tsx
index e1444de561..90a4e101e7 100644
--- a/packages/excalidraw/wysiwyg/textWysiwyg.tsx
+++ b/packages/excalidraw/wysiwyg/textWysiwyg.tsx
@@ -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(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();