Skip to content

Make caret track resolved text color at cursor position#315

Merged
hackerwins merged 2 commits into
mainfrom
cursor-follows-text-color
May 30, 2026
Merged

Make caret track resolved text color at cursor position#315
hackerwins merged 2 commits into
mainfrom
cursor-follows-text-color

Conversation

@hackerwins

@hackerwins hackerwins commented May 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Slides text-edit caret on dark deck themes (e.g. Simple Dark) was invisible — the docs Theme.cursorColor knows about light/dark mode of the docs package but not about per-deck slide backgrounds, so a dark caret painted on top of a dark slide.
  • Match Google Docs/Slides behaviour: caret picks up the resolved text color at the cursor position (light text → light caret, red text → red caret).
  • Adds resolveColorAtPosition helper next to defaultColorResolver, widens the three caret paint sites (paintLayout, DocCanvas body/header/footer) with an optional cursor.color, and threads the resolved color from the slides text-box editor and the docs full editor. Falls back to Theme.cursorColor when no color is supplied so existing callers are unaffected.

Test plan

  • pnpm verify:fast
  • Unit: 5 new cases in packages/docs/test/model/color.test.ts cover the seam rule, role-color fallback, missing color, theme-aware resolver
  • Unit: 2 new cases in packages/docs/test/view/themed-color.test.ts assert the cursor.color override + Theme.cursorColor fallback paths
  • Manual smoke: open a Simple Dark deck in pnpm dev, enter a text placeholder, confirm the caret is visible against the dark slide background
  • Manual smoke: in light-theme docs, set a run to red, place the caret inside it, confirm the caret renders red

Design notes in docs/tasks/active/20260530-cursor-follows-text-color-todo.md.

Out of scope: honouring styleBuffer (toolbar-picked color before next keystroke); selection-spanning caret; peer carets already carry their own per-peer color.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Documentation

    • Added documentation about cursor color rendering improvements.
  • Bug Fixes

    • Text cursor now automatically matches the surrounding text color instead of using a fixed theme color, improving visibility with dark themes where contrast could make the cursor invisible.
  • Tests

    • Added test coverage for cursor color resolution and rendering.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@hackerwins, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 16 minutes and 39 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 368fa9b4-723c-43f7-aea5-9371e0f6860e

📥 Commits

Reviewing files that changed from the base of the PR and between 36cff78 and 0136100.

📒 Files selected for processing (9)
  • docs/tasks/active/20260530-cursor-follows-text-color-lessons.md
  • docs/tasks/active/20260530-cursor-follows-text-color-todo.md
  • packages/docs/src/model/color.ts
  • packages/docs/src/view/doc-canvas.ts
  • packages/docs/src/view/editor.ts
  • packages/docs/src/view/paint-layout.ts
  • packages/docs/src/view/text-box-editor.ts
  • packages/docs/test/model/color.test.ts
  • packages/docs/test/view/themed-color.test.ts
📝 Walkthrough

Walkthrough

This PR implements cursor color resolution to make text-edit carets visible in dark-themed decks. It adds a color resolution helper, extends render interfaces to accept per-cursor colors, wires color computation into editors, and verifies the behavior with unit and integration tests.

Changes

Cursor Color Resolution and Rendering Pipeline

Layer / File(s) Summary
Color resolution helper
packages/docs/src/model/color.ts, packages/docs/test/model/color.test.ts
New resolveColorAtPosition(block, offset, colorResolver, fallback) function selects the inline at a given offset, resolves its color via a provided resolver, and falls back to a default. Unit tests cover fallback behavior, inline selection including boundary cases, undefined resolver results, and theme-aware resolvers.
Render pipeline contracts
packages/docs/src/view/paint-layout.ts, packages/docs/src/view/doc-canvas.ts
PaintLayoutOpts.cursor and DocCanvas.render cursor parameters now accept optional color?: string. Caret rendering uses cursor.color ?? theme.cursorColor for body, header, and footer cursors.
Editor cursor color resolution
packages/docs/src/view/editor.ts, packages/docs/src/view/text-box-editor.ts
Editors compute and attach resolved cursor color using resolveColorAtPosition with defaultColorResolver and theme.cursorColor fallback. Main canvas, header, and footer cursors receive the resolved color during rendering.
Integration verification
packages/docs/test/view/themed-color.test.ts
New tests verify paintLayout uses provided cursor.color override and falls back to theme color when unspecified.
Task documentation
docs/tasks/active/20260530-cursor-follows-text-color-*.md
Task plan documenting the fix, implementation steps, verification checklist, and out-of-scope behaviors. Placeholder lesson page for post-implementation notes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • wafflebase/wafflebase#64: Modifies DocCanvas.render(...) cursor rendering pipeline in the same function and parameter layer.
  • wafflebase/wafflebase#90: Also extends DocCanvas.render(...) parameters for rendering configuration (cursor input parameters overlap at the same call boundary).
  • wafflebase/wafflebase#300: Threads theme-aware inline colors through the text-box editor rendering pipeline, parallel to this PR's per-caret color wiring.

🐰 A cursor once hid in the dark,
Invisible, lost without spark,
But now with a glow,
It steals the show,
Following text with a lark! 🎨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Make caret track resolved text color at cursor position' is clear, specific, and directly summarizes the primary change across multiple files to render the text caret in the resolved color of text at the cursor position rather than a static theme color.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor-follows-text-color

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/docs/test/view/themed-color.test.ts`:
- Around line 72-90: The test is a false positive because the inline text uses
the same color as the caret override; change the inline text style in the Block
from '`#ffffff`' to a different color (e.g., '`#000000`' or '`#00ff00`') so text and
caret colors differ, and then assert caret-specific drawing: use the fake canvas
context produced by makeFakeCtx() to verify the caret draw call (paintLayout ->
fillRect) used the override color '`#ffffff`' (for example by checking the last
fill style pushed to fillStyles or the specific fillRect call associated with
the cursor draw), ensuring computeLayout/paintLayout and the cursor object
passed to paintLayout are the symbols referenced.
- Around line 92-109: The test's assertion is too broad: instead of checking for
any hex color in fillStyles, pass a deterministic theme with a unique
cursorColor (e.g. '`#ABCDEF`') into paintLayout (or the fake context from
makeFakeCtx) and then assert that fillStyles contains that exact value; update
the test that uses makeFakeCtx(), computeLayout(...), and paintLayout(...) to
inject the known theme.cursorColor and replace the regex assertion with
expect(fillStyles.includes('`#ABCDEF`')).toBe(true) so the caret fallback is
verified precisely.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8e191d10-2f4b-4a31-a6fb-1ab640a1683e

📥 Commits

Reviewing files that changed from the base of the PR and between 988dcd9 and 36cff78.

📒 Files selected for processing (9)
  • docs/tasks/active/20260530-cursor-follows-text-color-lessons.md
  • docs/tasks/active/20260530-cursor-follows-text-color-todo.md
  • packages/docs/src/model/color.ts
  • packages/docs/src/view/doc-canvas.ts
  • packages/docs/src/view/editor.ts
  • packages/docs/src/view/paint-layout.ts
  • packages/docs/src/view/text-box-editor.ts
  • packages/docs/test/model/color.test.ts
  • packages/docs/test/view/themed-color.test.ts

Comment thread packages/docs/test/view/themed-color.test.ts
Comment thread packages/docs/test/view/themed-color.test.ts
@github-actions

github-actions Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor

Verification: verify:self

Result: ✅ PASS in 257.1s

Lane Status Duration
tokens:build ✅ pass 2.1s
sheets:build ✅ pass 14.5s
docs:build ✅ pass 12.6s
slides:build ✅ pass 14.5s
verify:fast ✅ pass 168.6s
frontend:build ✅ pass 18.6s
verify:frontend:chunks ✅ pass 0.3s
backend:build ✅ pass 5.0s
cli:build ✅ pass 2.1s
verify:entropy ✅ pass 18.6s

Verification: verify:integration

Result: ✅ PASS

@codecov

codecov Bot commented May 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 56.00000% with 33 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/docs/src/view/editor.ts 32.50% 26 Missing and 1 partial ⚠️
packages/docs/src/model/color.ts 83.33% 3 Missing ⚠️
packages/docs/src/view/doc-canvas.ts 50.00% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

hackerwins and others added 2 commits May 31, 2026 01:30
On a Slides deck with the Simple Dark theme (and any future theme that
paints light text on a dark background), the text-edit caret was
rendered with the docs `Theme.cursorColor`. That theme knows about
light/dark mode of the docs package itself but not about deck-theme
backgrounds, so the caret painted in dark ink and was effectively
invisible against the slide background.

Match Google Docs/Slides behaviour: the caret picks up the resolved
text color at the cursor position. Adds `resolveColorAtPosition` next
to the existing `defaultColorResolver`, widens the three caret paint
sites (`paintLayout`, `DocCanvas` body/header/footer) with an optional
`cursor.color` field, and threads the resolved color from the slides
text-box editor and the docs full editor.

Falls back to `Theme.cursorColor` when no color is supplied so
existing callers keep their current rendering.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
CodeRabbit flagged the two caret-paint tests as false positives. The
override test used the same color for inline text and caret override
(`#ffffff`), so the assertion could not distinguish the caret pass
from the text pass. The fallback test only checked that some hex
string reached `fillStyle`, which any text run satisfies.

Pick distinct text / caret colors and assert against the last
`fillStyle` entry — paintLayout draws the caret last, so the final
fillStyle write must be the cursor color. Also assert the chosen
text color differs from `Theme.cursorColor` so the fallback test
cannot match the text-paint fillStyle by accident.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@hackerwins
hackerwins force-pushed the cursor-follows-text-color branch from 955f2f8 to 0136100 Compare May 30, 2026 16:33
@hackerwins
hackerwins merged commit ea810a8 into main May 30, 2026
4 checks passed
@hackerwins
hackerwins deleted the cursor-follows-text-color branch May 30, 2026 16:43
hackerwins added a commit that referenced this pull request May 30, 2026
On a Slides deck with the Simple Dark theme (and any future deck theme
that paints light text on a dark background), the text-edit caret was
rendered with the docs `Theme.cursorColor`. That theme knows about
light/dark mode of the docs package itself but not about per-deck slide
backgrounds, so the caret painted in dark ink and was effectively
invisible against the slide background.

Match Google Docs / Slides behaviour: the caret picks up the resolved
text color at the cursor position — light text yields a light caret,
red text yields a red caret. Adds `resolveColorAtPosition` next to the
existing `defaultColorResolver`, widens the three caret paint sites
(`paintLayout`, `DocCanvas` body / header / footer) with an optional
`cursor.color` field, and threads the resolved color from the slides
text-box editor and the docs full editor. Falls back to
`Theme.cursorColor` when no color is supplied so existing callers keep
their current rendering.

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
hackerwins added a commit that referenced this pull request May 30, 2026
On a Slides deck with the Simple Dark theme (and any future deck theme
that paints light text on a dark background), the text-edit caret was
rendered with the docs `Theme.cursorColor`. That theme knows about
light/dark mode of the docs package itself but not about per-deck slide
backgrounds, so the caret painted in dark ink and was effectively
invisible against the slide background.

Match Google Docs / Slides behaviour: the caret picks up the resolved
text color at the cursor position — light text yields a light caret,
red text yields a red caret. Adds `resolveColorAtPosition` next to the
existing `defaultColorResolver`, widens the three caret paint sites
(`paintLayout`, `DocCanvas` body / header / footer) with an optional
`cursor.color` field, and threads the resolved color from the slides
text-box editor and the docs full editor. Falls back to
`Theme.cursorColor` when no color is supplied so existing callers keep
their current rendering.

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
hackerwins added a commit that referenced this pull request May 31, 2026
On a Slides deck with the Simple Dark theme (and any future deck theme
that paints light text on a dark background), the text-edit caret was
rendered with the docs `Theme.cursorColor`. That theme knows about
light/dark mode of the docs package itself but not about per-deck slide
backgrounds, so the caret painted in dark ink and was effectively
invisible against the slide background.

Match Google Docs / Slides behaviour: the caret picks up the resolved
text color at the cursor position — light text yields a light caret,
red text yields a red caret. Adds `resolveColorAtPosition` next to the
existing `defaultColorResolver`, widens the three caret paint sites
(`paintLayout`, `DocCanvas` body / header / footer) with an optional
`cursor.color` field, and threads the resolved color from the slides
text-box editor and the docs full editor. Falls back to
`Theme.cursorColor` when no color is supplied so existing callers keep
their current rendering.

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
hackerwins added a commit that referenced this pull request May 31, 2026
PRs #257/#301/#303/#304/#305/#306/#307/#309/#315/#316/#317/#321/#322
shipped between v0.4.2 and the v0.4.3 cut, leaving their paired todo
files in active with the process checkboxes still open. Flip the
remaining boxes for the work that landed, then move the paired
todo/lessons into docs/tasks/archive/2026/05/ via pnpm tasks:archive.
Active count drops from 17 to 6; archive count grows by 21 files.

Patch release covering 29 commits since v0.4.2. Headline theme is
Slides editing & UX polish toward Google Slides / PowerPoint parity:
smart guides (equal-spacing / distance / size), Shift drag modifiers,
text inside shapes, a Format options right panel, tier-1 universal
toolbar controls, text autofit (shrink + grow), group-selection
visuals, and several smaller text-box / selection fixes. PPTX import
gained paragraph-level bullet styles, body anchor (vertical
alignment), and stretched blipFill cover-crop.

Docs added a pending-inline-style at collapsed caret, a caret that
tracks the resolved text color, bullet indent on Tab / Shift+Tab,
font / size / line-spacing / clear formatting toolbar controls, an
inline-style-attribute clear that actually lands in the CRDT, and a
polished toolbar trigger / color swatch pass shared across docs /
sheets / slides. Sheets gained .xlsx import.

Infrastructure: Docker images now build on native arm64 runners,
fixing the release hang seen on v0.4.2. No Prisma migration, no new
backend env vars — the devops bump is a routine image-tag change.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant