Skip to content

refactor: theme attributes on test and result words (T1) (@miodec) - #8531

Open
Miodec wants to merge 18 commits into
masterfrom
t1-letter-span
Open

Miodec wants to merge 18 commits into
masterfrom
t1-letter-span

Conversation

@Miodec

@Miodec Miodec commented Oct 26, 2026

Copy link
Copy Markdown
Member

Roadmap step T1. Stacked on #8529 (TH1).

Summary

Theme attributes on the test and result words. <letter>/<hint> keep their tags and classes (old selectors keep working); they become spans in CL3.

 <div id="words" class="… blind flipped highlight-word"
+     data-ui-element="words" data-ui-variant="highlight-word blind flipped">
   <div class="word typed error"
+       data-ui-element="word" data-ui-state="typedIncorrectly">
     <letter class="incorrect extra"
+            data-ui-element="letter" data-ui-state="extra">
   <div class="word active"
+       data-ui-element="word" data-ui-state="untyped" data-ui-active>
     <letter class="tabChar"
+            data-ui-element="letter" data-ui-state="untyped" data-ui-variant="tab">
     <div class="hints"><hint data-ui-element="typoHint">

 result: words history / replay
+<div data-ui-element="wordsHistory">            <div data-ui-element="replayWords">
+  <div data-ui-element="word">
+    <letter data-ui-element="letter" data-ui-state="correct" data-ui-corrections="corrected extraCorrected">
  • data-ui-state is one value from a status type: LetterStatus, new WordStatus (untyped | typed | typedIncorrectly), ResultLetterStatus (untyped | correct | incorrect | extra).
  • Code finds letters by LETTER_SELECTOR, never the tag (caret, layout, break-joining, typo hints, __mt).
  • Bundled theme and funbox CSS moved off #words, classes and letter. Class selectors map to every state they matched:
.correct                        → correct | deadCorrect
.incorrect                      → incorrect | extra
.incorrect:not(.extra)          → incorrect
:not(.correct):not(.incorrect)  → untyped | dead
.word.typed                     → typed | typedIncorrectly
.word.error                     → typedIncorrectly
.word.active                    → [data-ui-active]
  • Test-page harness reads data-ui-*: word(i).state is a WordStatus, plus word(i).isActive.
  • Spec, roadmap (T1 ticked; CL3 now does the span swap) and glossary updated.

Evidence

Same typed words (correct, incorrect, extra, typed-with-error, active), animations frozen at the same time. Before = th1-test-page-harness, after = this branch. Each pair is byte-identical (cmp).

Computed styles (color, opacity, text-shadow, animation, text-fill, decoration, borders, ::after) of every word and letter, scripted, for the 8 changed themes and 2 funboxes × 30 configs (all highlight modes × blind × flipped, + colorful): 0 differences before vs after.

Keystroke benchmark (production builds, 48 ms gap, 300 chars, 3 runs each, ms):

latency mean latency p95 frame mean
before 6.3 (5.7–7.0) 10.5–11.8 1.9–2.5
after 6.3 (6.1–6.7) 10.7–11.7 2.2–2.5

Tests: full frontend suite green (1658), new specs for word/letter/words-mode attributes and result letter attributes. __mt.checkLayout() clean with tape off/letter/word.

Merge Danger

Door: two-way

Additive attributes; old tags and classes stay. Revert restores the old theme CSS.

Blast Radius: theming

  • Bundled theme selectors lost their ids, so they're less specific: user custom CSS targeting #words … can now beat a bundled theme rule it used to lose to.
  • Result screen: wordsHistory/replayWords share word/letter names with the test, so an unscoped [data-ui-element="letter"][data-ui-state="correct"] rule applies to both.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NZNRfGDYsGYMUTp2zYUTrv

Miodec and others added 10 commits October 26, 2026 23:09
Mounts the real TestPage and engine in jsdom on fake timers, types
through the words input, advances frames, and reads word/letter states,
phase and live stats. Own vitest project (no global DOM query mocks).
Typing driver moved to dev/typing-driver.ts, shared with __mt, plus
compose for IME input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NZNRfGDYsGYMUTp2zYUTrv
The test-page project included one spec file, so a new spec on the
harness would land in the jsx project (mocked DOM queries) and fail
obscurely. Specs on it are now named *.page-spec.tsx, and the harness
throws if it loads with the mocked DOM.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NZNRfGDYsGYMUTp2zYUTrv
test-helpers.ts only fed window.__mt once typing moved to the shared
typing driver.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NZNRfGDYsGYMUTp2zYUTrv
…ts (T1)

Themes target data-ui-element/-state/-variant: words list their modes,
words carry their status and data-ui-active, letters their status and
tab/newline variant. The harness reads them instead of classes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NZNRfGDYsGYMUTp2zYUTrv
… (T1)

Letters carry their final outcome in data-ui-state and what was fixed
while typing in data-ui-corrections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NZNRfGDYsGYMUTp2zYUTrv
…and letter (T1)

Class selectors map to every state they matched: .correct to correct and
deadCorrect, .incorrect to incorrect and extra, .word.typed to typed and
typedIncorrectly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NZNRfGDYsGYMUTp2zYUTrv
@monkeytypegeorge monkeytypegeorge added frontend User interface or web stuff docs Related to Markdown files and documentation assets Languages, themes, layouts, etc. labels Oct 26, 2026
Base automatically changed from th1-test-page-harness to master October 27, 2026 10:59
Miodec and others added 4 commits October 27, 2026 12:04
…variant and wordsWrapper (T1)

Leaves taro/modern_ink .word.error (also styles result words, which have
no error attribute) and funbox read_ahead_disabled/#wordsInput (L2).
Drops phantom's .word .active rule, which matched nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NZNRfGDYsGYMUTp2zYUTrv
… (T1)

History and replay words get the test's WordStatus: typed once committed,
typedIncorrectly where they show .error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NZNRfGDYsGYMUTp2zYUTrv
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NZNRfGDYsGYMUTp2zYUTrv
Copilot AI balanced review requested due to automatic review settings October 27, 2026 11:10
@github-actions github-actions Bot added the waiting for review Pull requests that require a review before continuing label Oct 27, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It is a large theming refactor across ~25 CSS files plus core word/letter rendering with an acknowledged theming blast radius (reduced selector specificity and result/test selector sharing) that warrants human verification of visual output.

No open issues 🎉

What changed in this PR

This PR implements roadmap step T1: it adds stable theme-facing data-ui-* attributes to the test and result words/letters, and migrates the bundled theme and funbox CSS to target those attributes instead of ids/classes/the <letter> tag. The <letter>/<hint> tags and their classes are intentionally retained so legacy selectors keep working until the single announced break in CL3. This is a behavior-preserving refactor on the critical "Track T" path, backed by the new test-page harness (TH1, on which this is stacked).

Changes:

  • Add data-ui-element/data-ui-state/data-ui-variant (plus data-ui-active, data-ui-corrections) to live words/letters (Words, Word, WordLetter, TypoHints) and result words/letters (result-words, ResultWordsHistory, ResultReplay), introducing WordStatus/ResultLetterStatus types and a shared LETTER_SELECTOR.
  • Rewrite 14 theme + 8 funbox CSS files to attribute selectors, expanding each class selector to the states it previously matched (.word.typed → typed|typedIncorrectly, .incorrect → incorrect|extra, etc.).
  • Move dev __mt helpers into expose.ts + new typing-driver.ts (delete test-helpers.ts), add the test-page harness/specs, and update roadmap/spec/glossary/agent docs.
File Description
components/​pages/​test/​Words.tsx Adds data-ui-element="words" and reactive wordsVariant() tokens
components/​pages/​test/​Word.tsx Adds WordStatus, data-ui-state, data-ui-active mirroring retained classes
components/​pages/​test/​WordLetter.tsx Adds letter data-ui-state and tab/newline data-ui-variant
components/​pages/​test/​TypoHints.tsx /​ TestPage.tsx data-ui-element on typo hint / words wrapper; LETTER_SELECTOR
components/​pages/​test/​words-layout.ts Uses LETTER_SELECTOR, reads data-ui-state for incorrect/extra, tags temp letter
components/​pages/​test/​result/​result-words.ts New letterAttributes/wordAttributes + ResultLetterStatus
result/​ResultWordsHistory.tsx /​ ResultReplay.tsx /​ replay.ts Apply result attributes; add typed to replay words
test/​words-history.ts Adds typed (committed) to HistoryWord
states/​word-elements.ts, elements/​caret.ts, test/​break-joining.ts Introduce/use LETTER_SELECTOR
dev/​typing-driver.ts, dev/​expose.ts, dev/​test-helpers.ts Extract typing driver; inline remaining __mt helpers; delete old file
static/​themes/​*.css, static/​funbox/​*.css Migrate selectors to data-ui-*
__tests__/​** (harness, specs, mock-static), vitest.config.ts Test-page harness + new specs; test-page vitest project; language mocks
docs/​*, GLOSSARY.md Roadmap T1/TH1 ticked; spec/glossary/agent-browser updates

I verified the CSS state-mapping is applied consistently (including dead/deadCorrect, :not(.blind), .colorfulMode), that the #typingTest → [data-ui-element="words"] rescoping is equivalent (the result is not inside #typingTest), that wordsVariant() tokens match HighlightModeSchema and the retained classes, that the test-helpers.ts move leaves no dangling imports, and that the mocked getCurrentLanguage signature matches the real one. No concrete defects found.

Review effort: Balanced

# Conflicts:
#	docs/specs/solid-monkeytype/roadmap.md
#	frontend/__tests__/__harness__/test-page.tsx
#	frontend/__tests__/components/pages/test/TestPage.page-spec.tsx
#	frontend/src/ts/dev/expose.ts
#	frontend/src/ts/dev/typing-driver.ts
@github-actions

Copy link
Copy Markdown
Contributor

Continuous integration check(s) failed. Please review the failing check's logs and make the necessary changes.

@github-actions github-actions Bot added waiting for update Pull requests or issues that require changes/comments before continuing and removed waiting for review Pull requests that require a review before continuing labels Oct 28, 2026
…(T1) (@Miodec)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot removed the waiting for update Pull requests or issues that require changes/comments before continuing label Oct 28, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

assets Languages, themes, layouts, etc. docs Related to Markdown files and documentation frontend User interface or web stuff

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants