Skip to content

refactor: unify theme color resolution across display paths#272

Open
jedrazb wants to merge 2 commits intomainfrom
fix/unify-theme-color-resolution
Open

refactor: unify theme color resolution across display paths#272
jedrazb wants to merge 2 commits intomainfrom
fix/unify-theme-color-resolution

Conversation

@jedrazb
Copy link
Copy Markdown
Contributor

@jedrazb jedrazb commented Apr 17, 2026

Summary

Follow-up to #270. Extracts a single shared helper — resolveColorToHex(color, theme) — and routes every display-side call site through it so themeFill/themeColor with themeTint/themeShade is honored everywhere, not just on table cells.

Background

#270 fixed the OOXML tint/shade math and table-cell theme resolution, but the same bug pattern (direct .fill.rgb reads that silently drop themed fills) remained in two other places:

  • Paragraph shading in layout-bridge/toFlowBlocks.ts — paragraphs with w:shd w:themeFill=\"accent1\" rendered with no background.
  • Clipboard HTML export in utils/clipboard.ts — themed text color and shading were dropped when copy-pasting to external apps (Gmail, Word, etc.).

Changes

New helper — resolveColorToHex

packages/core/src/utils/colorResolver.ts

  • Accepts any ColorValue (rgb, themeColor + tint/shade, or auto).
  • Returns a 6-char uppercase hex without #, or undefined when unresolvable (transparent, auto, or theme ref with no theme).
  • Gracefully degrades when a theme ref has no theme: falls back to rgb if present, else undefined.

Unified call sites

  • prosemirror/conversion/toProseDoc.ts — replaces the inline resolution added in fix: correct OOXML theme color tint/shade resolution #270 (table cells).
  • layout-bridge/toFlowBlocks.ts — paragraph shading (new fix).
  • utils/clipboard.tsrunToHtml and paragraphsToHtml now thread an optional theme and resolve both text color and shading via the shared helper. ClipboardOptions gains theme?: Theme | null; UseClipboardOptions in useClipboard follows suit.

Backwards compatible — theme is optional everywhere; omitting it preserves the previous rgb-only behavior.

Known follow-up

fromProseDoc.ts:1508 writes attrs.backgroundColor back as plain { fill: { rgb } }, which can strip themeFill/themeFillTint/themeFillShade on round-trip after #270 started populating backgroundColor for themed cells. Documented here as a separate concern — fix requires either threading the theme into fromProseDoc or stashing a "resolved fill" sentinel on _originalFormatting to detect user edits. Left for a follow-up since it touches a different seam.

Tests

  • colorResolver.test.ts — 10 new cases covering helper edge cases (undefined, auto, rgb, themeColor w/ and w/o tint/shade, missing-theme fallback, leading-# normalization).
  • layout-bridge/__tests__/toFlowBlocks-shading.test.ts (new) — end-to-end: Document model → toProseDoctoFlowBlocks, verifies paragraph attrs.shading resolves themed fills.
  • clipboard.test.ts — 5 new cases covering themed text color and shading in HTML output, plus graceful no-theme degradation.

Test plan

  • bun run typecheck passes (all 4 packages)
  • bun test — 377 pass, 0 fail (was 357 on main, +20 new tests)
  • bun run format clean
  • npx playwright test tests/demo-docx.spec.ts — 44/45 pass (1 pre-existing failure on main, unrelated to colors)

🤖 Generated with Claude Code

Adds `resolveColorToHex` as the single shared helper for converting any
`ColorValue` (rgb or themeColor+tint/shade) to a display-ready hex string,
with consistent handling of transparent/auto and missing-theme cases.

Applies it at every display-side call site so `themeFill`/`themeColor`
with `themeTint`/`themeShade` is honored everywhere, not just on table cells:

- `toProseDoc.ts` — replaces the inline resolution added in #270.
- `toFlowBlocks.ts` — paragraph shading now resolves themed fills (previously
  read `.fill.rgb` directly, silently dropping themed paragraph backgrounds).
- `clipboard.ts` — HTML copy now honors themed text color and shading when
  a theme is threaded through `ClipboardOptions`/`useClipboard` options.

Tests: +20 new pass (357 → 377 total), covering helper edge cases,
paragraph themed-shading end-to-end (Document → PM → flow blocks), and
clipboard HTML with themed runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docx-editor Ready Ready Preview, Comment Apr 17, 2026 7:21am

Request Review

…tches

Addresses review feedback on #272.

**fromProseDoc round-trip fix** — themed cells (`themeFill` + `themeFillTint`/`themeFillShade`) no longer lose their theme refs on save. Stores the parse-time resolved hex in a new `_originalResolvedFill` attr; if it still matches `attrs.backgroundColor` at save time, the user hasn't changed the color so `orig.shading` is preserved intact. If they have changed it, we write plain `{ fill: { rgb } }` as before.

**Helper simplification** — `resolveColorToHex` now uses `slice(1)` instead of a second `.replace(/^#/, '')` in the themed-color branch (`resolveColor` already guarantees the `#` prefix). Dedups the rgb-without-theme fallback by folding it into the single `rgb` branch below. Trims the docstring.

**Unify remaining sites** — three sites were hand-rolling the same `resolveColor(...).replace(/^#/, '')` pattern; all now use the helper:
- `DocxEditor.tsx:1474` (cell border color)
- `FormattingBar.tsx:597` (table border color picker value)
- `AdvancedColorPicker.tsx:222` (selected-cell hex comparison)

Plus two sites that read `.color?.rgb` directly and dropped themed text colors:
- `DocxEditor.tsx` text-color swatch readout
- `toolbarUtils.ts` `getSelectionFormatting` (new optional `theme` param)

**Tests** — 3 new round-trip tests in `toProseDoc.test.ts` proving themed `tint`/`shade` survive toProseDoc → fromProseDoc unchanged, and that user-initiated color changes still override theme refs with plain rgb.

380 pass (was 377), typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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