feat(color-picker): export formatColor utility#823
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds a new exported utility formatColor(value, format) that parses CSS color strings, returns null for unparseable input, serializes OKLCH directly, and for hex/rgb/hsl gamut-maps wide-gamut OKLCH into sRGB before formatting. Hex output is uppercased and uses 8-digit hex when alpha < 1; translucent outputs use rgba/hsla or an okLCH alpha tail. Changes include implementation in utils.ts, re-export in index.ts, unit tests, and docs. Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/raystack/components/color-picker/utils.ts (1)
31-37: 💤 Low value
colorToHexlooks correct. Parse guard, alpha-aware 6/8-digit formatting (?? 1correctly handles the no-alpha case fromparse), gamut-mapping, andnullfallback are all sound. culori'stoGamutshort-circuits already-in-gamut inputs, so opaque sRGB/named-color cases stay exact.Optional: the
alpha === 1 ? formatHex : formatHex8+toUpperCase()tail duplicates thehexbranch ofgetColorString(Lines 113-116). A tiny shared helper would keep the two hex paths from drifting (note the guard there isclipped.alpha === 1vs(safe.alpha ?? 1) === 1here).♻️ Optional shared helper
+const toUpperHex = (color: { alpha?: number }) => + ((color.alpha ?? 1) === 1 ? formatHex(color) : formatHex8(color)).toUpperCase(); + export const colorToHex = (value: string): string | null => { const parsed = parse(value); if (!parsed) return null; - const safe = toSrgb(parsed); - const hex = (safe.alpha ?? 1) === 1 ? formatHex(safe) : formatHex8(safe); - return hex.toUpperCase(); + return toUpperHex(toSrgb(parsed)); };🤖 Prompt for 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. In `@packages/raystack/components/color-picker/utils.ts` around lines 31 - 37, There’s duplicated logic for choosing 6- vs 8-digit hex and uppercasing in colorToHex and getColorString; extract that into a small shared helper (e.g., formatHexWithAlpha or formatHexForColor) that accepts a culori color object (or its clipped/safe variant), checks alpha using the same guard ((color.alpha ?? 1) or clipped.alpha), returns formatHex or formatHex8 and uppercases the result, then replace the hex branch in colorToHex and the corresponding branch in getColorString to call this helper.apps/www/src/content/docs/components/color-picker/index.mdx (1)
87-114: 💤 Low valueDocs match
colorToHex; wide-gamut example values are illustrative.
colorToHexfollows the documented contract:culori.parse+toGamutmapping, uppercase#RRGGBBforalpha===1and#RRGGBBAAotherwise, andnullfor unparseable input.Keep in mind the exact wide-gamut example outputs (
#3E63DD,#FF5843) aren’t pinned by tests—oklch(0.7 0.32 30)is only asserted as a valid 6-digit hex andnot '#FF0000'. Withculoripinned to4.0.2, this should only matter if the dependency is upgraded.🤖 Prompt for 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. In `@apps/www/src/content/docs/components/color-picker/index.mdx` around lines 87 - 114, The docs/examples assert specific outputs for colorToHex but the implementation may produce different gamut-mapped results depending on culori version; update the documentation to clarify that the provided wide-gamut example hex values (e.g., '`#3E63DD`', '`#FF5843`') are illustrative and not guaranteed by tests; reference the colorToHex implementation that uses culori.parse and toGamut and explicitly state that colorToHex returns uppercase '`#RRGGBB`' for alpha===1, '`#RRGGBBAA`' otherwise, and null for unparseable input, noting that exact gamut-mapped outputs can vary with culori versions (e.g., 4.0.2) so tests only assert format/validity rather than exact hex.
🤖 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.
Nitpick comments:
In `@apps/www/src/content/docs/components/color-picker/index.mdx`:
- Around line 87-114: The docs/examples assert specific outputs for colorToHex
but the implementation may produce different gamut-mapped results depending on
culori version; update the documentation to clarify that the provided wide-gamut
example hex values (e.g., '`#3E63DD`', '`#FF5843`') are illustrative and not
guaranteed by tests; reference the colorToHex implementation that uses
culori.parse and toGamut and explicitly state that colorToHex returns uppercase
'`#RRGGBB`' for alpha===1, '`#RRGGBBAA`' otherwise, and null for unparseable input,
noting that exact gamut-mapped outputs can vary with culori versions (e.g.,
4.0.2) so tests only assert format/validity rather than exact hex.
In `@packages/raystack/components/color-picker/utils.ts`:
- Around line 31-37: There’s duplicated logic for choosing 6- vs 8-digit hex and
uppercasing in colorToHex and getColorString; extract that into a small shared
helper (e.g., formatHexWithAlpha or formatHexForColor) that accepts a culori
color object (or its clipped/safe variant), checks alpha using the same guard
((color.alpha ?? 1) or clipped.alpha), returns formatHex or formatHex8 and
uppercases the result, then replace the hex branch in colorToHex and the
corresponding branch in getColorString to call this helper.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7f91001c-ad4a-450c-badd-5910f145223a
📒 Files selected for processing (4)
apps/www/src/content/docs/components/color-picker/index.mdxpackages/raystack/components/color-picker/__tests__/utils.test.tspackages/raystack/components/color-picker/index.tspackages/raystack/components/color-picker/utils.ts
Exposes a small public helper for consumers that need to convert any CSS color string (oklch, rgb, hsl, hex, named) to a string in another format — useful when feeding apsara's OKLCH tokens into APIs that expect hex/rgb/hsl (charts, SVG attrs, canvas, design exports), or normalizing arbitrary input back to the OKLCH design-system format. For sRGB-bound outputs (hex/rgb/hsl), wide-gamut OKLCH inputs are gamut-mapped via culori's `toGamut` (chroma reduced, lightness/hue preserved) so the returned value is the closest sRGB representation, not a per-channel-clipped one that would distort hue. OKLCH output preserves the full color and matches the design system's token format. Returns null for unparseable input. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7e1f477 to
04fbf04
Compare
Summary
Exports a
formatColorutility from@raystack/apsarafor consumers that need any format from apsara's OKLCH-authored tokens — hex for chart libraries, rgb/hsl for legacy APIs, or normalizing arbitrary input back to the OKLCH design-system format.Contract
formatis'hex' | 'rgb' | 'hsl' | 'oklch'— same set the picker supportstoGamut— chroma reduced, lightness/hue preserved. No per-channel-clip hue distortion.rgba()/hsla()/oklch(... / A).nullfor unparseable input rather than throwing.Test plan
utils.test.tscovering all four formats + alpha + gamut-map + null fallbackpnpm test components/color-picker— 47/47 passingtsc --noEmitclean onraystackandapps/wwwbiome checkclean on touched filesdist/index.cjs— all four formats return expected values, no stalecolorToHexexportDocs added in the Utilities section of the Color Picker page.
🤖 Generated with Claude Code