Skip to content

refactor: Words triggers its own layout (flushes, config, font, resize) (@miodec) - #8507

Merged
Miodec merged 55 commits into
masterfrom
solid-words-layout-effects
Oct 26, 2026
Merged

Miodec merged 55 commits into
masterfrom
solid-words-layout-effects

Conversation

@Miodec

@Miodec Miodec commented Oct 23, 2026

Copy link
Copy Markdown
Member

Words renders #words and owns its layout (createWordsLayout). test-ui
drives it through intents (layout, relayout, resized, reset...) instead
of querying #words. Logic moved unchanged.

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

Miodec and others added 15 commits October 23, 2026 14:48
Words renders #words and owns its layout (createWordsLayout). test-ui
drives it through intents (layout, relayout, resized, reset...) instead
of querying #words. Logic moved unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dren

LineBreak registers its elements by word index. Line jump and tape
scroll walk the rendered words and line breaks from the render store,
no longer depending on LineBreak's markup or class names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The out of focus warning transitioned every #words property, the
inherited font size included, so layout measured the old size and
clipped the words (eg. font size changed from the commandline).
Only transition what .blurred changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
Letter widths change once the new font is applied and loaded, but
nothing repositioned the caret until the next keystroke.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
- getLineAboveTop reads words from the render store, no sibling walk
- font caret update skips reset words and finished tests
- Words' layout prop renamed ref -> onLayout (it isn't an element)
- stale comments about TestPage/test-ui owning #words updated
- specs share renderWords and the static layouts mock from __harness__

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
# Conflicts:
#	docs/AGENT_BROWSER.md
words-render hands its layout hook what the flush changed: new words
(after a reset), the word change, the updated words. Words registers the
hook and lays out new words from scratch, so test-ui no longer tracks
pending layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
resetWordsRender bumps a generation; Words resets on it, and again on the
new words' flush in case a batch deferred the effect past it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
Copilot AI balanced review requested due to automatic review settings October 23, 2026 15:00
@monkeytypegeorge monkeytypegeorge added frontend User interface or web stuff docs Related to Markdown files and documentation labels Oct 23, 2026
@github-actions github-actions Bot added the waiting for review Pull requests that require a review before continuing label Oct 23, 2026
@Miodec
Miodec changed the base branch from master to solid-words-layout October 23, 2026 15:01
@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 23, 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 relocates the app's most intricate layout/animation logic (line jump, tape scroll, caret sync) across module boundaries and bundles at least one new runtime behavior, which warrants human verification of visual/timing equivalence.

No open issues 🎉

What changed in this PR

This PR refactors the test-words layout engine out of the legacy test-ui.ts module and into the SolidJS Words component. Words now renders the #words element itself and owns its layout via a new createWordsLayout factory (words-layout.ts). test-ui.ts no longer queries #words; instead it drives layout through flush intents (newWords, wordChange, updatedWords) carried by the words-render flush hook, plus config/resize effects living inside the component. This continues the ongoing vanilla→Solid migration and better scopes layout lifetime to the component mount.

Changes:

  • Moved line-jump, tape-scroll, wrapper-height, and overflow-guard logic from test-ui.ts into words-layout.ts, reworking DOM-child traversal into an index-based getLayoutItems() model backed by registered word/line-break elements.
  • Words.tsx now renders #words, registers line-break elements, and wires config/resize/flush effects; words-render.ts gains a generation counter, WordsFlush payload, an unregisterable setLayoutHook, and a wordChange on setActiveWord.
  • Updated before-insert-text.ts, TestPage.tsx, tests, and docs to the new module boundaries.
File Description
frontend/​src/​ts/​components/​pages/​test/​words-layout.ts New module containing all moved layout logic (line jump, tape scroll, wrapper height, overflow guard).
frontend/​src/​ts/​components/​pages/​test/​Words.tsx Now owns #words markup, line-break registration, and layout-driving effects/flush hook.
frontend/​src/​ts/​test/​test-ui.ts Removed layout logic; delegates to Words via flush intents; keeps input-position + resize glue.
frontend/​src/​ts/​states/​words-render.ts Added generation, WordsFlush, unregisterable setLayoutHook, wordChange on setActiveWord.
frontend/​src/​ts/​states/​word-elements.ts Added line-break element registry for the layout.
frontend/​src/​ts/​states/​test.ts Comment-only updates reflecting new ownership.
frontend/​src/​ts/​input/​handlers/​before-insert-text.ts Imports wouldActiveWordOverflow from new location.
frontend/​src/​ts/​components/​pages/​test/​TestPage.tsx Drops #words markup; renders <Words>; exports/uses wordsModeClasses.
frontend/​__tests__/​**, __harness__/​render-words.tsx Tests retargeted to words-layout/new Words API; shared render harness added.
GLOSSARY.md, docs/​AGENT_BROWSER.md Documentation additions/clarifications.

Review effort: Balanced

Miodec and others added 2 commits October 23, 2026 17:11
The lists open indexedDB on import; app-shell.spec imports expose in
jsdom, which lacks it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
@monkeytypegeorge monkeytypegeorge removed the docs Related to Markdown files and documentation label Oct 23, 2026
@github-actions github-actions Bot removed the waiting for update Pull requests or issues that require changes/comments before continuing label Oct 23, 2026
…and wordsWrapperRef

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
Miodec and others added 18 commits October 24, 2026 00:04
… words layout

The reset hook runs synchronously, so a reset inside a batch no longer needs
the flush to catch up: drops the store's generation and its effect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
reset -> dropOldWordsLayout, relayout -> layOutAll, inline updateLayout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
…n their flush

Freeing the words for the result needs no reset: a line jump completing after
it finds nothing to remove, and the next new words drop its state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
replaceWords renders the new words and runs the onWordsFlushed hook right
away, so the restart no longer resets, appends and flushes, and the newWords
flag consumed by the next flush is gone. resetWordsRender only frees the words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
…st-ui

The layout moves the words input onto the active word itself, so Words loses
its onActiveWordLaidOut prop and test-ui its wordsWrapper ref.
keepWordsInputInTheCenter moves next to the input element. Drops the
highlightMode effect: highlight mode is only a class on #words now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
The layout publishes the vertical middle of the active word's letters, the
input centers on it in CSS. The layout no longer reads the input element.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
… drop them from test-ui

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
# Conflicts:
#	frontend/src/ts/states/words-render.ts
… typo hints one

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qmCFS2TL6XhqNY5dLX78e
…o the active word

The window scroll moves from WordsInput into the words layout pass: it follows the active word after the input is positioned and recenters after a resize or on focus requests. It only runs during a test; before it, the test block is scrolled into view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…w gotcha

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@monkeytypegeorge monkeytypegeorge added the docs Related to Markdown files and documentation label Oct 25, 2026
Miodec and others added 9 commits October 25, 2026 11:31
Every caller already runs outside a batch or effect: the flush from its animation frame, replaceWords after restart's awaits. Drops the throwaway root and effect per flush; replaceWords documents the constraint instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Words only keeps the active line in view during a test, so resizing an idle
test page no longer recentered #typingTest. TestPage does it now, as the spec
places it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
layoutAll already snaps it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… words

It always measured from the left edge of the next letter, so the caret looked
off by a letter's width in right to left tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	docs/specs/solid-monkeytype/roadmap.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Miodec
Miodec merged commit 87a8fe4 into master Oct 26, 2026
13 checks passed
@Miodec
Miodec deleted the solid-words-layout-effects branch October 26, 2026 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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