Skip to content

feat(ui): paint and clear non-palette highlight colors - #330

Merged
cameronapak merged 7 commits into
mainfrom
cursor/cp/ype-4494-non-palette-highlight-paint-clear-4e35
Aug 12, 2026
Merged

feat(ui): paint and clear non-palette highlight colors#330
cameronapak merged 7 commits into
mainfrom
cursor/cp/ype-4494-non-palette-highlight-paint-clear-4e35

Conversation

@cameronapak

@cameronapak cameronapak commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Review feedback addressed (Brenden / bmanquen)

Spec / correctness

  • buildVerseActionSwatches now normalizes every activeHighlights entry once up front; remove/apply rows use that normalized set only (fixes uppercase/# palette colors missing from remove row and duplicate swatch keys).
  • Tests: Story 10 (non-palette on part of selection still gets remove swatch); server parseServerColors path drops invalid hex.

Docs

  • docs/highlight-flow-statechart.md: TAP_COLOR noop covers non-palette apply (YPE-4494).
  • docs/adr/YPE-3705-controlled-mode.md: valid non-palette paint/clear in scope; custom apply creation still out of scope.

Nits

  • Shared stripHighlightHexPrefix helper for validation + normalization.
  • Comment on non-palette .sort() for stable tray order.
  • fillFor(hex) in popover test instead of magic rgb string.

Explicitly not done: machine guard collapse, unified projector, export cleanup, # rejection tightening.

YPE-4494

Open in Web Open in Cursor 

Visual context (YPE-4494)

Policy in one pass:

on(API color / user action)
  invalid hex        -> drop (no paint, no swatch)
  valid non-palette  -> paint + exact Clear swatch; apply rejected
  palette            -> paint + Clear; apply allowed

Ownership:

packages/ui/src/
|-- lib/
|   |-- highlight-colors.ts      # validate / normalize / swatch row
|   `-- highlight-projection.ts  # project any valid API hex into paint
|-- components/
|   |-- use-bible-reader-highlights.ts      # controlled + live projection
|   |-- bible-reader-highlights-machine.ts  # palette-only apply paths
|   `-- verse-action-popover.tsx            # Clear for exact color

Flow:

flowchart LR
  API[API / controlled highlight] --> Valid{Valid 6-digit hex?}
  Valid -->|no| Drop[Drop]
  Valid -->|yes| Paint[Normalize + paint]
  Paint --> Tray[Popover swatches]
  Tray --> Remove[Clear at exact hex]
  Apply[Apply tap] --> Gate{In HIGHLIGHT_COLORS?}
  Gate -->|yes| Write[Write highlight]
  Gate -->|no| Reject[Reject]
Loading

Pairs with expo #131 for the native tray.

Greptile Summary

The PR extends Bible-reader highlight projection and removal to valid non-palette hexadecimal colors while retaining palette-only apply behavior and dropping invalid colors.

  • Adds shared color validation, normalization, swatch construction, and highlight projection behavior.
  • Updates controlled and self-contained highlight flows, verse presentation, tests, documentation, and the package changeset.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/ui/src/lib/highlight-colors.ts Centralizes hexadecimal validation and normalization and constructs apply/remove swatch rows with support for valid non-palette colors.
packages/ui/src/lib/highlight-projection.ts Projects all valid normalized highlight colors into the rendered verse map while excluding invalid values.
packages/ui/src/components/use-bible-reader-highlights.ts Integrates normalized server and controlled highlight projection with the existing adapter.
packages/ui/src/components/bible-reader-highlights-machine.ts Enforces palette-only apply operations at the state-machine boundary while preserving remove behavior for projected colors.
packages/ui/src/components/verse-action-popover.tsx Presents exact-color removal swatches for valid non-palette highlights.
packages/ui/src/components/verse.tsx Updates verse highlight rendering and contrast behavior for arbitrary valid hexadecimal fills.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[API or controlled highlight] --> B{Valid six-digit hex?}
  B -->|No| C[Drop]
  B -->|Yes| D[Normalize and paint]
  D --> E[Expose exact-color clear swatch]
  F[User apply tap] --> G{Palette color?}
  G -->|Yes| H[Apply highlight]
  G -->|No| I[No-op]
Loading

Reviews (6): Last reviewed commit: "docs(ui): note HIGHLIGHT_COLORS re-expor..." | Re-trigger Greptile

Context used:

Implement YPE-4494 web highlight paint/clear rules aligned with RN Expo:
- Apply stays palette-only; reject non-palette writes
- Paint valid non-palette API hex; drop invalid hex
- Remove tray shows exact hex + checkmark for every distinct valid color (ANY rule)
- Add buildVerseActionSwatches and highlight color helpers with unit tests
@changeset-bot

changeset-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: bce34ee

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@youversion/platform-react-ui Patch
vite-react Patch
@youversion/platform-core Patch
@youversion/platform-react-hooks Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@cameronapak cameronapak self-assigned this Aug 12, 2026

@cameronapak cameronapak left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Spec

Pass (minor soft edges) vs YPE-4494.

  • Apply palette-only; non-palette apply → noop
  • Paint accepts valid non-palette; invalid dropped
  • buildVerseActionSwatches: exact-hex remove + checkmark; apply palette-only; ANY kept
  • Hook/machine remove path allows non-palette clear
  • Changeset present; no Swift/Kotlin

Soft: remove matching in places uses toLowerCase() rather than normalizeHighlightHex (# prefixed edge). Fine if API never sends #.

Standards

Mostly pass.

  1. Hard (test shape): new highlight-colors.test.ts has four top-level describes. Root AGENTS.md Musts ask for one optional top-level describe per module (no nested). Flatten or use one module describe.
  2. Judgement: changeset also patches @youversion/platform-core + @youversion/platform-react-hooks with no code changes there — confirm that’s intentional for unified versioning.
  3. Judgement: palette-apply gates repeated across machine + hook (policy lives in highlight-colors, enforcement still sprinkled).

Product rules look right; docs/test-shape nits only.


Code Reviewer bot, sent on behalf of Cam. Own-PR review → COMMENT (GitHub blocks self-approve).

Comment thread packages/ui/src/lib/highlight-colors.ts
Comment thread packages/ui/src/lib/highlight-colors.test.ts Outdated
Comment thread .changeset/ype-4494-non-palette-highlight-paint-clear.md Outdated
@cameronapak
cameronapak marked this pull request as ready for review August 12, 2026 16:00
Flatten highlight-colors.test.ts to one module describe with flat it
blocks per AGENTS.md testing Musts.

Scope the changeset to @youversion/platform-react-ui only; unified
versioning is handled by the fixed group in changeset config.

@cameronapak cameronapak left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Re-review @ 6cbfbbd

Follow-up addresses the prior Standards notes.

Spec

Pass. Unchanged product rules still match YPE-4494 (prior review).

Standards

Pass.

  • highlight-colors.test.ts now uses a single top-level describe('highlight-colors')
  • Changeset is platform-react-ui only (core/hooks bump removed)

No remaining blocking findings from my side.


Code Reviewer bot, sent on behalf of Cam. Own-PR review → COMMENT (GitHub blocks self-approve).

Comment thread packages/ui/src/lib/highlight-colors.test.ts
Comment thread .changeset/ype-4494-non-palette-highlight-paint-clear.md
Comment thread packages/ui/src/components/verse-action-popover.test.tsx
cursoragent and others added 2 commits August 12, 2026 16:18
Light-mode paints highlights at full strength, so black API colors sat under dark body text. Flip verse text and the remove checkmark to white when fill luma is dark.

Co-authored-by: Cursor <cursoragent@cursor.com>

@bmanquen bmanquen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Two-axis review — Standards (repo conventions + Fowler smell baseline) and Spec (YPE-4494, web half only; RN Expo lands on platform-sdk-reactnative-expo#100). Findings are inline, as conventional comments. Nothing fixed — reporting only.

No hard standards violations. All web-half spec requirements are met: apply stays palette-only, paint accepts any valid hex, remove swatches use exact hex + checkmark, invalid hex dropped from paint and tray, ANY rule unchanged. 129 tests pass.

One finding has no diff line to anchor to:

suggestion (non-blocking): docs/highlight-flow-statechart.md:29 — "TAP_COLOR forks in flow: authorized / signed out / no permission" no longer describes the machine; tapInert now also swallows non-palette colors. bible-reader.tsx:241 prose was updated, the statechart and docs/adr/YPE-3705-controlled-mode.md ("Out of scope: … custom colors") were not.

Comment thread packages/ui/src/lib/highlight-colors.ts
Comment thread packages/ui/src/lib/highlight-colors.ts Outdated
Comment thread packages/ui/src/lib/highlight-colors.ts
Comment thread packages/ui/src/lib/highlight-colors.ts Outdated
Comment thread packages/ui/src/lib/highlight-colors.ts
Comment thread packages/ui/src/components/use-bible-reader-highlights.ts
Comment thread packages/ui/src/lib/highlight-colors.test.ts
Comment thread packages/ui/src/components/verse-action-popover.test.tsx Outdated
Comment thread packages/ui/src/components/verse-action-popover.tsx
Comment thread packages/ui/src/components/verse-action-popover.tsx
…YPE-4494)

- Normalize activeHighlights once in buildVerseActionSwatches (dedupe/casing)
- Add Story 10, server-path invalid-hex, and normalization tests
- Update highlight-flow and YPE-3705 ADR docs for YPE-4494 rules
- Deduplicate hex prefix stripping; document non-palette sort rationale
Comment thread packages/ui/src/components/verse-action-popover.test.tsx Outdated
cursoragent and others added 2 commits August 12, 2026 18:27
Rebase left <<<<<<< markers in verse-action-popover.test.tsx at HEAD;
keep Edge cases non-palette remove swatch test with fillFor(hex).
Co-authored-by: Cameron Pak <cameronandrewpak@gmail.com>
Comment thread packages/ui/src/components/verse-action-popover.test.tsx Outdated
Comment thread packages/ui/src/components/verse-action-popover.test.tsx Outdated
@cameronapak
cameronapak merged commit f06e86a into main Aug 12, 2026
14 checks passed
@cameronapak
cameronapak deleted the cursor/cp/ype-4494-non-palette-highlight-paint-clear-4e35 branch August 12, 2026 18:55
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.

3 participants