Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[types] Add JSDoc based on website docs #436

Merged
merged 10 commits into from
Feb 18, 2024
8 changes: 7 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,13 @@ module.exports = {
"@typescript-eslint/ban-ts-comment": 1,
// Disallow certain built-in types
// https://typescript-eslint.io/rules/ban-types
"@typescript-eslint/ban-types": 1,
"@typescript-eslint/ban-types": [
1,
{
extendDefaults: true,
types: { "{}": false },
},
],
// Disallow generic `Array` constructors
// https://typescript-eslint.io/rules/no-array-constructor
"@typescript-eslint/no-array-constructor": 1,
Expand Down
6 changes: 6 additions & 0 deletions types/src/display.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ import ColorSpace from "./space.js";

export type Display = string & { color: PlainColorObject };

/**
* Returns a serialization of the color that can actually be displayed in the browser.
* If the default serialization can be displayed, it is returned.
* Otherwise, the color is converted to Lab, REC2020, or P3, whichever is the widest supported.
* In Node.js, this is basically equivalent to `serialize()` but returns a `String` object instead
*/
export default function display (
color: ColorTypes,
options?: {
Expand Down
36 changes: 36 additions & 0 deletions types/src/hooks.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,49 @@
/**
* This is for plugin authors.
* If you're not interested in writing plugins for Color.js, you can skip this.
*
* Hooks afford extensibility far beyond what can be achieved
* by overriding properties and methods, or using functions.
* Hooks allow plugin authors to change how Color.js’ internal code works,
* by adding custom callbacks to predefined points in the execution.
*
* You can find available hooks by searching the source code for `hooks.run(` in color.js.
* If you need a hook that is not present, we typically accept pull requests for new hooks pretty easily!
*
* The Hooks module exports both a hooks object that is used throughout Color.js (as a default export),
* as well as a Hooks class (as a named export) that can be used to create new sets of hooks.
*/
export class Hooks {
// Can't find a way to type this more specifically
// without conflicting with the types of add and run
[name: string]: any;

/**
* Schedule a callback to be executed at a certain point in the source code
* @param name The name of the hook to add the callback to
* @param callback The code to run at the given hook.
* The callback will be callewd with (typically) the same context as the calling code,
* and a single object as its only argument (typically called `env`)
* with writeable properties for various aspects of the calling environment
* @param [first=false] Whether to prepend instead of append this callback to any existing callbacks
* on the same hook. Defaults to `false`
*/
add (
name: string | string[],
callback: (env: Record<string, any>) => void,
first?: boolean
): void;
/**
* Creates a hook for plugin authors to add code to
* @param name The name of the hook to create.
* By convention, it's in the form `[class-name]-[function name]-[location in function body]`.
* Class name can be omitted if it's in `color.js`.
* Location in function body is typically something like `"start"`, `"end'`,
* `"before-conversion"`, `"after-init"`, etc.
* @param env Object with properties to be passed to the hook's callback.
* This will also be used as the function context, unless it has a `context` property,
* in which case that is used as the function context
*/
run (name: string, env?: { context?: Record<string, any> }): void;
}

Expand Down
16 changes: 16 additions & 0 deletions types/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,20 @@ declare module "./color" {
// interpolation
// These signatures should always match those in interpolation.d.ts,
// including the static versions
/** Create color mixtures in any desired proportion between two colors */
mix (color2: ColorTypes, options?: MixOptions): Color;
mix (color2: ColorTypes, p: number, options?: MixOptions): Color;
/**
* Creates a function that accepts a number and returns a color.
* For numbers in the range 0 to 1, the function interpolates;
* for numbers outside that range, the function extrapolates
* (and thus may not return the results you expect)
*/
range: ToColorPrototype<typeof range>;
/** Get an array of discrete steps */
steps (color2: ColorTypes, options?: StepsOptions): Color[];

/** Create color mixtures in any desired proportion between two colors */
static mix (
color1: ColorTypes,
color2: ColorTypes,
Expand All @@ -85,7 +94,14 @@ declare module "./color" {
p: number,
options?: MixOptions
): Color;
/**
* Creates a function that accepts a number and returns a color.
* For numbers in the range 0 to 1, the function interpolates;
* for numbers outside that range, the function extrapolates
* (and thus may not return the results you expect)
*/
static range: typeof range;
/** Get an array of discrete steps */
static steps (
color1: ColorTypes,
color2: ColorTypes,
Expand Down
27 changes: 27 additions & 0 deletions types/src/interpolation.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,34 @@ export type Range = ((percentage: number) => Color) & {
export function isRange (val: any): val is Range;

export interface RangeOptions {
/**
* The interpolation space.
* Colors do not need to be in this space; they will be converted for interpolation
* @see {@link <https://colorjs.io/docs/interpolation#ranges>}
*/
space?: string | ColorSpace | undefined;
outputSpace?: string | ColorSpace | undefined;
/**
* Used to customize the progression and make in nonlinear
* @example
* let r = new Color("lch(50 50 0)").range("lch(90 50 20)");
* Color.range(r, { progression: p => p ** 3 });
*/
progression?: ((percentage: number) => number) | undefined;
premultiplied?: boolean | undefined;
/**
* Inspired by the
* {@link https://drafts.csswg.org/css-color-5/#hue-adjuster hue-adjuster in CSS Color 5}.
*/
hue?: "longer" | "shorter" | "increasing" | "decreasing" | "raw" | undefined;
}

/**
* Creates a function that accepts a number and returns a color.
* For numbers in the range 0 to 1, the function interpolates;
* for numbers outside that range, the function extrapolates
* (and thus may not return the results you expect)
*/
export function range (range: Range, options?: RangeOptions): Range;
export function range (
color1: ColorTypes,
Expand All @@ -25,6 +46,7 @@ export function range (

export type MixOptions = RangeOptions;

/** Create color mixtures in any desired proportion between two colors */
export function mix (
color1: ColorTypes,
color2: ColorTypes,
Expand All @@ -38,12 +60,17 @@ export function mix (
): PlainColorObject;

export interface StepsOptions extends RangeOptions {
/** max deltaE between consecutive steps */
maxDeltaE?: number | undefined;
/** @see {@link Methods} */
deltaEMethod?: Methods | undefined;
/** The minimum number of steps */
steps?: number | undefined;
/** The maximum number of steps */
maxSteps?: number | undefined;
}

/** Get an array of discrete steps */
export function steps (color1: ColorTypes, color2: ColorTypes, options?: StepsOptions): PlainColorObject[];
export function steps (range: Range, options?: StepsOptions): PlainColorObject[];

Expand Down
6 changes: 6 additions & 0 deletions types/src/parse.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ export interface Options {
meta?: object | undefined;
}

/**
* Parse a string as a color.
* Understands all {@link https://www.w3.org/TR/css-color-4/ CSS Color 4} functions.
* Uses the DOM if present to parse hex colors and color names,
* so that will not available in non-DOM environments such as Node.js
*/
export default function parse (
str: string,
options?: Options & Record<string, any>
Expand Down
33 changes: 33 additions & 0 deletions types/src/space.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,31 @@ import { White } from "./adapt.js";
import Color, { ColorConstructor, ColorObject, Coords } from "./color.js";

export interface Format {
/** @default "function" */
type?: string | undefined;
/** @default "color" */
name?: string | undefined;
id?: string | undefined;
coords?: string[] | undefined;
coordGrammar?: (string & { range?: [number, number] })[] | undefined;
serializeCoords?:
| ((coords: Coords, precision: number) => [string, string, string])
| undefined;
/** Whether to adjust the coordinates to fit in the gamut */
toGamut?: boolean | undefined;
/** Whether commas should separate arguments for a format */
commas?: boolean | undefined;
/** Whether the last coordinate is the alpha coordinate */
lastAlpha?: boolean | undefined;
/** Whether the format has an alpha channel */
noAlpha?: boolean | undefined;
test?: ((str: string) => boolean) | undefined;
/** Function to parse a string into a color */
parse?: ((str: string) => ColorConstructor) | undefined;
/**
* Serialize coordinates and an alpha channel into a string.
* Must be defined for a format to support serialization
*/
serialize?: ((coords: Coords, alpha: number, opts?: Record<string, any>) => string) | undefined;
}

Expand All @@ -27,15 +38,35 @@ export interface CoordMeta {
}

export interface Options {
/** Id of this space, used in things such as conversions */
id: string;
/** The readable name of the space, used in user-facing UI */
name: string;
/** The base color space */
base?: string | ColorSpace | null | undefined;
/**
* Function that converts coords in the base color space to coords in this color space.
* Must perform chromatic adaptation if needed
*/
fromBase?: ((coords: Coords) => number[]) | undefined;
/**
* Function that converts coords in this color space to coords in the base color space.
* Must perform chromatic adaptation if needed
*/
toBase?: ((coords: Coords) => number[]) | undefined;
/**
* Object mapping coord ids to coord metadata
* @see {@link CoordMeta}
*/
coords?: Record<string, CoordMeta> | undefined;
white?: string | White | undefined;
/** The ID used by CSS, such as `display-p3` or `--cam16-jmh` */
cssId?: string | undefined;
MysteryBlokHed marked this conversation as resolved.
Show resolved Hide resolved
referred?: string | undefined;
/**
* Details about string formats to parse from / serialize to
* @see {@link Format}
*/
formats?: Record<string, Format> | undefined;
gamutSpace?: "self" | string | ColorSpace | null | undefined;
}
Expand All @@ -45,6 +76,7 @@ export type Ref =
| [string | ColorSpace, string]
| { space: string | ColorSpace; coordId: string };

/** Class for color spaces. Each color space corresponds to a `ColorSpace` instance */
export default class ColorSpace {
constructor (options: Options);

Expand Down Expand Up @@ -79,6 +111,7 @@ export default class ColorSpace {
static registry: Record<string, ColorSpace>;

get all (): Set<ColorSpace>;
/** The ID used by CSS, such as `display-p3` or `--cam16-jmh` */
get cssId (): string;
get isPolar (): boolean;

Expand Down
49 changes: 35 additions & 14 deletions types/src/toGamut.d.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
import { ColorTypes, PlainColorObject } from "./color.js";
import { Methods } from "./deltaE/index.js";
import ColorSpace, { Ref } from "./space.js";

export interface Options {
/**
* How to force into gamut.
*
* If `"clip"`, coordinates are just clipped to their reference range.\
* If `"css"`, coordinates are reduced according to the CSS 4 Gamut Mapping Algorithm.\
* If in the form `[colorSpaceId].[coordName]`, that coordinate is reduced
* until the color is in gamut. Please note that this may produce nonsensical
* results for certain coordinates (e.g. hue) or infinite loops
* if reducing the coordinate never brings the color in gamut
* @default "css"
*/
method?: "css" | "clip" | (string & {}) | undefined;
MysteryBlokHed marked this conversation as resolved.
Show resolved Hide resolved
/** The color whose space is being mapped to. Defaults to the current space */
space?: string | ColorSpace | undefined;
deltaEMethod?: Methods | undefined;
/** The "just noticeable difference" to target */
jnd?: number | undefined;
/**
* Used to configure SDR black and clamping.
* `channel` indicates the `space.channel` to use for determining when to clamp.
* `min` indicates the lower limit for black clamping and `max` indicates the upper
* limit for white clamping
*/
blackWhiteClamp?:
| {
channel: Ref;
min: number;
max: number;
}
| undefined;
}

declare namespace toGamut {
let returns: "color";
}

declare function toGamut (
color: ColorTypes,
options?: {
method?: string | undefined;
space?: string | ColorSpace | undefined;
deltaEMethod?: string | undefined;
jnd?: number | undefined;
blackWhiteClamp?: {
channel: Ref;
min: number;
max: number;
} | undefined;
} | string
): PlainColorObject;
declare function toGamut (color: ColorTypes, options?: Options | string): PlainColorObject;

export default toGamut;

Expand Down