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();