Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,35 @@ describe('convert', () => {
}
})

// All of these are equivalent to `red` (#ff0000)
const wide_gamut_colors = [
'lab(54.2905414047 80.8049283205 69.8909647686)',
'lch(54.2905414047 106.8371817167 40.8576564524)',
'hwb(0 0% 0%)',
'color(display-p3 0.9174875573 0.2002868079 0.1385605911)',
'color(a98-rgb 0.8585916023 0 0)',
'color(prophoto-rgb 0.7022480752 0.275720531 0.1035476647)',
'color(rec2020 0.7919771358 0.2309756849 0.0737614751)',
]
test.each(wide_gamut_colors)(
'the convert fn parses wide-gamut and CIE color spaces: %s',
(color) => {
let converted = convert(color)
let hue_distance = Math.min(converted.hue, 360 - converted.hue)
expect(hue_distance, `Failed hue for '${color}', got ${converted.hue}`).toBeLessThan(0.01)
expect(
converted.saturation,
`Failed saturation for '${color}', got ${converted.saturation}`,
).toBeGreaterThan(99.9)
expect(
converted.lightness,
`Failed lightness for '${color}', got ${converted.lightness}`,
).toBeCloseTo(50, 1)
expect(converted.alpha).toBe(1)
expect(converted.authored).toBe(color)
},
)

const invalid_colors = ['hsl(0, 0, 0)', 'rgb(0 0 0 1)', 'rgb(a, b, c, 1)']
test.each(invalid_colors)(`invalid colors return a default object: %s`, (color) => {
expect(convert(color)).toEqual({
Expand Down
92 changes: 27 additions & 65 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,23 @@
import {
tryColor,
ColorSpace,
XYZ_D65,
XYZ_D50,
XYZ_ABS_D65,
Lab_D65,
Lab,
LCH,
sRGB_Linear,
sRGB,
HSL,
HWB,
HSV,
P3_Linear,
P3,
A98RGB_Linear,
A98RGB,
ProPhoto_Linear,
ProPhoto,
REC_2020_Linear,
REC_2020,
OKLab,
OKLCH,
OKLrab,
to as convertColor,
} from 'colorjs.io/fn'

// Register color spaces for parsing and converting
// TODO: According to the changelog we should be able to import
// and register all spaces in one go but it doesn't seem to work
ColorSpace.register(sRGB) // Parses keywords and hex colors
ColorSpace.register(XYZ_D65)
ColorSpace.register(XYZ_D50)
ColorSpace.register(XYZ_ABS_D65)
ColorSpace.register(Lab_D65)
ColorSpace.register(Lab)
ColorSpace.register(LCH)
ColorSpace.register(sRGB_Linear)
ColorSpace.register(HSL)
ColorSpace.register(HWB)
ColorSpace.register(HSV)
ColorSpace.register(P3_Linear)
ColorSpace.register(P3)
ColorSpace.register(A98RGB_Linear)
ColorSpace.register(A98RGB)
ColorSpace.register(ProPhoto_Linear)
ColorSpace.register(ProPhoto)
ColorSpace.register(REC_2020_Linear)
ColorSpace.register(REC_2020)
ColorSpace.register(OKLab)
ColorSpace.register(OKLCH)
ColorSpace.register(OKLrab)
import { colordx, extend } from '@colordx/core'
import lab from '@colordx/core/plugins/lab'
import lch from '@colordx/core/plugins/lch'
import hwb from '@colordx/core/plugins/hwb'
import hsv from '@colordx/core/plugins/hsv'
import p3 from '@colordx/core/plugins/p3'
import rec2020 from '@colordx/core/plugins/rec2020'
import a98rgb from '@colordx/core/plugins/a98rgb'
import prophoto from '@colordx/core/plugins/prophoto'
import names from '@colordx/core/plugins/names'

// Register color spaces for parsing and converting.
// Not registered: `color(srgb ...)` / `color(srgb-linear ...)` function
// syntax, which @colordx/core doesn't support yet (colordx.dev roadmap).
extend([lab, lch, hwb, hsv, p3, rec2020, a98rgb, prophoto, names])

// High enough to preserve near-full float precision, since `compare()`
// relies on tiny lightness differences to break ties before falling
// back to alphabetical sorting.
const HSL_PRECISION = 15

export type NormalizedColor = {
hue: number
Expand All @@ -75,9 +42,9 @@ function numerify(value: number | null | undefined): number {
* @example convert('red')
*/
export function convert(authored: string): NormalizedColorWithAuthored {
let parsed = tryColor(authored)
let color = colordx(authored)

if (parsed === null) {
if (!color.isValid()) {
return {
hue: 0,
saturation: 0,
Expand All @@ -87,18 +54,13 @@ export function convert(authored: string): NormalizedColorWithAuthored {
}
}

let converted = parsed.space.id === 'hsl' ? parsed : convertColor(parsed, HSL)
let hsl = converted.coords
let hue = numerify(hsl[0])
let saturation = numerify(hsl[1])
let lightness = numerify(hsl[2])
let alpha = numerify(converted.alpha)
let hsl = color.toHsl(HSL_PRECISION)

return {
hue,
saturation,
lightness,
alpha,
hue: numerify(hsl.h),
saturation: numerify(hsl.s),
lightness: numerify(hsl.l),
alpha: numerify(hsl.alpha),
authored,
}
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"format": "oxfmt"
},
"dependencies": {
"colorjs.io": "~0.7.1"
"@colordx/core": "^5.5.0"
},
"devDependencies": {
"@vitest/coverage-v8": "^4.1.10",
Expand Down
16 changes: 8 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.