diff --git a/frontend/src/html/pages/test.html b/frontend/src/html/pages/test.html index 040345d69fc3..77c9b68d98fa 100644 --- a/frontend/src/html/pages/test.html +++ b/frontend/src/html/pages/test.html @@ -60,7 +60,7 @@
-
+ diff --git a/frontend/src/styles/test.scss b/frontend/src/styles/test.scss index d2a97627b7bd..0169242f3685 100644 --- a/frontend/src/styles/test.scss +++ b/frontend/src/styles/test.scss @@ -1299,23 +1299,6 @@ padding: 1em 2em; } -#compositionDisplay { - font-size: 0.5em; - display: flex; - margin: 1rem auto 0px; - padding: 1rem 2rem; - height: 1.25em; - box-sizing: content-box; - user-select: none; - cursor: default; - color: var(--sub-color); - - &.blurred { - opacity: 0.25; - filter: blur(4px); - } -} - .pageTest { height: 100%; display: grid; diff --git a/frontend/src/ts/components/mount.tsx b/frontend/src/ts/components/mount.tsx index 0fb90c520b10..b269097f4ced 100644 --- a/frontend/src/ts/components/mount.tsx +++ b/frontend/src/ts/components/mount.tsx @@ -23,6 +23,7 @@ import { ProfilePage } from "./pages/profile/ProfilePage"; import { ProfileSearchPage } from "./pages/profile/ProfileSearchPage"; import { SettingsPage } from "./pages/settings/SettingsPage"; import { CapsWarning } from "./pages/test/CapsWarning"; +import { CompositionDisplay } from "./pages/test/CompositionDisplay"; import { Keymap } from "./pages/test/Keymap"; import { TestModesNotice } from "./pages/test/modes-notice/TestModesNotice"; import { Monkey } from "./pages/test/Monkey"; @@ -49,6 +50,7 @@ const components: Record JSXElement> = { commandlinehotkey: () => , testmodesnotice: () => , capswarning: () => , + compositiondisplay: () => , friendspage: () => , notfoundpage: () => , accountsettingspage: () => , diff --git a/frontend/src/ts/components/pages/test/CompositionDisplay.tsx b/frontend/src/ts/components/pages/test/CompositionDisplay.tsx new file mode 100644 index 000000000000..fa16a8c19d47 --- /dev/null +++ b/frontend/src/ts/components/pages/test/CompositionDisplay.tsx @@ -0,0 +1,24 @@ +import { Show } from "solid-js"; + +import { getConfig } from "../../../config/store"; +import { getCompositionText, isOutOfFocus } from "../../../states/test"; +import { cn } from "../../../utils/cn"; + +export function CompositionDisplay() { + return ( + +
+ {getCompositionText()} +
+
+ ); +} diff --git a/frontend/src/ts/elements/composition-display.ts b/frontend/src/ts/elements/composition-display.ts deleted file mode 100644 index 987bfef7f2fc..000000000000 --- a/frontend/src/ts/elements/composition-display.ts +++ /dev/null @@ -1,15 +0,0 @@ -const compositionDisplay = document.getElementById( - "compositionDisplay", -) as HTMLElement; - -export function update(data: string): void { - compositionDisplay.innerText = data; -} - -export function hide(): void { - compositionDisplay.classList.add("hidden"); -} - -export function show(): void { - compositionDisplay.classList.remove("hidden"); -} diff --git a/frontend/src/ts/input/listeners/composition.ts b/frontend/src/ts/input/listeners/composition.ts index 8f7272543782..1b9dc133754c 100644 --- a/frontend/src/ts/input/listeners/composition.ts +++ b/frontend/src/ts/input/listeners/composition.ts @@ -3,10 +3,9 @@ import * as CompositionState from "../../legacy-states/composition"; import * as TestState from "../../test/test-state"; import * as TestLogic from "../../test/test-logic"; import { setLastInsertCompositionTextData } from "../state"; -import * as CompositionDisplay from "../../elements/composition-display"; import { onInsertText } from "../handlers/insert-text"; import { logTestEvent } from "../../test/events/data"; -import { isTestActive } from "../../states/test"; +import { isTestActive, setCompositionText } from "../../states/test"; const inputEl = getInputElement(); @@ -40,7 +39,7 @@ inputEl.addEventListener("compositionupdate", (event) => { if (TestState.testRestarting || TestState.resultCalculating) return; CompositionState.setData(event.data); - CompositionDisplay.update(event.data); + setCompositionText(event.data); const now = performance.now(); @@ -57,7 +56,7 @@ inputEl.addEventListener("compositionend", async (event) => { if (TestState.testRestarting || TestState.resultCalculating) return; CompositionState.setComposing(false); CompositionState.setData(""); - CompositionDisplay.update(""); + setCompositionText(""); setLastInsertCompositionTextData(""); const now = performance.now(); diff --git a/frontend/src/ts/states/test.ts b/frontend/src/ts/states/test.ts index ae02ada75acf..5212f3b47252 100644 --- a/frontend/src/ts/states/test.ts +++ b/frontend/src/ts/states/test.ts @@ -24,6 +24,11 @@ export const [getLoadedChallenge, setLoadedChallenge] = createSignal(null); export const [getResultVisible, setResultVisible] = createSignal(false); export const [getFocus, setFocus] = createSignal(false); +// #words is still vanilla so it's blurred imperatively (see test/out-of-focus); +// the Solid-owned composition display reads this signal instead. +export const [isOutOfFocus, setOutOfFocus] = createSignal(false); +// live IME composition text, pushed from the compositionupdate/end events. +export const [getCompositionText, setCompositionText] = createSignal(""); export const [isTestInvalid, setIsTestInvalid] = createSignal(false); export const [isLongTest, setIsLongTest] = createSignal(false); export const [getLastResult, setLastResult] = createSignal { - qsa("#words, #compositionDisplay") - ?.setStyle({ transition: "0.25s" }) - ?.addClass("blurred"); + qsa("#words")?.setStyle({ transition: "0.25s" })?.addClass("blurred"); + setOutOfFocus(true); qs(".outOfFocusWarning .text")?.setText(messages[mode]); qs(".outOfFocusWarning")?.show(); }, 1000), diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts index 62f2a2b6ca91..ea6df1126d55 100644 --- a/frontend/src/ts/test/test-ui.ts +++ b/frontend/src/ts/test/test-ui.ts @@ -46,7 +46,6 @@ import { } from "../input/input-element"; import * as MonkeyPower from "../elements/monkey-power"; import * as SlowTimer from "../legacy-states/slow-timer"; -import * as CompositionDisplay from "../elements/composition-display"; import * as AdController from "../controllers/ad-controller"; import * as Joining from "./break-joining"; import * as LayoutfluidFunboxTimer from "../test/funbox/layoutfluid-funbox-timer"; @@ -65,6 +64,7 @@ import { getCurrentQuote, isTestActive, resetCurrentLiveStats, + setCompositionText, wordsHaveNewline, } from "../states/test"; import { @@ -450,9 +450,9 @@ function updateWordWrapperClasses(): void { wordsEl.removeClass("colorfulMode"); } - qsa( - "#caret, #paceCaret, #liveStatsMini, #typingTest, #wordsInput, #compositionDisplay", - ).setStyle({ fontSize: `${Config.fontSize}rem` }); + qsa("#caret, #paceCaret, #liveStatsMini, #typingTest, #wordsInput").setStyle({ + fontSize: `${Config.fontSize}rem`, + }); if (TestState.isLanguageRightToLeft) { wordsEl.addClass("rightToLeftTest"); @@ -1905,10 +1905,7 @@ export function onTestRestart(source: "testPage" | "resultPage"): void { } AdController.destroyResult(); if (Config.compositionDisplay === "below") { - CompositionDisplay.update(" "); - CompositionDisplay.show(); - } else { - CompositionDisplay.hide(); + setCompositionText(" "); } void SoundController.clearAllSounds(); cancelPendingAnimationFramesStartingWith("test-ui"); @@ -2028,13 +2025,8 @@ configEvent.subscribe(({ key, newValue }) => { if (key === "showOutOfFocusWarning" && !newValue) { OutOfFocus.hide(); } - if (key === "compositionDisplay") { - if (newValue === "below") { - CompositionDisplay.update(" "); - CompositionDisplay.show(); - } else { - CompositionDisplay.hide(); - } + if (key === "compositionDisplay" && newValue === "below") { + setCompositionText(" "); } if ( ["fontSize", "fontFamily", "blindMode", "hideExtraLetters"].includes(