Skip to content

Commit

Permalink
feat(color): add CSS Level4 oklab/oklch support
Browse files Browse the repository at this point in the history
- update parseCss() to support oklab/oklch colors
- add oklab/oklch CSS serializers
- update css() to optionally support CSS Color Module L4
- add CSS_LEVEL3 / CSS_LEVEL4 conversions
  • Loading branch information
postspectacular committed Mar 1, 2023
1 parent 3e77420 commit 137d322
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 12 deletions.
51 changes: 39 additions & 12 deletions packages/color/src/css/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,24 @@ import { hslCss } from "../hsl/hsl-css.js";
import { hsvCss } from "../hsv/hsv-css.js";
import { intArgb32Css } from "../int/int-css.js";
import { intAbgr32Argb32 } from "../int/int-int.js";
import { labCss } from "../lab/lab-css.js";
import { labLabD65_50 } from "../lab/lab-lab.js";
import { lchLab } from "../lab/lab-lch.js";
import { labRgb, labRgbD65 } from "../lab/lab-rgb.js";
import { lchCss } from "../lch/lch-css.js";
import { oklabCss } from "../oklab/oklab-css.js";
import { oklchCss } from "../oklch/oklch-css.js";
import { rgbCss } from "../rgb/rgb-css.js";
import { rgbSrgb } from "../rgb/rgb-srgb.js";
import { srgbCss } from "../srgb/srgb-css.js";

/** @internal */
const CSS_CONVERSIONS: Partial<Record<ColorMode, Fn<any, string>>> = {
export type CSSConversions = Partial<Record<ColorMode, Fn<any, string>>>;

export const CSS_LEVEL3: CSSConversions = {
abgr32: (x) => intArgb32Css(intAbgr32Argb32(x[0])),
argb32: (x) => intArgb32Css(x[0]),
hsl: hslCss,
hsv: hsvCss,
// TODO temporarily disabled until CSS L4 is officially supported in browsers
// currently serializing as sRGB CSS
// lab50: labCss,
// lab65: (x) => labCss(labLabD65_50([], x)),
// lch: lchCss,
lab50: (src) => srgbCss(rgbSrgb(null, labRgb([], src))),
lab65: (src) => srgbCss(rgbSrgb(null, labRgbD65([], src))),
lch: (src) => srgbCss(rgbSrgb(null, labRgb(null, lchLab([], src)))),
Expand All @@ -37,26 +38,52 @@ const CSS_CONVERSIONS: Partial<Record<ColorMode, Fn<any, string>>> = {
};

/**
* Takes a color in one of the following formats and tries to convert it
* to a CSS string:
* Extended set of direct CSS conversions for use with CSS Color Module Level 4.
* Based on {@link CSS_LEVEL3}.
*/
export const CSS_LEVEL4: CSSConversions = {
...CSS_LEVEL3,
lab50: labCss,
lab65: (x) => labCss(labLabD65_50([], x)),
lch: lchCss,
oklab: oklabCss,
oklch: oklchCss,
};

/**
* Takes a color in one of the following formats and tries to convert it to a
* CSS string.
*
* @remarks
* The following input formats are supported:
*
* - any {@link TypedColor} instance
* - raw sRGB(A) vector
* - number (packed 0xaarrggbb int, MUST provide alpha channel)
* - string (passthrough)
*
* If CSS Color Module Level 4 support is desired, pass {@link CSS_LEVEL4} as
* 2nd argument.
*
* If no direct conversion route for a given source color mode exists, the color
* will be first converted to sRGB and serialized as such.
*
* @param col - source color
* @param cssTarget - CSS conversions
*/
export const css = (src: Exclude<MaybeColor, IParsedColor>) => {
export const css = (
src: Exclude<MaybeColor, IParsedColor>,
cssTarget: CSSConversions = CSS_LEVEL3
) => {
let asCss: Fn<any, string> | undefined;
return isString(src)
? src
: isNumber(src)
? intArgb32Css(src)
: (<TypedColor<any>>src).mode
? (asCss = CSS_CONVERSIONS[(<TypedColor<any>>src).mode])
? (asCss = cssTarget[(<TypedColor<any>>src).mode])
? asCss(src)
: CSS_CONVERSIONS.rgb!(
: cssTarget.rgb!(
convert([], src, "rgb", (<TypedColor<any>>src).mode)
)
: srgbCss(src);
Expand Down
16 changes: 16 additions & 0 deletions packages/color/src/css/parse-css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import { intArgb32Srgb } from "../int/int-srgb.js";
* - `hsla(h,s%,l%,a)`
* - `lab(l a b / alpha?)`
* - `lch(l c h / alpha?)`
* - `oklab(l a b / alpha?)`
* - `oklch(l c h / alpha?)`
*
* Hue values can be given according to CSS Color L4 spec (raw, deg, rad, grad,
* turn): https://www.w3.org/TR/css-color-4/#typedef-hue
Expand Down Expand Up @@ -92,6 +94,20 @@ export const parseCss = (src: string | IDeref<string>): IParsedColor => {
parseHue(c),
parseAlpha(d),
]);
case "oklab":
return new ParsedColor("oklab", [
parsePercent(a, false),
parseNumber(b) * 0.01,
parseNumber(c) * 0.01,
parseAlpha(d),
]);
case "oklch":
return new ParsedColor("oklch", [
parsePercent(a, false),
parseNumber(b) * 0.01,
parseHue(c),
parseAlpha(d),
]);
default:
unsupported(`color mode: ${mode}`);
}
Expand Down
1 change: 1 addition & 0 deletions packages/color/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export * from "./lab/lab65.js";
export * from "./lch/lch-css.js";
export * from "./lch/lch.js";

export * from "./oklab/oklab-css.js";
export * from "./oklab/oklab-rgb.js";
export * from "./oklab/oklab-xyz.js";
export * from "./oklab/oklab.js";
Expand Down
12 changes: 12 additions & 0 deletions packages/color/src/oklab/oklab-css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { ReadonlyColor } from "../api.js";
import { labCss } from "../lab/lab-css.js";

/**
* @remarks
* Only supported in CSS Color Level 4 onwards
* - https://www.w3.org/TR/css-color-4/#specifying-oklab-oklch
* - https://test.csswg.org/harness/results/css-color-4_dev/grouped/ (test reports)
*
* @param src -
*/
export const oklabCss = (src: ReadonlyColor) => "ok" + labCss(src);

0 comments on commit 137d322

Please sign in to comment.