From 343e3b437ef08ec2702158f65fa4ae531710143e Mon Sep 17 00:00:00 2001 From: Lloyd Kupchanko Date: Mon, 26 Feb 2024 12:43:19 -0700 Subject: [PATCH 1/8] Audit function parameter and return types (1/2) Ensure that functions in the following modules have the correct types and ensure that all color types can be passed as parameters: - chromaticity - distance - get - getAll --- src/chromaticity.js | 2 ++ src/distance.js | 3 +++ src/get.js | 3 +++ src/getAll.js | 3 +++ types/src/chromaticity.d.ts | 6 +++--- types/src/distance.d.ts | 6 +++--- types/src/get.d.ts | 4 ++-- types/src/getAll.d.ts | 6 +++--- types/test/chromaticity.ts | 9 +++++---- types/test/distance.ts | 3 +++ types/test/get.ts | 3 +++ types/test/getAll.ts | 9 ++++++--- 12 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/chromaticity.js b/src/chromaticity.js index 752fe5fdd..f93547579 100644 --- a/src/chromaticity.js +++ b/src/chromaticity.js @@ -3,12 +3,14 @@ import getAll from "./getAll.js"; // Chromaticity coordinates export function uv (color) { + // Assumes getAll() calls getColor() on color let [X, Y, Z] = getAll(color, xyz_d65); let denom = X + 15 * Y + 3 * Z; return [4 * X / denom, 9 * Y / denom]; } export function xy (color) { + // Assumes getAll() calls getColor() on color let [X, Y, Z] = getAll(color, xyz_d65); let sum = X + Y + Z; return [X / sum, Y / sum]; diff --git a/src/distance.js b/src/distance.js index d41459504..6f8c92653 100644 --- a/src/distance.js +++ b/src/distance.js @@ -1,9 +1,12 @@ import ColorSpace from "./space.js"; +import getColor from "./getColor.js"; /** * Euclidean distance of colors in an arbitrary color space */ export default function distance (color1, color2, space = "lab") { + [color1, color2] = getColor([color1, color2]); + space = ColorSpace.get(space); let coords1 = space.from(color1); diff --git a/src/get.js b/src/get.js index ee72bb787..59e1184b9 100644 --- a/src/get.js +++ b/src/get.js @@ -1,7 +1,10 @@ import ColorSpace from "./space.js"; import getAll from "./getAll.js"; +import getColor from "./getColor.js"; export default function get (color, prop) { + color = getColor(color); + let {space, index} = ColorSpace.resolveCoord(prop, color.space); let coords = getAll(color, space); return coords[index]; diff --git a/src/getAll.js b/src/getAll.js index c9d15e15c..05a803c86 100644 --- a/src/getAll.js +++ b/src/getAll.js @@ -1,4 +1,5 @@ import ColorSpace from "./space.js"; +import getColor from "./getColor.js"; /** * Get the coordinates of a color in any color space @@ -7,6 +8,8 @@ import ColorSpace from "./space.js"; * @returns {number[]} The color coordinates in the given color space */ export default function getAll (color, space) { + color = getColor(color); + if (!space || color.space.equals(space)) { // No conversion needed return color.coords.slice(); diff --git a/types/src/chromaticity.d.ts b/types/src/chromaticity.d.ts index 2d79bfeef..17f40c2da 100644 --- a/types/src/chromaticity.d.ts +++ b/types/src/chromaticity.d.ts @@ -1,7 +1,7 @@ -import Color, { ColorObject } from "./color.js"; +import Color, { ColorTypes } from "./color.js"; -export function uv (color: Color | ColorObject): [number, number]; +export function uv (color: ColorTypes): [number, number]; -export function xy (color: Color | ColorObject): [number, number]; +export function xy (color: ColorTypes): [number, number]; export function register (color: typeof Color): void; diff --git a/types/src/distance.d.ts b/types/src/distance.d.ts index 5684be876..60a368afe 100644 --- a/types/src/distance.d.ts +++ b/types/src/distance.d.ts @@ -1,8 +1,8 @@ -import Color, { ColorObject } from "./color.js"; +import { ColorTypes } from "./color.js"; import ColorSpace from "./space.js"; export default function distance ( - color1: Color | ColorObject, - color2: Color | ColorObject, + color1: ColorTypes, + color2: ColorTypes, space?: string | ColorSpace ): number; diff --git a/types/src/get.d.ts b/types/src/get.d.ts index b2eca227c..1ee99d55e 100644 --- a/types/src/get.d.ts +++ b/types/src/get.d.ts @@ -1,4 +1,4 @@ -import Color, { ColorObject } from "./color.js"; +import { ColorTypes } from "./color.js"; import { Ref } from "./space.js"; -export default function get (color: Color | ColorObject, prop: Ref): number; +export default function get (color: ColorTypes, prop: Ref): number; diff --git a/types/src/getAll.d.ts b/types/src/getAll.d.ts index 0ac081906..48c6a1b68 100644 --- a/types/src/getAll.d.ts +++ b/types/src/getAll.d.ts @@ -1,7 +1,7 @@ -import Color, { ColorObject } from "./color.js"; +import { ColorTypes, Coords } from "./color.js"; import ColorSpace from "./space.js"; export default function getAll ( - color: Color | ColorObject, + color: ColorTypes, space?: string | ColorSpace -): [number, number, number]; +): Coords; diff --git a/types/test/chromaticity.ts b/types/test/chromaticity.ts index dfd64e044..50447f96c 100644 --- a/types/test/chromaticity.ts +++ b/types/test/chromaticity.ts @@ -3,17 +3,18 @@ import { uv, xy, register } from "colorjs.io/src/chromaticity"; // @ts-expect-error uv(); -// @ts-expect-error -uv("red"); +uv("red"); // $ExpectType [number, number] uv(new Color("red")); // $ExpectType [number, number] +new Color("red").uv(); // $ExpectType [number, number] // @ts-expect-error xy(); -// @ts-expect-error -xy("red"); +xy("red"); // $ExpectType [number, number] xy(new Color("red")); // $ExpectType [number, number] +new Color("red").xy(); // $ExpectType [number, number] + // @ts-expect-error register(); diff --git a/types/test/distance.ts b/types/test/distance.ts index 04fabaa2f..7ec7dba85 100644 --- a/types/test/distance.ts +++ b/types/test/distance.ts @@ -13,3 +13,6 @@ distance(c1); distance(c1, c2); // $ExpectType number distance(c1, c2, space); // $ExpectType number distance(c1, c2, "srgb"); // $ExpectType number +distance("red", "blue"); // $ExpectType number + +c1.distance(c2); // $ExpectType number diff --git a/types/test/get.ts b/types/test/get.ts index 89cc8ce4c..609fbe5b9 100644 --- a/types/test/get.ts +++ b/types/test/get.ts @@ -9,3 +9,6 @@ get(new Color("red")); get(new Color("red"), "p3.r"); // $ExpectType number get(new Color("red"), ["p3", "r"]); // $ExpectType number get(new Color("red"), { space: "p3", coordId: "r" }); // $ExpectType number +get("red", "p3.r"); // $ExpectType number + +new Color("red").get("p3.r"); // $ExpectType number diff --git a/types/test/getAll.ts b/types/test/getAll.ts index 6fce16a2d..86386c7e9 100644 --- a/types/test/getAll.ts +++ b/types/test/getAll.ts @@ -5,6 +5,9 @@ import sRGB from "colorjs.io/src/spaces/srgb"; // @ts-expect-error getAll(); -getAll(new Color("red")); // $ExpectType [number, number, number] -getAll(new Color("red"), "srgb"); // $ExpectType [number, number, number] -getAll(new Color("red"), sRGB); // $ExpectType [number, number, number] +getAll(new Color("red")); // $ExpectType Coords +getAll(new Color("red"), "srgb"); // $ExpectType Coords +getAll(new Color("red"), sRGB); // $ExpectType Coords +getAll("red", sRGB); // $ExpectType Coords + +new Color("red").getAll(); // $ExpectType Coords From bd5ede07435ce3c3ba2d1e822ee6b5bf5df02ef5 Mon Sep 17 00:00:00 2001 From: Lloyd Kupchanko Date: Mon, 26 Feb 2024 17:48:00 -0700 Subject: [PATCH 2/8] Audit function parameter and return types (2/2) Ensure that functions in the following modules have the correct types and ensure that all color types can be passed as parameters: - inGamut - luminance - set - setAll - space - toGamut --- src/inGamut.js | 7 ++++++- src/luminance.js | 2 ++ src/setAll.js | 3 +++ src/toGamut.js | 18 +++++++++++++++--- types/src/luminance.d.ts | 6 +++--- types/src/set.d.ts | 6 +++--- types/src/setAll.d.ts | 14 ++++++++++---- types/src/space.d.ts | 6 +++--- types/test/luminance.ts | 8 ++++++-- types/test/set.ts | 10 ++++++---- types/test/setAll.ts | 9 ++++++--- types/test/spaces.ts | 14 ++++++++++++++ types/test/toGamut.ts | 6 ++++++ 13 files changed, 83 insertions(+), 26 deletions(-) diff --git a/src/inGamut.js b/src/inGamut.js index 94b46d04f..417ac622a 100644 --- a/src/inGamut.js +++ b/src/inGamut.js @@ -7,8 +7,13 @@ const ε = .000075; * Check if a color is in gamut of either its own or another color space * @return {Boolean} Is the color in gamut? */ -export default function inGamut (color, space = color.space, {epsilon = ε} = {}) { +export default function inGamut (color, space, {epsilon = ε} = {}) { color = getColor(color); + + if (!space) { + space = color.space; + } + space = ColorSpace.get(space); let coords = color.coords; diff --git a/src/luminance.js b/src/luminance.js index 57133d988..81d2655fe 100644 --- a/src/luminance.js +++ b/src/luminance.js @@ -6,10 +6,12 @@ import set from "./set.js"; import xyz_d65 from "./spaces/xyz-d65.js"; export function getLuminance (color) { + // Assume getColor() is called on color in get() return get(color, [xyz_d65, "y"]); } export function setLuminance (color, value) { + // Assume getColor() is called on color in set() set(color, [xyz_d65, "y"], value); } diff --git a/src/setAll.js b/src/setAll.js index d3155faae..ac56a2da9 100644 --- a/src/setAll.js +++ b/src/setAll.js @@ -1,6 +1,9 @@ import ColorSpace from "./space.js"; +import getColor from "./getColor.js"; export default function setAll (color, space, coords) { + color = getColor(color); + space = ColorSpace.get(space); color.coords = space.to(color.space, coords); return color; diff --git a/src/toGamut.js b/src/toGamut.js index d2ee43da8..c0961f23e 100644 --- a/src/toGamut.js +++ b/src/toGamut.js @@ -65,15 +65,20 @@ export default function toGamut ( color, { method = defaults.gamut_mapping, - space = color.space, + space = undefined, deltaEMethod = "", jnd = 2, blackWhiteClamp = {}, } = {}, ) { + color = getColor(color); + if (util.isString(arguments[1])) { space = arguments[1]; } + else if (!space) { + space = color.space; + } space = ColorSpace.get(space); @@ -83,7 +88,7 @@ export default function toGamut ( // mapSpace: space with the coord we're reducing if (inGamut(color, space, { epsilon: 0 })) { - return getColor(color); + return color; } let spaceColor; @@ -219,9 +224,16 @@ const COLORS = { * @param {ColorSpace|string} options.space * @returns {Color} */ -export function toGamutCSS (origin, { space = origin.space }) { +export function toGamutCSS (origin, {space} = {}) { const JND = 0.02; const ε = 0.0001; + + origin = getColor(origin); + + if (!space) { + space = origin.space; + } + space = ColorSpace.get(space); const oklchSpace = ColorSpace.get("oklch"); diff --git a/types/src/luminance.d.ts b/types/src/luminance.d.ts index 5a1b9fac4..da8cd9d9f 100644 --- a/types/src/luminance.d.ts +++ b/types/src/luminance.d.ts @@ -1,9 +1,9 @@ -import Color, { ColorObject } from "./color.js"; +import Color, { ColorTypes } from "./color.js"; -export function getLuminance (color: Color | ColorObject): number; +export function getLuminance (color: ColorTypes): number; export function setLuminance ( - color: Color | ColorObject, + color: ColorTypes, value: number | ((coord: number) => number), ): void; diff --git a/types/src/set.d.ts b/types/src/set.d.ts index 08955fc61..2f9665bff 100644 --- a/types/src/set.d.ts +++ b/types/src/set.d.ts @@ -1,12 +1,12 @@ -import Color, { ColorTypes } from "./color.js"; +import { ColorTypes, PlainColorObject } from "./color.js"; import { Ref } from "./space.js"; export default function set ( color: ColorTypes, prop: Ref, value: number | ((coord: number) => number) -): Color; +): PlainColorObject; export default function set ( color: ColorTypes, props: Record number)> -): Color; +): PlainColorObject; diff --git a/types/src/setAll.d.ts b/types/src/setAll.d.ts index db46e384e..ba2fce3c7 100644 --- a/types/src/setAll.d.ts +++ b/types/src/setAll.d.ts @@ -1,8 +1,14 @@ -import Color, { ColorObject } from "./color.js"; +import Color, { ColorTypes, PlainColorObject } from "./color.js"; import ColorSpace from "./space.js"; -export default function setAll ( - color: T, +declare namespace setAll { + let returns: "color"; +} + +declare function setAll ( + color: ColorTypes, space: string | ColorSpace, coords: [number, number, number] -): T; +): PlainColorObject; + +export default setAll; diff --git a/types/src/space.d.ts b/types/src/space.d.ts index 03312ca16..9e8f01442 100644 --- a/types/src/space.d.ts +++ b/types/src/space.d.ts @@ -1,5 +1,5 @@ import { White } from "./adapt.js"; -import Color, { ColorConstructor, ColorObject, Coords } from "./color.js"; +import Color, { ColorConstructor, ColorObject, Coords, PlainColorObject } from "./color.js"; export interface Format { /** @default "function" */ @@ -127,7 +127,7 @@ export default class ColorSpace { white: White; gamutSpace: ColorSpace; - from (color: Color | ColorObject): Coords; + from (color: {space: ColorSpace, coords: Coords, alpha?: number | undefined}): Coords; from (space: string | ColorSpace, coords: Coords): Coords; getFormat (format?: string | Format): Format | null; @@ -136,7 +136,7 @@ export default class ColorSpace { inGamut (coords: Coords, options?: { epsilon?: number }): boolean; - to (color: Color | ColorObject): Coords; + to (color: {space: ColorSpace, coords: Coords, alpha?: number | undefined}): Coords; to (space: string | ColorSpace, coords: Coords): Coords; toString (): string; diff --git a/types/test/luminance.ts b/types/test/luminance.ts index 3fedf9e67..523c04a1c 100644 --- a/types/test/luminance.ts +++ b/types/test/luminance.ts @@ -3,10 +3,11 @@ import { getLuminance, setLuminance, register } from "colorjs.io/src/luminance"; // @ts-expect-error getLuminance(); -// @ts-expect-error -getLuminance("red"); +getLuminance("red"); // $ExpectType number getLuminance(new Color("red")); // $ExpectType number +new Color("red").luminance; // $ExpectType number + // @ts-expect-error setLuminance(); @@ -15,8 +16,11 @@ setLuminance("red"); // @ts-expect-error setLuminance(new Color("red")); + setLuminance(new Color("red"), 1); setLuminance(new Color("red"), () => 1); +setLuminance("red", 1); +new Color("red").luminance = 1; // @ts-expect-error register(); diff --git a/types/test/set.ts b/types/test/set.ts index 61c2c06b6..2a84f4ca4 100644 --- a/types/test/set.ts +++ b/types/test/set.ts @@ -7,12 +7,14 @@ set(); // @ts-expect-error set("red"); -set("red", "foo", 123); // $ExpectType Color -set(new Color("red"), ["srgb", "bar"], (_: number) => 123); // $ExpectType Color -set(new Color("red"), [sRGB, "bar"], (_: number) => 123); // $ExpectType Color +set("red", "foo", 123); // $ExpectType PlainColorObject +set(new Color("red"), ["srgb", "bar"], (_: number) => 123); // $ExpectType PlainColorObject +set(new Color("red"), [sRGB, "bar"], (_: number) => 123); // $ExpectType PlainColorObject -// $ExpectType Color +// $ExpectType PlainColorObject set("red", { foo: 123, bar: (_: number) => 123, }); + +new Color("red").set("foo", 123); // $ExpectType Color diff --git a/types/test/setAll.ts b/types/test/setAll.ts index f6668f98f..f3d5719dd 100644 --- a/types/test/setAll.ts +++ b/types/test/setAll.ts @@ -11,9 +11,9 @@ setAll(new Color("red"), "srgb"); // @ts-expect-error setAll(new Color("red"), sRGB); -setAll(new Color("red"), "srgb", [1, 2, 3]); // $ExpectType Color -setAll(new Color("red"), sRGB, [1, 2, 3]); // $ExpectType Color -// $ExpectType { coords: [number, number, number]; space: RGBColorSpace; alpha: number; } +setAll(new Color("red"), "srgb", [1, 2, 3]); // $ExpectType PlainColorObject +setAll(new Color("red"), sRGB, [1, 2, 3]); // $ExpectType PlainColorObject +// $ExpectType PlainColorObject setAll( { coords: [1, 2, 3], @@ -23,3 +23,6 @@ setAll( "srgb_linear", [4, 5, 6], ); + +new Color("red").setAll("srgb", [1, 2, 3]); // $ExpectType Color +new Color("red").setAll(sRGB, [1, 2, 3]); // $ExpectType Color diff --git a/types/test/spaces.ts b/types/test/spaces.ts index ee25b34ff..86fa8fd84 100644 --- a/types/test/spaces.ts +++ b/types/test/spaces.ts @@ -1,3 +1,4 @@ +import Color from "colorjs.io/src"; import ColorSpace from "colorjs.io/src/space"; // @ts-expect-error @@ -47,3 +48,16 @@ ColorSpace.registry["abc"]; // $ExpectType ColorSpace ColorSpace.resolveCoord("p3.0", "p3"); ColorSpace.resolveCoord(["p3", "r"], "p3"); + +space.to(new Color("red")); // $ExpectType Coords +space.to({space: space, coords: [1, 2, 3], alpha: 1}); // $ExpectType Coords +space.to({space: space, coords: [1, 2, 3]}); // $ExpectType Coords +space.to(space, [1, 2, 3]); // $ExpectType Coords +space.to("srgb", [1, 2, 3]); // $ExpectType Coords + +space.from(new Color("red")); // $ExpectType Coords +space.from({space: space, coords: [1, 2, 3], alpha: 1}); // $ExpectType Coords +space.from({space: space, coords: [1, 2, 3]}); // $ExpectType Coords +space.from(space, [1, 2, 3]); // $ExpectType Coords +space.from("srgb", [1, 2, 3]); // $ExpectType Coords + diff --git a/types/test/toGamut.ts b/types/test/toGamut.ts index d9f97fb92..4bb02c16f 100644 --- a/types/test/toGamut.ts +++ b/types/test/toGamut.ts @@ -11,3 +11,9 @@ toGamut(new Color("red")); // $ExpectType PlainColorObject toGamut(new Color("red"), { method: "clip", space: "srgb" }); // $ExpectType PlainColorObject toGamut(new Color("red"), { method: "clip", space: sRGB }); // $ExpectType PlainColorObject toGamut(new Color("red"), "srgb"); // $ExpectType PlainColorObject + + +new Color("red").toGamut(); // $ExpectType Color +new Color("red").toGamut({ method: "clip", space: "srgb" }); // $ExpectType Color +new Color("red").toGamut({ method: "clip", space: sRGB }); // $ExpectType Color +new Color("red").toGamut("srgb"); // $ExpectType Color From 69d62dbdc963591ac5308536ed7378ba2b3409b2 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Wed, 28 Feb 2024 10:57:55 -0500 Subject: [PATCH 3/8] All Color methods return a Color object; use getColor on remaining fns --- src/get.js | 3 +++ src/getAll.js | 3 +++ src/set.js | 2 ++ src/setAll.js | 2 ++ src/space.js | 7 +++++-- types/src/chromaticity.d.ts | 6 +++--- types/src/color.d.ts | 34 +++++++++++++++++++++++----------- types/src/distance.d.ts | 6 +++--- types/src/get.d.ts | 4 ++-- types/src/getAll.d.ts | 4 ++-- types/src/set.d.ts | 10 ++++++++-- types/src/setAll.d.ts | 2 +- types/src/space.d.ts | 6 +++--- types/test/chromaticity.ts | 6 ++---- types/test/distance.ts | 1 + types/test/get.ts | 1 + types/test/getAll.ts | 1 + types/test/set.ts | 3 +++ types/test/setAll.ts | 3 +++ types/test/spaces.ts | 3 ++- types/test/toGamut.ts | 3 +++ 21 files changed, 76 insertions(+), 34 deletions(-) diff --git a/src/get.js b/src/get.js index ee72bb787..59e1184b9 100644 --- a/src/get.js +++ b/src/get.js @@ -1,7 +1,10 @@ import ColorSpace from "./space.js"; import getAll from "./getAll.js"; +import getColor from "./getColor.js"; export default function get (color, prop) { + color = getColor(color); + let {space, index} = ColorSpace.resolveCoord(prop, color.space); let coords = getAll(color, space); return coords[index]; diff --git a/src/getAll.js b/src/getAll.js index c9d15e15c..05a803c86 100644 --- a/src/getAll.js +++ b/src/getAll.js @@ -1,4 +1,5 @@ import ColorSpace from "./space.js"; +import getColor from "./getColor.js"; /** * Get the coordinates of a color in any color space @@ -7,6 +8,8 @@ import ColorSpace from "./space.js"; * @returns {number[]} The color coordinates in the given color space */ export default function getAll (color, space) { + color = getColor(color); + if (!space || color.space.equals(space)) { // No conversion needed return color.coords.slice(); diff --git a/src/set.js b/src/set.js index 17fc3682d..1463b8462 100644 --- a/src/set.js +++ b/src/set.js @@ -29,3 +29,5 @@ export default function set (color, prop, value) { return color; } + +set.returns = "color"; diff --git a/src/setAll.js b/src/setAll.js index ac56a2da9..54afeeba1 100644 --- a/src/setAll.js +++ b/src/setAll.js @@ -8,3 +8,5 @@ export default function setAll (color, space, coords) { color.coords = space.to(color.space, coords); return color; } + +setAll.returns = "color"; diff --git a/src/space.js b/src/space.js index dccf1a73f..9f32602bb 100644 --- a/src/space.js +++ b/src/space.js @@ -1,6 +1,7 @@ import {type, parseCoordGrammar, serializeNumber, mapRange} from "./util.js"; import {getWhite} from "./adapt.js"; import hooks from "./hooks.js"; +import getColor from "./getColor.js"; const ε = .000075; @@ -173,7 +174,8 @@ export default class ColorSpace { to (space, coords) { if (arguments.length === 1) { - [space, coords] = [space.space, space.coords]; + const color = getColor(space); + [space, coords] = [color.space, color.coords]; } space = ColorSpace.get(space); @@ -222,7 +224,8 @@ export default class ColorSpace { from (space, coords) { if (arguments.length === 1) { - [space, coords] = [space.space, space.coords]; + const color = getColor(space); + [space, coords] = [color.space, color.coords]; } space = ColorSpace.get(space); diff --git a/types/src/chromaticity.d.ts b/types/src/chromaticity.d.ts index 2d79bfeef..17f40c2da 100644 --- a/types/src/chromaticity.d.ts +++ b/types/src/chromaticity.d.ts @@ -1,7 +1,7 @@ -import Color, { ColorObject } from "./color.js"; +import Color, { ColorTypes } from "./color.js"; -export function uv (color: Color | ColorObject): [number, number]; +export function uv (color: ColorTypes): [number, number]; -export function xy (color: Color | ColorObject): [number, number]; +export function xy (color: ColorTypes): [number, number]; export function register (color: typeof Color): void; diff --git a/types/src/color.d.ts b/types/src/color.d.ts index 0477ddaff..6bc178df0 100644 --- a/types/src/color.d.ts +++ b/types/src/color.d.ts @@ -6,17 +6,16 @@ import ColorSpace, { Ref } from "./space.js"; import SpaceAccessors from "./space-coord-accessors.js"; import { - to, + to as toType, parse, serialize, inGamut, - toGamut, + toGamut as toGamutType, distance, equals, get, getAll, - set, - setAll, + setAll as setAllType, display, } from "./index-fn.js"; @@ -69,20 +68,33 @@ export type ToColorPrototype any> = T extends ( : (...args: A) => R : never; +/** Convert a function to a Color namespace property (returning a Color) */ +export type ToColorNamespace any> = T extends ( + ...args: infer A +) => infer R + ? T extends { returns: "color" } + ? (...args: A) => Color + : (...args: A) => R + : never; + declare namespace Color { export { getAll, - set, - setAll, - to, equals, inGamut, - toGamut, distance, serialize as toString, }; export { util, hooks, WHITES, ColorSpace as Space, parse, defaults }; + export const setAll: ToColorNamespace; + export const to: ToColorNamespace; + export const toGamut: ToColorNamespace; export const spaces: typeof ColorSpace["registry"]; + + // Must be manually defined due to overloads + // These should always match the signature of the original function + export function set (color: ColorTypes, prop: Ref, value: number | ((coord: number) => number)): Color; + export function set (color: ColorTypes, props: Record number)>): Color; } declare class Color extends SpaceAccessors implements PlainColorObject { @@ -130,11 +142,11 @@ declare class Color extends SpaceAccessors implements PlainColorObject { // Functions defined using Color.defineFunctions get: ToColorPrototype; getAll: ToColorPrototype; - setAll: ToColorPrototype; - to: ToColorPrototype; + setAll: ToColorPrototype; + to: ToColorPrototype; equals: ToColorPrototype; inGamut: ToColorPrototype; - toGamut: ToColorPrototype; + toGamut: ToColorPrototype; distance: ToColorPrototype; toString: ToColorPrototype; diff --git a/types/src/distance.d.ts b/types/src/distance.d.ts index 5684be876..60a368afe 100644 --- a/types/src/distance.d.ts +++ b/types/src/distance.d.ts @@ -1,8 +1,8 @@ -import Color, { ColorObject } from "./color.js"; +import { ColorTypes } from "./color.js"; import ColorSpace from "./space.js"; export default function distance ( - color1: Color | ColorObject, - color2: Color | ColorObject, + color1: ColorTypes, + color2: ColorTypes, space?: string | ColorSpace ): number; diff --git a/types/src/get.d.ts b/types/src/get.d.ts index b2eca227c..1ee99d55e 100644 --- a/types/src/get.d.ts +++ b/types/src/get.d.ts @@ -1,4 +1,4 @@ -import Color, { ColorObject } from "./color.js"; +import { ColorTypes } from "./color.js"; import { Ref } from "./space.js"; -export default function get (color: Color | ColorObject, prop: Ref): number; +export default function get (color: ColorTypes, prop: Ref): number; diff --git a/types/src/getAll.d.ts b/types/src/getAll.d.ts index 0ac081906..61f8b9546 100644 --- a/types/src/getAll.d.ts +++ b/types/src/getAll.d.ts @@ -1,7 +1,7 @@ -import Color, { ColorObject } from "./color.js"; +import { ColorTypes } from "./color.js"; import ColorSpace from "./space.js"; export default function getAll ( - color: Color | ColorObject, + color: ColorTypes, space?: string | ColorSpace ): [number, number, number]; diff --git a/types/src/set.d.ts b/types/src/set.d.ts index 2f9665bff..6aea210fe 100644 --- a/types/src/set.d.ts +++ b/types/src/set.d.ts @@ -1,12 +1,18 @@ import { ColorTypes, PlainColorObject } from "./color.js"; import { Ref } from "./space.js"; -export default function set ( +declare namespace set { + let returns: "color"; +} + +declare function set ( color: ColorTypes, prop: Ref, value: number | ((coord: number) => number) ): PlainColorObject; -export default function set ( +declare function set ( color: ColorTypes, props: Record number)> ): PlainColorObject; + +export default set; diff --git a/types/src/setAll.d.ts b/types/src/setAll.d.ts index ba2fce3c7..9959fa55a 100644 --- a/types/src/setAll.d.ts +++ b/types/src/setAll.d.ts @@ -1,4 +1,4 @@ -import Color, { ColorTypes, PlainColorObject } from "./color.js"; +import { ColorTypes, PlainColorObject } from "./color.js"; import ColorSpace from "./space.js"; declare namespace setAll { diff --git a/types/src/space.d.ts b/types/src/space.d.ts index 9e8f01442..33facad8e 100644 --- a/types/src/space.d.ts +++ b/types/src/space.d.ts @@ -1,5 +1,5 @@ import { White } from "./adapt.js"; -import Color, { ColorConstructor, ColorObject, Coords, PlainColorObject } from "./color.js"; +import { ColorConstructor, Coords, ColorTypes } from "./color.js"; export interface Format { /** @default "function" */ @@ -127,7 +127,7 @@ export default class ColorSpace { white: White; gamutSpace: ColorSpace; - from (color: {space: ColorSpace, coords: Coords, alpha?: number | undefined}): Coords; + from (color: ColorTypes): Coords; from (space: string | ColorSpace, coords: Coords): Coords; getFormat (format?: string | Format): Format | null; @@ -136,7 +136,7 @@ export default class ColorSpace { inGamut (coords: Coords, options?: { epsilon?: number }): boolean; - to (color: {space: ColorSpace, coords: Coords, alpha?: number | undefined}): Coords; + to (color: ColorTypes): Coords; to (space: string | ColorSpace, coords: Coords): Coords; toString (): string; diff --git a/types/test/chromaticity.ts b/types/test/chromaticity.ts index dfd64e044..b9995842f 100644 --- a/types/test/chromaticity.ts +++ b/types/test/chromaticity.ts @@ -3,16 +3,14 @@ import { uv, xy, register } from "colorjs.io/src/chromaticity"; // @ts-expect-error uv(); -// @ts-expect-error -uv("red"); +uv("red"); // $ExpectType [number, number] uv(new Color("red")); // $ExpectType [number, number] // @ts-expect-error xy(); -// @ts-expect-error -xy("red"); +xy("red"); // $ExpectType [number, number] xy(new Color("red")); // $ExpectType [number, number] // @ts-expect-error diff --git a/types/test/distance.ts b/types/test/distance.ts index 04fabaa2f..d28c92f96 100644 --- a/types/test/distance.ts +++ b/types/test/distance.ts @@ -10,6 +10,7 @@ distance(); // @ts-expect-error distance(c1); +distance("red", "blue"); // $ExpectType number distance(c1, c2); // $ExpectType number distance(c1, c2, space); // $ExpectType number distance(c1, c2, "srgb"); // $ExpectType number diff --git a/types/test/get.ts b/types/test/get.ts index 89cc8ce4c..83b9f0759 100644 --- a/types/test/get.ts +++ b/types/test/get.ts @@ -6,6 +6,7 @@ get(); // @ts-expect-error get(new Color("red")); +get("red", "p3.r"); // $ExpectType number get(new Color("red"), "p3.r"); // $ExpectType number get(new Color("red"), ["p3", "r"]); // $ExpectType number get(new Color("red"), { space: "p3", coordId: "r" }); // $ExpectType number diff --git a/types/test/getAll.ts b/types/test/getAll.ts index 6fce16a2d..3c783d27b 100644 --- a/types/test/getAll.ts +++ b/types/test/getAll.ts @@ -5,6 +5,7 @@ import sRGB from "colorjs.io/src/spaces/srgb"; // @ts-expect-error getAll(); +getAll("red"); // $ExpectType [number, number, number] getAll(new Color("red")); // $ExpectType [number, number, number] getAll(new Color("red"), "srgb"); // $ExpectType [number, number, number] getAll(new Color("red"), sRGB); // $ExpectType [number, number, number] diff --git a/types/test/set.ts b/types/test/set.ts index 2a84f4ca4..7a7f6c8ce 100644 --- a/types/test/set.ts +++ b/types/test/set.ts @@ -18,3 +18,6 @@ set("red", { }); new Color("red").set("foo", 123); // $ExpectType Color + +Color.set("red", "foo", 123); // $ExpectType Color +Color.set(new Color("red"), "foo", 123); // $ExpectType Color diff --git a/types/test/setAll.ts b/types/test/setAll.ts index f3d5719dd..9b4df2b97 100644 --- a/types/test/setAll.ts +++ b/types/test/setAll.ts @@ -26,3 +26,6 @@ setAll( new Color("red").setAll("srgb", [1, 2, 3]); // $ExpectType Color new Color("red").setAll(sRGB, [1, 2, 3]); // $ExpectType Color + +Color.setAll("red", "srgb", [1, 2, 3]); // $ExpectType Color +Color.setAll(new Color("red"), "srgb", [1, 2, 3]); // $ExpectType Color diff --git a/types/test/spaces.ts b/types/test/spaces.ts index 86fa8fd84..cbb233098 100644 --- a/types/test/spaces.ts +++ b/types/test/spaces.ts @@ -50,14 +50,15 @@ ColorSpace.resolveCoord("p3.0", "p3"); ColorSpace.resolveCoord(["p3", "r"], "p3"); space.to(new Color("red")); // $ExpectType Coords +space.to("red"); // $ExpectType Coords space.to({space: space, coords: [1, 2, 3], alpha: 1}); // $ExpectType Coords space.to({space: space, coords: [1, 2, 3]}); // $ExpectType Coords space.to(space, [1, 2, 3]); // $ExpectType Coords space.to("srgb", [1, 2, 3]); // $ExpectType Coords space.from(new Color("red")); // $ExpectType Coords +space.from("red"); // $ExpectType Coords space.from({space: space, coords: [1, 2, 3], alpha: 1}); // $ExpectType Coords space.from({space: space, coords: [1, 2, 3]}); // $ExpectType Coords space.from(space, [1, 2, 3]); // $ExpectType Coords space.from("srgb", [1, 2, 3]); // $ExpectType Coords - diff --git a/types/test/toGamut.ts b/types/test/toGamut.ts index 4bb02c16f..d2547ea17 100644 --- a/types/test/toGamut.ts +++ b/types/test/toGamut.ts @@ -17,3 +17,6 @@ new Color("red").toGamut(); // $ExpectType Color new Color("red").toGamut({ method: "clip", space: "srgb" }); // $ExpectType Color new Color("red").toGamut({ method: "clip", space: sRGB }); // $ExpectType Color new Color("red").toGamut("srgb"); // $ExpectType Color + +Color.toGamut("red"); // $ExpectType Color +Color.toGamut(new Color("red")); // $ExpectType Color From 839ae861777eebd8136ce6d220bd87570a86831c Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Wed, 28 Feb 2024 11:05:35 -0500 Subject: [PATCH 4/8] add comments --- src/chromaticity.js | 2 ++ src/distance.js | 1 + 2 files changed, 3 insertions(+) diff --git a/src/chromaticity.js b/src/chromaticity.js index 752fe5fdd..647503bd8 100644 --- a/src/chromaticity.js +++ b/src/chromaticity.js @@ -3,12 +3,14 @@ import getAll from "./getAll.js"; // Chromaticity coordinates export function uv (color) { + // Assume getColor() is called on color in getAll() let [X, Y, Z] = getAll(color, xyz_d65); let denom = X + 15 * Y + 3 * Z; return [4 * X / denom, 9 * Y / denom]; } export function xy (color) { + // Assume getColor() is called on color in getAll() let [X, Y, Z] = getAll(color, xyz_d65); let sum = X + Y + Z; return [X / sum, Y / sum]; diff --git a/src/distance.js b/src/distance.js index d41459504..788772482 100644 --- a/src/distance.js +++ b/src/distance.js @@ -6,6 +6,7 @@ import ColorSpace from "./space.js"; export default function distance (color1, color2, space = "lab") { space = ColorSpace.get(space); + // Assume getColor() is called on color in space.from() let coords1 = space.from(color1); let coords2 = space.from(color2); From 617af5e2222d76f3857b233826dddc3c469f1ebe Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Wed, 28 Feb 2024 14:51:41 -0500 Subject: [PATCH 5/8] remove duplicate getColor call --- src/distance.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/distance.js b/src/distance.js index 0316989a2..788772482 100644 --- a/src/distance.js +++ b/src/distance.js @@ -1,12 +1,9 @@ import ColorSpace from "./space.js"; -import getColor from "./getColor.js"; /** * Euclidean distance of colors in an arbitrary color space */ export default function distance (color1, color2, space = "lab") { - [color1, color2] = getColor([color1, color2]); - space = ColorSpace.get(space); // Assume getColor() is called on color in space.from() From 3c007fbe06d0fde24f5672cb5c96b3e3daaf5703 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Wed, 28 Feb 2024 15:20:18 -0500 Subject: [PATCH 6/8] remove duplicates and add missing tests --- src/distance.js | 3 --- types/test/distance.ts | 1 - types/test/get.ts | 1 - types/test/to.ts | 5 +++++ 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/distance.js b/src/distance.js index 0316989a2..788772482 100644 --- a/src/distance.js +++ b/src/distance.js @@ -1,12 +1,9 @@ import ColorSpace from "./space.js"; -import getColor from "./getColor.js"; /** * Euclidean distance of colors in an arbitrary color space */ export default function distance (color1, color2, space = "lab") { - [color1, color2] = getColor([color1, color2]); - space = ColorSpace.get(space); // Assume getColor() is called on color in space.from() diff --git a/types/test/distance.ts b/types/test/distance.ts index 0b24169b5..7ec7dba85 100644 --- a/types/test/distance.ts +++ b/types/test/distance.ts @@ -10,7 +10,6 @@ distance(); // @ts-expect-error distance(c1); -distance("red", "blue"); // $ExpectType number distance(c1, c2); // $ExpectType number distance(c1, c2, space); // $ExpectType number distance(c1, c2, "srgb"); // $ExpectType number diff --git a/types/test/get.ts b/types/test/get.ts index 02ffe6b9f..609fbe5b9 100644 --- a/types/test/get.ts +++ b/types/test/get.ts @@ -6,7 +6,6 @@ get(); // @ts-expect-error get(new Color("red")); -get("red", "p3.r"); // $ExpectType number get(new Color("red"), "p3.r"); // $ExpectType number get(new Color("red"), ["p3", "r"]); // $ExpectType number get(new Color("red"), { space: "p3", coordId: "r" }); // $ExpectType number diff --git a/types/test/to.ts b/types/test/to.ts index 286d6996b..759e55eed 100644 --- a/types/test/to.ts +++ b/types/test/to.ts @@ -1,3 +1,4 @@ +import Color from "colorjs.io/src"; import to from "colorjs.io/src/to"; // @ts-expect-error @@ -8,3 +9,7 @@ to("red"); to("red", "srgb"); // $ExpectType PlainColorObject to("red", "srgb", { inGamut: false }); // $ExpectType PlainColorObject + +new Color("red").to("srgb"); // $ExpectType Color +Color.to("red", "srgb"); // $ExpectType Color +Color.to(new Color("red"), "srgb"); // $ExpectType Color From 0054fe02e467c936316222e28025608c956210eb Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Thu, 29 Feb 2024 11:41:52 -0500 Subject: [PATCH 7/8] More consistent Color namespace type exports --- types/src/color.d.ts | 47 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/types/src/color.d.ts b/types/src/color.d.ts index 6bc178df0..2564de812 100644 --- a/types/src/color.d.ts +++ b/types/src/color.d.ts @@ -6,16 +6,16 @@ import ColorSpace, { Ref } from "./space.js"; import SpaceAccessors from "./space-coord-accessors.js"; import { - to as toType, + to as toFn, parse, serialize, - inGamut, - toGamut as toGamutType, - distance, - equals, + inGamut as inGamutFn, + toGamut as toGamutFn, + distance as distanceFn, + equals as equalsFn, get, - getAll, - setAll as setAllType, + getAll as getAllFn, + setAll as setAllFn, display, } from "./index-fn.js"; @@ -78,17 +78,16 @@ export type ToColorNamespace any> = T extends ( : never; declare namespace Color { - export { - getAll, - equals, - inGamut, - distance, - serialize as toString, - }; + // Functions defined using Color.defineFunctions + export const getAll: ToColorNamespace; + export const setAll: ToColorNamespace; + export const to: ToColorNamespace; + export const equals: ToColorNamespace; + export const inGamut: ToColorNamespace; + export const toGamut: ToColorNamespace; + export const distance: ToColorNamespace; + export { util, hooks, WHITES, ColorSpace as Space, parse, defaults }; - export const setAll: ToColorNamespace; - export const to: ToColorNamespace; - export const toGamut: ToColorNamespace; export const spaces: typeof ColorSpace["registry"]; // Must be manually defined due to overloads @@ -141,13 +140,13 @@ declare class Color extends SpaceAccessors implements PlainColorObject { // Functions defined using Color.defineFunctions get: ToColorPrototype; - getAll: ToColorPrototype; - setAll: ToColorPrototype; - to: ToColorPrototype; - equals: ToColorPrototype; - inGamut: ToColorPrototype; - toGamut: ToColorPrototype; - distance: ToColorPrototype; + getAll: ToColorPrototype; + setAll: ToColorPrototype; + to: ToColorPrototype; + equals: ToColorPrototype; + inGamut: ToColorPrototype; + toGamut: ToColorPrototype; + distance: ToColorPrototype; toString: ToColorPrototype; // Must be manually defined due to overloads From bf1d4f217b3fad5f36b8b7310fab358246a52f24 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Thu, 29 Feb 2024 12:06:54 -0500 Subject: [PATCH 8/8] add comment --- types/src/color.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/types/src/color.d.ts b/types/src/color.d.ts index 2564de812..6853dd240 100644 --- a/types/src/color.d.ts +++ b/types/src/color.d.ts @@ -86,6 +86,8 @@ declare namespace Color { export const inGamut: ToColorNamespace; export const toGamut: ToColorNamespace; export const distance: ToColorNamespace; + // `get` is defined below as a static method on the Class, + // and `toString` is intentionally not overridden for the namespace export { util, hooks, WHITES, ColorSpace as Space, parse, defaults }; export const spaces: typeof ColorSpace["registry"];