Skip to content

Commit

Permalink
feat(color): update types, CSS formatting
Browse files Browse the repository at this point in the history
BREAKING CHANGE: remove obsolete resolveAsCss(), use css() instead

- update MaybeColor alias
- update TypedColor
- merge resolveAsCss() cases into css()
- fix color factory for int args
  • Loading branch information
postspectacular committed Jan 29, 2021
1 parent 9e1ed2e commit f0502a2
Show file tree
Hide file tree
Showing 19 changed files with 69 additions and 87 deletions.
33 changes: 23 additions & 10 deletions packages/color/src/api.ts
Expand Up @@ -5,7 +5,12 @@ import type { IVector, ReadonlyVec, Vec } from "@thi.ng/vectors";
export type Color = Vec;
export type ReadonlyColor = ReadonlyVec;

export type MaybeColor = string | number | ReadonlyColor | IColor;
export type MaybeColor =
| TypedColor<any>
| IParsedColor
| ReadonlyColor
| string
| number;

export type ColorOp = (out: Color | null, src: ReadonlyColor) => Color;

Expand Down Expand Up @@ -64,13 +69,8 @@ export interface ColorSpec<M extends ColorMode, K extends string> {
}

export interface ColorFactory<T extends TypedColor<any>> {
(
col: TypedColor<any> | ParsedColor | string | number,
buf?: Color,
idx?: number,
stride?: number
): T;
(col?: Color, idx?: number, stride?: number): T;
(col: MaybeColor, buf?: Vec, idx?: number, stride?: number): T;
(col?: Vec, idx?: number, stride?: number): T;
(a: number, b: number, c: number, ...xs: number[]): T;

/**
Expand Down Expand Up @@ -124,7 +124,14 @@ export interface TypedColor<T> extends IColor, IDeref<Color>, IVector<T> {
* Step size between channels
*/
stride: number;
random(rnd?: IRandom): this;
/**
* Randomizes all color channels based on channel ranges defined for this
* color type (usually [0..1] interval). Alpha channel will remain
* untouched.
*
* @param rnd
*/
randomize(rnd?: IRandom): this;
/**
* Copies `src` into this color's array.
*
Expand All @@ -138,7 +145,13 @@ export interface TypedColor<T> extends IColor, IDeref<Color>, IVector<T> {
toJSON(): number[];
}

export class ParsedColor implements IDeref<Color> {
export interface IParsedColor extends IColor, IDeref<Color> {}

/**
* Result type returned by {@link parseCss}, a simple wrapper for a raw color
* array and color mode.
*/
export class ParsedColor implements IParsedColor {
constructor(public readonly mode: ColorMode, public value: Color) {}

deref() {
Expand Down
15 changes: 13 additions & 2 deletions packages/color/src/css/css.ts
@@ -1,6 +1,6 @@
import type { Fn } from "@thi.ng/api";
import { isNumber, isString } from "@thi.ng/checks";
import type { ColorMode, TypedColor, ReadonlyColor } from "../api";
import type { ColorMode, IParsedColor, MaybeColor, TypedColor } from "../api";
import { convert } from "../convert";
import { hslCss } from "../hsl/hsl-css";
import { hsvCss } from "../hsv/hsv-css";
Expand All @@ -19,7 +19,18 @@ const CSS_CONVERSIONS: Partial<Record<ColorMode, Fn<any, string>>> = {
srgb: srgbCss,
};

export const css = (src: TypedColor<any> | ReadonlyColor | string | number) => {
/**
* Takes a color in one of the following formats and tries to convert it
* to a CSS string:
*
* - any {@link TypedColor} instance
* - raw sRGB(A) vector
* - number (packed 0xaarrggbb int, MUST provide alpha channel)
* - string (passthrough)
*
* @param col - source color
*/
export const css = (src: Exclude<MaybeColor, IParsedColor>) => {
if (isString(src)) return src;
if (isNumber(src)) return int32Css(src);
if ((<TypedColor<any>>src).mode) {
Expand Down
4 changes: 2 additions & 2 deletions packages/color/src/css/parse-css.ts
Expand Up @@ -3,7 +3,7 @@ import { assert } from "@thi.ng/api";
import { isString } from "@thi.ng/checks";
import { illegalArgs, unsupported } from "@thi.ng/errors";
import { clamp01, TAU } from "@thi.ng/math";
import { ParsedColor } from "../api";
import { IParsedColor, ParsedColor } from "../api";
import { CSS_NAMES } from "../api/names";
import { CSS_SYSTEM_COLORS } from "../api/system";
import { int32Srgb } from "../int/int-srgb";
Expand Down Expand Up @@ -43,7 +43,7 @@ import { ensureHue } from "../internal/ensure-hue";
*
* @param src
*/
export const parseCss = (src: string | IDeref<string>) => {
export const parseCss = (src: string | IDeref<string>): IParsedColor => {
src = (isString(src) ? src : src.deref()).toLowerCase();
const named = (<any>CSS_NAMES)[src] || (<any>CSS_SYSTEM_COLORS)[src];
if (named || src[0] === "#")
Expand Down
25 changes: 0 additions & 25 deletions packages/color/src/css/resolve.ts

This file was deleted.

43 changes: 14 additions & 29 deletions packages/color/src/defcolor.ts
@@ -1,4 +1,4 @@
import type { FloatArray, IDeref } from "@thi.ng/api";
import type { FloatArray } from "@thi.ng/api";
import {
implementsFunction,
isArrayLike,
Expand All @@ -11,23 +11,24 @@ import type { IRandom } from "@thi.ng/random";
import {
declareIndices,
eqDelta,
IVector,
mapStridedBuffer,
randMinMax,
set,
stridedValues,
} from "@thi.ng/vectors";
import type {
Color,
ColorFactory,
ColorMode,
ColorSpec,
IColor,
MaybeColor,
ReadonlyColor,
TypedColor,
} from "./api";
import { CONVERSIONS, convert } from "./convert";
import { parseCss } from "./css/parse-css";
import { int32Rgb } from "./int/int-rgba";
import { ensureArgs } from "./internal/ensure-args";
import { parseCss } from "./css/parse-css";

type $DefColor<M extends ColorMode, K extends string> = {
[k in K]: number;
Expand All @@ -36,9 +37,7 @@ type $DefColor<M extends ColorMode, K extends string> = {
random(rnd?: IRandom): $DefColor<M, K>;
set(src: ReadonlyColor): $DefColor<M, K>;
toJSON(): number[];
} & IColor &
IDeref<Color> &
IVector<$DefColor<M, K>>;
} & TypedColor<$DefColor<M, K>>;

export const defColor = <M extends ColorMode, K extends string>(
spec: ColorSpec<M, K>
Expand All @@ -50,8 +49,7 @@ export const defColor = <M extends ColorMode, K extends string>(
);
const max = spec.order.map((id) => (spec.channels[id].range || [0, 1])[1]);

const $clazz = class
implements IColor, IVector<$DefColor<any, any>>, IDeref<Color> {
const $clazz = class implements TypedColor<$DefColor<any, any>> {
buf: Color;
offset: number;
stride: number;
Expand Down Expand Up @@ -92,15 +90,12 @@ export const defColor = <M extends ColorMode, K extends string>(
return <any>new $clazz();
}

deref(): Color {
deref() {
return [this[0], this[1], this[2], this[3]];
}

set(src: ReadonlyColor) {
this[0] = src[0];
this[1] = src[1];
this[2] = src[2];
this[3] = src[3];
set(this, src);
return this;
}

Expand All @@ -112,9 +107,8 @@ export const defColor = <M extends ColorMode, K extends string>(
return this.deref();
}

random(rnd?: IRandom) {
randMinMax(this, min, max, rnd);
return this;
randomize(rnd?: IRandom): this {
return <any>randMinMax(this, min, max, rnd);
}
};
declareIndices($clazz.prototype, channels);
Expand All @@ -129,10 +123,7 @@ export const defColor = <M extends ColorMode, K extends string>(
return res;
};

const factory = (
src?: string | number | ReadonlyColor | IColor,
...xs: any[]
): $DefColor<any, any> => {
const factory = (src?: MaybeColor, ...xs: any[]): $DefColor<any, any> => {
if (src == null) return <any>new $clazz();
if (isString(src)) {
return factory(parseCss(src), ...xs);
Expand All @@ -152,9 +143,7 @@ export const defColor = <M extends ColorMode, K extends string>(
) {
return <any>new $clazz(...ensureArgs([src, ...xs]));
}
// FIXME disallow (since wrong for anything but rgb)
// or enforce mandatory `from` int conversion
return factory(<any>int32Rgb([], src), ...xs);
return <any>fromColor(int32Rgb([], src), "rgb", xs);
}
illegalArgs(`can't create a ${spec.mode} color from: ${src}`);
};
Expand All @@ -164,11 +153,7 @@ export const defColor = <M extends ColorMode, K extends string>(
buf?: Color,
idx?: number,
stride?: number
) => {
const res = new $clazz(buf, idx, stride);
randMinMax(res, min, max, rnd);
return <any>res;
};
) => <any>new $clazz(buf, idx, stride).randomize(rnd);

factory.mapBuffer = (
buf: FloatArray,
Expand Down
2 changes: 1 addition & 1 deletion packages/color/src/hcy/hcy.ts
Expand Up @@ -21,7 +21,7 @@ export declare class HCY implements TypedColor<HCY> {
deref(): Color;
empty(): HCY;
eqDelta(o: HCY, eps?: number): boolean;
random(rnd?: IRandom): this;
randomize(rnd?: IRandom): this;
set(src: ReadonlyColor): this;
toJSON(): number[];
}
Expand Down
2 changes: 1 addition & 1 deletion packages/color/src/hsi/hsi.ts
Expand Up @@ -21,7 +21,7 @@ export declare class HSI implements TypedColor<HSI> {
deref(): Color;
empty(): HSI;
eqDelta(o: HSI, eps?: number): boolean;
random(rnd?: IRandom): this;
randomize(rnd?: IRandom): this;
set(src: ReadonlyColor): this;
toJSON(): number[];
}
Expand Down
2 changes: 1 addition & 1 deletion packages/color/src/hsl/hsl.ts
Expand Up @@ -53,7 +53,7 @@ export declare class HSL implements TypedColor<HSL> {
deref(): Color;
empty(): HSL;
eqDelta(o: HSL, eps?: number): boolean;
random(rnd?: IRandom): this;
randomize(rnd?: IRandom): this;
set(src: ReadonlyColor): this;
toJSON(): number[];
}
Expand Down
2 changes: 1 addition & 1 deletion packages/color/src/hsv/hsv.ts
Expand Up @@ -53,7 +53,7 @@ export declare class HSV implements TypedColor<HSV> {
deref(): Color;
empty(): HSV;
eqDelta(o: HSV, eps?: number): boolean;
random(rnd?: IRandom): this;
randomize(rnd?: IRandom): this;
set(src: ReadonlyColor): this;
toJSON(): number[];
}
Expand Down
1 change: 0 additions & 1 deletion packages/color/src/index.ts
Expand Up @@ -9,7 +9,6 @@ export * from "./defcolor";

export * from "./css/css";
export * from "./css/parse-css";
export * from "./css/resolve";

export * from "./hcy/hcy-rgb";
export * from "./hcy/hcy";
Expand Down
2 changes: 1 addition & 1 deletion packages/color/src/lab/lab.ts
Expand Up @@ -23,7 +23,7 @@ export declare class Lab implements TypedColor<Lab> {
deref(): Color;
empty(): Lab;
eqDelta(o: Lab, eps?: number): boolean;
random(rnd?: IRandom): this;
randomize(rnd?: IRandom): this;
set(src: ReadonlyColor): this;
toJSON(): number[];
}
Expand Down
2 changes: 1 addition & 1 deletion packages/color/src/lch/lch.ts
Expand Up @@ -22,7 +22,7 @@ export declare class LCH implements TypedColor<LCH> {
deref(): Color;
empty(): LCH;
eqDelta(o: LCH, eps?: number): boolean;
random(rnd?: IRandom): this;
randomize(rnd?: IRandom): this;
set(src: ReadonlyColor): this;
toJSON(): number[];
}
Expand Down
2 changes: 1 addition & 1 deletion packages/color/src/oklab/oklab.ts
Expand Up @@ -22,7 +22,7 @@ export declare class Oklab implements TypedColor<Oklab> {
deref(): Color;
empty(): Oklab;
eqDelta(o: Oklab, eps?: number): boolean;
random(rnd?: IRandom): this;
randomize(rnd?: IRandom): this;
set(src: ReadonlyColor): this;
toJSON(): number[];
}
Expand Down
11 changes: 5 additions & 6 deletions packages/color/src/ops/luminance.ts
@@ -1,7 +1,7 @@
import { DEFAULT, defmulti, MultiFn1 } from "@thi.ng/defmulti";
import type { IColor, ReadonlyColor } from "../api";
import { luminanceRgb, luminanceSrgb } from "./luminance-rgb";
import type { MaybeColor } from "../api";
import { rgb } from "../rgb/rgb";
import { luminanceRgb, luminanceSrgb } from "./luminance-rgb";

/**
* Multi-method to compute relative luminance from any supported input color
Expand All @@ -13,10 +13,9 @@ import { rgb } from "../rgb/rgb";
* unless a direct implementation is available, colors will first be converted
* to linear RGB.
*/
export const luminance: MultiFn1<
number | string | ReadonlyColor | IColor,
number
> = defmulti((col: any) => col.mode);
export const luminance: MultiFn1<MaybeColor, number> = defmulti(
(col: any) => col.mode
);

luminance.addAll({
hcy: (x: any) => x[2],
Expand Down
2 changes: 1 addition & 1 deletion packages/color/src/rgb/rgb.ts
Expand Up @@ -29,7 +29,7 @@ export declare class RGB implements TypedColor<RGB> {
deref(): Color;
empty(): RGB;
eqDelta(o: RGB, eps?: number): boolean;
random(rnd?: IRandom): this;
randomize(rnd?: IRandom): this;
set(src: ReadonlyColor): this;
toJSON(): number[];
}
Expand Down
2 changes: 1 addition & 1 deletion packages/color/src/srgb/srgb.ts
Expand Up @@ -21,7 +21,7 @@ export declare class SRGB implements TypedColor<SRGB> {
deref(): Color;
empty(): SRGB;
eqDelta(o: SRGB, eps?: number): boolean;
random(rnd?: IRandom): this;
randomize(rnd?: IRandom): this;
set(src: ReadonlyColor): this;
toJSON(): number[];
}
Expand Down
2 changes: 1 addition & 1 deletion packages/color/src/xyy/xyy.ts
Expand Up @@ -22,7 +22,7 @@ export declare class XYY implements TypedColor<XYY> {
deref(): Color;
empty(): XYY;
eqDelta(o: XYY, eps?: number): boolean;
random(rnd?: IRandom): this;
randomize(rnd?: IRandom): this;
set(src: ReadonlyColor): this;
toJSON(): number[];
}
Expand Down
2 changes: 1 addition & 1 deletion packages/color/src/xyz/xyz.ts
Expand Up @@ -25,7 +25,7 @@ export declare class XYZ implements TypedColor<XYZ> {
deref(): Color;
empty(): XYZ;
eqDelta(o: XYZ, eps?: number): boolean;
random(rnd?: IRandom): this;
randomize(rnd?: IRandom): this;
set(src: ReadonlyColor): this;
toJSON(): number[];
}
Expand Down
2 changes: 1 addition & 1 deletion packages/color/src/ycc/ycc.ts
Expand Up @@ -21,7 +21,7 @@ export declare class YCC implements TypedColor<YCC> {
deref(): Color;
empty(): YCC;
eqDelta(o: YCC, eps?: number): boolean;
random(rnd?: IRandom): this;
randomize(rnd?: IRandom): this;
set(src: ReadonlyColor): this;
toJSON(): number[];
}
Expand Down

0 comments on commit f0502a2

Please sign in to comment.