Skip to content

feat(core): parse CSS Color 4 syntax - #206

Merged
pbroom merged 4 commits into
mainfrom
feat/core-css-color-4-parsing
Oct 10, 2026
Merged

pbroom merged 4 commits into
mainfrom
feat/core-css-color-4-parsing

Conversation

@pbroom

@pbroom pbroom commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

parse() now implements CSS Color 4 instead of a handful of regexes:

  • The 148 named colors plus transparent (conversion/named-colors.ts,
    packed into one name:hex string; *grey folds onto *gray).
  • rgb()/rgba() and hsl()/hsla() in modern space syntax and legacy comma
    syntax, percentages everywhere CSS allows them (rgb 100% = 255), and
    plain numbers for hsl saturation/lightness.
  • hwb(), lab(), lch() (CIE Lab D50), oklab(), oklch().
  • color() with srgb, srgb-linear, display-p3, rec2020 (BT.1886 2.4
    gamma, as current CSS Color 4 / colorjs.io), a98-rgb, prophoto-rgb,
    xyz, xyz-d65 and xyz-d50, including values outside 0-1.
  • Hue units deg/grad/rad/turn and negative hues; every parsed hue is
    normalized to [0, 360), matching the Color type's documented range.
  • none is a missing component and behaves as 0 (CSS's rule for
    conversion); it is rejected in legacy comma syntax. Lab/OKLab
    lightness and LCH/OKLCH chroma are clamped at parse time per spec.

New conversion/xyz.ts holds the CSS Color 4 float64 matrices (XYZ D65 ->
linear sRGB, Bradford D50 -> D65, Rec2020/A98/ProPhoto -> XYZ) and the
Lab -> XYZ D50 conversion. color(srgb) reuses the existing sign-extended
sRGB transfer function export (p3ToLinearP3Into) rather than a new one.
A final finiteness check rejects values that overflow inside a
conversion (color(srgb 1e300 0 0)).

Tests: reference-accuracy compares every new syntax (all named colors,
random lab/lch/hwb/hsl/rgb% and extended-range color() samples) against
colorjs.io; max observed error is ~5e-15 (tolerance 1e-9). fast-check
properties cover hue normalization in every unit and toCss(oklch) ->
parse round-trips.

Bundle size: parse + toHex + contrastRatio grows 2.64 kB -> 5.13 kB
and the everyday toolkit 2.69 kB -> 5.18 kB, so their budgets rise to
5.2 kB and 5.25 kB (~70 B headroom). The named-color table cannot be
tree-shaken out because parse('red') must work; it is ~1.3 kB gzipped,
the color() / Lab matrices ~0.6 kB, and the parser itself ~0.6 kB.
Other budgets are unchanged. README/docs claims updated accordingly.

Part of a stacked set of PRs (#204 → #221) from the color-kit assessment. Validated per branch with pnpm build and pnpm test; lint, format, typecheck, size, artifact, preprod and agents checks pass at the top of the stack.

🤖 Generated with Claude Code

pbroom commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@greptile-apps

greptile-apps Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Medium risk] Adds CSS Color 4 parsing support to the color library.

The PR should not merge until color() rejects unsupported space names.

Fix All in CursorFindings

  1. P1 Invalid color spaces are accepted ▶

Summary

This PR expands parse() to handle named colors and CSS Color 4 functions and spaces, adds conversion matrices and reference tests, and updates documentation and size budgets.

  • The new color() dispatch also accepts unsupported space names that coincide with top-level color functions.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Input["color(rgb 1 0 0)"] --> Token["space = rgb"]
  Token --> Shared["Top-level rgb handler"]
  Shared --> Result["Color returned instead of rejection"]
Loading

Reviews (1) · Last reviewed commit: "feat(core): parse CSS Color 4 syntax"

Comment thread packages/core/src/conversion/parse.ts
@pbroom
pbroom force-pushed the feat/core-css-color-4-parsing branch from 1e39187 to ebe8c51 Compare October 7, 2026 23:28
@vercel

vercel Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
color-kit Ready Ready Preview Oct 10, 2026 7:01pm UTC

pbroom commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner Author

Merge activity

  • Oct 10, 6:47 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Oct 10, 7:00 PM UTC: Graphite rebased this pull request as part of a merge.
  • Oct 10, 7:00 PM UTC: @pbroom merged this pull request with Graphite.

@pbroom
pbroom changed the base branch from fix/core-input-validation to graphite-base/206 October 10, 2026 18:56
@pbroom
pbroom changed the base branch from graphite-base/206 to main October 10, 2026 18:58
pbroom and others added 4 commits October 10, 2026 18:59
parse() now implements CSS Color 4 instead of a handful of regexes:

- The 148 named colors plus `transparent` (conversion/named-colors.ts,
  packed into one `name:hex` string; `*grey` folds onto `*gray`).
- rgb()/rgba() and hsl()/hsla() in modern space syntax and legacy comma
  syntax, percentages everywhere CSS allows them (rgb 100% = 255), and
  plain numbers for hsl saturation/lightness.
- hwb(), lab(), lch() (CIE Lab D50), oklab(), oklch().
- color() with srgb, srgb-linear, display-p3, rec2020 (BT.1886 2.4
  gamma, as current CSS Color 4 / colorjs.io), a98-rgb, prophoto-rgb,
  xyz, xyz-d65 and xyz-d50, including values outside 0-1.
- Hue units deg/grad/rad/turn and negative hues; every parsed hue is
  normalized to [0, 360), matching the Color type's documented range.
- `none` is a missing component and behaves as 0 (CSS's rule for
  conversion); it is rejected in legacy comma syntax. Lab/OKLab
  lightness and LCH/OKLCH chroma are clamped at parse time per spec.

New conversion/xyz.ts holds the CSS Color 4 float64 matrices (XYZ D65 ->
linear sRGB, Bradford D50 -> D65, Rec2020/A98/ProPhoto -> XYZ) and the
Lab -> XYZ D50 conversion. color(srgb) reuses the existing sign-extended
sRGB transfer function export (p3ToLinearP3Into) rather than a new one.
A final finiteness check rejects values that overflow inside a
conversion (color(srgb 1e300 0 0)).

Tests: reference-accuracy compares every new syntax (all named colors,
random lab/lch/hwb/hsl/rgb% and extended-range color() samples) against
colorjs.io; max observed error is ~5e-15 (tolerance 1e-9). fast-check
properties cover hue normalization in every unit and toCss(oklch) ->
parse round-trips.

Bundle size: `parse + toHex + contrastRatio` grows 2.64 kB -> 5.13 kB
and the everyday toolkit 2.69 kB -> 5.18 kB, so their budgets rise to
5.2 kB and 5.25 kB (~70 B headroom). The named-color table cannot be
tree-shaken out because parse('red') must work; it is ~1.3 kB gzipped,
the color() / Lab matrices ~0.6 kB, and the parser itself ~0.6 kB.
Other budgets are unchanged. README/docs claims updated accordingly.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
CSS Color 4 legacy rgb() needs all-number or all-percentage channels and
legacy hsl() needs percentage saturation and lightness; #205 enforced
this, and the CSS Color 4 parser accepted rgb(100%, 0, 0) and
hsl(0, 100, 50). The modern space syntax still allows mixing.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…ecks

Measured 5.25 kB (parse + toHex + contrastRatio) and 5.29 kB (everyday)
gzipped after multiline arguments, the HSL saturation clamp and legacy
comma-syntax validation.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@pbroom
pbroom force-pushed the feat/core-css-color-4-parsing branch from ebe8c51 to f92d170 Compare October 10, 2026 18:59
@pbroom
pbroom merged commit 5f99531 into main Oct 10, 2026
6 of 7 checks passed
@pbroom
pbroom deleted the feat/core-css-color-4-parsing branch October 10, 2026 19:00

This branch was successfully deployed

1 active deployment
Preview — f92d1706 Deployed Oct 10, 2026 by vercel[bot]
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