accepted/color-4-new-spaces-js.d.ts.md
This proposal updates Sass's JavaScript (JS) API to match the color spaces proposal.
import {List} from 'immutable';
import {Value} from '../spec/js-api/value';
export type ColorSpaceHsl = 'hsl';
export type ChannelNameHsl = 'hue' | 'saturation' | 'lightness' | 'alpha';
export type ColorSpaceHwb = 'hwb';
export type ChannelNameHwb = 'hue' | 'whiteness' | 'blackness' | 'alpha';
export type ColorSpaceLab = 'lab' | 'oklab';
export type ChannelNameLab = 'lightness' | 'a' | 'b' | 'alpha';
export type ColorSpaceLch = 'lch' | 'oklch';
export type ChannelNameLch = 'lightness' | 'chroma' | 'hue' | 'alpha';
export type ColorSpaceRgb =
| 'a98-rgb'
| 'display-p3'
| 'prophoto-rgb'
| 'rec2020'
| 'rgb'
| 'srgb'
| 'srgb-linear';
export type ChannelNameRgb = 'red' | 'green' | 'blue' | 'alpha';
export type ColorSpaceXyz = 'xyz' | 'xyz-d50' | 'xyz-d65';
export type ChannelNameXyz = 'x' | 'y' | 'z' | 'alpha';
export type ChannelName =
| ChannelNameHsl
| ChannelNameHwb
| ChannelNameLab
| ChannelNameLch
| ChannelNameRgb
| ChannelNameXyz;
export type KnownColorSpace =
| ColorSpaceHsl
| ColorSpaceHwb
| ColorSpaceLab
| ColorSpaceLch
| ColorSpaceRgb
| ColorSpaceXyz;
export type PolarColorSpace = ColorSpaceHsl | ColorSpaceHwb | ColorSpaceLch;
export type RectangularColorSpace = Exclude<KnownColorSpace, PolarColorSpace>;
export type HueInterpolationMethod =
| 'decreasing'
| 'increasing'
| 'longer'
| 'shorter';
export type GamutMapMethod = 'clip' | 'local-minde';
export class SassColor extends Value {
spaceReturns the name of internal's space.
get space(): KnownColorSpace;
toSpaceIf this.space is equal to space, return this.
Otherwise, return the result of Converting a Color with this as
origin-color and space as target-space.
toSpace(space: KnownColorSpace): SassColor;
isLegacyReturns whether internal is in a legacy color space (rgb, hsl, or
hwb).
get isLegacy(): boolean;
isInGamutReturns the result of color.is-in-gamut(internal, space) as a JavaScript
boolean.
isInGamut(space?: KnownColorSpace): boolean;
toGamutReturns the result of color.to-gamut(internal, space, method).
toGamut(options: {
space?: KnownColorSpace;
method: 'clip' | 'local-minde';
}): SassColor;
channelsOrNullReturns a list of channel values (excluding alpha) for internal, with
missing channels converted to null.
Let space be the value of this.space.
Let components be the list of channels in space.
Let channels be an empty list.
For each component in components:
Let value be the channel value in internal with name of component.
If value is none, let value be null.
Append value to channels.
Return channels.
get channelsOrNull(): List<number | null>;
channelsThis algorithm returns a list of channel values (excluding alpha) for
internal, with missing channels converted to 0.
Let channelsOrNull be the value of this.channelsOrNull.
Let channels be an empty list.
For each channel in channelsOrNull:
If channel equals null, let value be 0.
Append value to channels.
Return channels.
get channels(): List<number>;
channelLet initialSpace be the value of this.space.
Let space be options.space if it is defined, and the value of
initialSpace otherwise.
If channel is not "alpha" or a channel in space, throw an error.
Let color be the result of this.toSpace(space).
Let value be the channel value in color with name of component.
If value is null, return 0.
Otherwise, return value.
channel(channel: ChannelName): number;
channel(channel: ChannelNameHsl, options: {space: ColorSpaceHsl}): number;
channel(channel: ChannelNameHwb, options: {space: ColorSpaceHwb}): number;
channel(channel: ChannelNameLab, options: {space: ColorSpaceLab}): number;
channel(channel: ChannelNameLch, options: {space: ColorSpaceLch}): number;
channel(channel: ChannelNameRgb, options: {space: ColorSpaceRgb}): number;
channel(channel: ChannelNameXyz, options: {space: ColorSpaceXyz}): number;
alphaReturns the result of calling this.channel('alpha').
get alpha(): number;
isChannelMissingReturns the result of color.is-missing(internal, channel) as a JavaScript boolean.
isChannelMissing(channel: ChannelName): boolean;
isChannelPowerlessReturns the result of color.is-powerless(internal, channel, space) as a
JavaScript boolean.
isChannelPowerless(channel: ChannelName): boolean;
isChannelPowerless(
channel: ChannelNameHsl,
options?: {space: ColorSpaceHsl}
): boolean;
isChannelPowerless(
channel: ChannelNameHwb,
options?: {space: ColorSpaceHwb}
): boolean;
isChannelPowerless(
channel: ChannelNameLab,
options?: {space: ColorSpaceLab}
): boolean;
isChannelPowerless(
channel: ChannelNameLch,
options?: {space: ColorSpaceLch}
): boolean;
isChannelPowerless(
channel: ChannelNameRgb,
options?: {space: ColorSpaceRgb}
): boolean;
isChannelPowerless(
channel: ChannelNameXyz,
options?: {space: ColorSpaceXyz}
): boolean;
interpolateLet space be the value of this.space.
If options.method is set, let interpolationMethod be a space separated
list containing the value of space, a space, and the value of
options.method.
Otherwise, if space is a rectangular color space, let interpolationMethod
be space.
Otherwise, let interpolationMethod be a space separated list containing the
value of space, a space, and the string "shorter".
Return the result of color.mix(internal, color2, options.weight, interpolationMethod).
interpolate(
color2: SassColor,
options?: {
weight?: number;
method?: HueInterpolationMethod;
}
): SassColor;
changeReplace the definition of color.change with the following:
This algorithm takes a JavaScript object options and returns a new SassColor
as the result of changing some of internal's components.
The
spacevalue defaults to thespaceofinternal, and the caller may specify any combination of channels and alpha in that space to be changed.If
spaceis not a legacy color space, a channel value ofnullwill result in a missing component value for that channel.
Let initialSpace be the value of this.space.
Let spaceSetExplicitly be true if options.space is defined, and false
otherwise.
Let space be options.space if spaceSetExplicitly is true, and the value
of initialSpace otherwise.
If initialSpace is a legacy color space and spaceSetExplicitly is false:
If options.whiteness or options.blackness is set, let space be hwb.
Otherwise, if options.hue is set and initialSpace is hwb, let space be
hwb.
Otherwise, if options.hue, options.saturation, or options.lightness is
set, let space be hsl.
Otherwise, if options.red, options.green, or options.blue is set, let
space be rgb.
If initialSpace is not equal to space, emit a deprecation warning named
color-4-api.
Let changes be the object options without space and its value.
Let keys be a list of the keys in changes.
Let components be "alpha" and the names of the channels in space.
If any key in keys is not the name of a channel in components, throw an
error.
If options.alpha is set, and isn't either null or a number between 0 and 1
(inclusive and fuzzy), throw an error.
Let color be the result of this.toSpace(space).
Let changedValue be a function that takes a string argument for channel
and calls the procedure Changing a Component Value with changes and
color as initial.
If space equals hsl and spaceSetExplicitly is false:
If any of options.hue, options.saturation or options.lightness equals
null, emit a deprecation warning named color-4-api.
If options.alpha equals null, emit a deprecation warning named
null-alpha.
Let changedColor be the result of:
new SassColor({
hue: options.hue ?? color.channel('hue'),
saturation: options.saturation ?? color.channel('saturation'),
lightness: options.lightness ?? color.channel('lightness'),
alpha: options.alpha ?? color.channel('alpha'),
space: space
})
If space equals hsl and spaceSetExplicitly is true, let changedColor
be the result of:
new SassColor({
hue: changedValue('hue'),
saturation: changedValue('saturation'),
lightness: changedValue('lightness'),
alpha: changedValue('alpha'),
space: space
})
If space equals hwb and spaceSetExplicitly is false:
If any of options.hue, options.whiteness or options.blackness equals
null, emit a deprecation warning named color-4-api.
If options.alpha equals null, emit a deprecation warning named
null-alpha.
Let changedColor be the result of:
new SassColor({
hue: options.hue ?? color.channel('hue'),
whiteness: options.whiteness ?? color.channel('whiteness'),
blackness: options.blackness ?? color.channel('blackness'),
alpha: options.alpha ?? color.channel('alpha'),
space: space
})
If space equals hwb and spaceSetExplicitly is true, let changedColor
be the result of:
new SassColor({
hue: changedValue('hue'),
whiteness: changedValue('whiteness'),
blackness: changedValue('blackness'),
alpha: changedValue('alpha'),
space: space
})
If space equals rgb and spaceSetExplicitly is false:
If any of options.red, options.green or options.blue equals
null, emit a deprecation warning named color-4-api.
If options.alpha equals null, emit a deprecation warning named
null-alpha.
Let changedColor be the result of:
new SassColor({
red: options.red ?? color.channel('red'),
green: options.green ?? color.channel('green'),
blue: options.blue ?? color.channel('blue'),
alpha: options.alpha ?? color.channel('alpha'),
space: space
})
If space equals rgb and spaceSetExplicitly is true, let changedColor
be the result of:
new SassColor({
red: changedValue('red'),
green: changedValue('green'),
blue: changedValue('blue'),
alpha: changedValue('alpha'),
space: space
})
If space equals lab or oklab, let changedColor be the result of:
new SassColor({
lightness: changedValue('lightness'),
a: changedValue('a'),
b: changedValue('b'),
alpha: changedValue('alpha'),
space: space
})
If space equals lch or oklch, let changedColor be the result of:
new SassColor({
lightness: changedValue('lightness'),
chroma: changedValue('chroma'),
hue: changedValue('hue'),
alpha: changedValue('alpha'),
space: space
})
If space equals a98-rgb, display-p3, prophoto-rgb, rec2020, srgb,
or srgb-linear, let changedColor be the result of:
new SassColor({
red: changedValue('red'),
green: changedValue('green'),
blue: changedValue('blue'),
alpha: changedValue('alpha'),
space: space
})
If space equals xyz, xyz-d50, or xyz-d65, let changedColor be the
result of:
new SassColor({
y: changedValue('y'),
x: changedValue('x'),
z: changedValue('z'),
alpha: changedValue('alpha'),
space: space
})
Return the result of changedColor.toSpace(initialSpace).
change(
options: {
[key in ChannelNameHsl]?: number | null;
} & {
space?: ColorSpaceHsl;
}
): SassColor;
change(
options: {
[key in ChannelNameHwb]?: number | null;
} & {
space?: ColorSpaceHwb;
}
): SassColor;
change(
options: {
[key in ChannelNameLab]?: number | null;
} & {
space?: ColorSpaceLab;
}
): SassColor;
change(
options: {
[key in ChannelNameLch]?: number | null;
} & {
space?: ColorSpaceLch;
}
): SassColor;
change(
options: {
[key in ChannelNameRgb]?: number | null;
} & {
space?: ColorSpaceRgb;
}
): SassColor;
change(
options: {
[key in ChannelNameXyz]?: number | null;
} & {
space?: ColorSpaceXyz;
}
): SassColor;
Let constructionSpace be the result of Determining Construction Space with
the options object passed to the constructor.
Use the constructor that matches constructionSpace.
Create a new SassColor in a color space with Lab channels—lab and oklab.
If options.space equals lab, let maximum be 100. Otherwise, let
maximum be 1.
Let lightness be the result of parsing a channel value with value of
options.lightness, minimum of 0, and maximum of maximum.
Let a be the result of parsing a channel value with value options.a.
Let b be the result of parsing a channel value with value options.b.
If options.alpha is not set, let alpha be 1. Otherwise, let alpha be
the result of parsing a clamped channel value with value options.alpha,
minimum of 0, and maximum of 1.
If options.space equals lab, set internal to the result of
lab(lightness a b / alpha).
Otherwise, if options.space equals oklab, set internal to the result
of oklab(lightness a b / alpha).
constructor(options: {
lightness: number | null;
a: number | null;
b: number | null;
alpha?: number | null;
space: ColorSpaceLab;
});
Create a new SassColor in a color space with LCH channels—lch and oklch.
If options.space equals lch, let maximum be 100. Otherwise, let
maximum be 1.
Let lightness be the result of parsing a channel value with value of
options.lightness, minimum of 0, and maximum of maximum.
Let c be the result of parsing a channel value with value options.c.
Let h be the result of parsing a channel value with value options.h.
If options.alpha is not set, let alpha be 1. Otherwise, let alpha be
the result of parsing a clamped channel value with value options.alpha,
minimum of 0, and maximum of 1.
If options.space equals lch, set internal to the result of
lch(lightness a b / alpha).
Otherwise, if options.space equals oklch, set internal to the result
of oklch(lightness a b / alpha).
constructor(options: {
lightness: number | null;
chroma: number | null;
hue: number | null;
alpha?: number | null;
space: ColorSpaceLch;
});
Create a new SassColor in a color space with RGB channels—srgb, srgb-linear,
display-p3, a98-rgb, prophoto-rgb, and rec2020. rgb is supported
through the modified RGB Constructor.
Let red be the result of parsing a channel value with value options.red.
Let green be the result of parsing a channel value with value
options.green.
Let blue be the result of parsing a channel value with value
options.blue.
If options.alpha is not set, let alpha be 1. Otherwise, let alpha be
the result of parsing a clamped channel value with value options.alpha,
minimum of 0, and maximum of 1.
Let space be the unquoted string value of options.space.
Set internal to the result of color(space red green blue / alpha).
constructor(options: {
red: number | null;
green: number | null;
blue: number | null;
alpha?: number | null;
space: Exclude<ColorSpaceRgb, 'rgb'>;
});
Create a new SassColor in a color space with XYZ channels—xyz, xyz-d50, and
xyz-d65.
Let x be the result of parsing a channel value with value options.x.
Let y be the result of parsing a channel value with value options.y.
Let z be the result of parsing a channel value with value options.z.
If options.alpha is not set, let alpha be 1. Otherwise, let alpha be
the result of parsing a clamped channel value with value options.alpha,
minimum of 0, and maximum of 1.
Let space be the unquoted string value of options.space.
Set internal to the result of color(space x y z / alpha).
constructor(options: {
x: number | null;
y: number | null;
z: number | null;
alpha?: number | null;
space: ColorSpaceXyz;
});
These will replace the existing constructors for legacy colors.
Create a new SassColor in the hsl color space.
If options.alpha is null and options.space is not set, emit a
deprecation warning named null-alpha.
Let hue be the result of parsing a channel value with value options.hue.
Let saturation be the result of parsing a channel value with value
options.saturation.
Let lightness be the result of parsing a channel value with value of
options.lightness, minimum of 0, and maximum of 100.
If options.alpha is not set, let alpha be 1. Otherwise, let alpha be
the result of parsing a clamped channel value with value of
options.alpha, minimum of 0, and maximum of 1.
Set internal to the result of hsl(hue saturation lightness / alpha).
constructor(options: {
hue: number | null;
saturation: number | null;
lightness: number | null;
alpha?: number | null;
space?: ColorSpaceHsl;
});
Create a new SassColor in the hwb color space.
If options.alpha is null and options.space is not set, emit a
deprecation warning named null-alpha.
Let hue be the result of parsing a channel value with value options.hue.
Let whiteness be the result of parsing a channel value with value
options.whiteness.
Let blackness be the result of parsing a channel value with value
options.blackness.
If options.alpha is not set, let alpha be 1. Otherwise, let alpha be
the result of parsing a clamped channel value with value of
options.alpha, minimum of 0, and maximum of 1.
Set internal to the result of hwb(hue whiteness blackness / alpha).
constructor(options: {
hue: number | null;
whiteness: number | null;
blackness: number | null;
alpha?: number | null;
space?: ColorSpaceHwb;
});
Create a new SassColor in the rgb color space.
If options.alpha is null and options.space is not set, emit a
deprecation warning named null-alpha.
Let red be the result of parsing a channel value with value options.red.
Let green be the result of parsing a channel value with value
options.green.
Let blue be the result of parsing a channel value with value
options.blue.
If options.alpha is not set, let alpha be 1. Otherwise, let alpha be
the result of parsing a clamped channel value with value of
options.alpha, minimum of 0, and maximum of 1.
Set internal to the result of rgb(red green blue / alpha).
constructor(options: {
red: number | null;
green: number | null;
blue: number | null;
alpha?: number | null;
space?: 'rgb';
});
}
A number of SassColor getters only make sense for legacy color space, and so
are being deprecated in favor of the new channel function. This deprecation
is called color-4-api.
The following deprecated getters return the result of
this.channel(channelName, { space: "rgb" }) where channelName
is the name of the respective getter.
redgreenblueThe following deprecated getters return the result of
this.channel(channelName, { space: "hsl" }) where channelName
is the name of the respective getter.
huesaturationlightnessThe following deprecated getters return the result of
this.channel(channelName, { space: "hwb" }) where channelName
is the name of the respective getter.
whitenessblacknessThis procedure takes a channel value value, and returns the special value
none if the value is null.
If value is a number, return a Sass number with a value of value.
If value is the Javascript value null, return the unquoted Sass string
none.
This procedure takes a channel value value and an inclusive range of minimum
and maximum. It asserts the value is in the range, and returns the special
value none if the value is null.
If value is fuzzy less-than minimum, throw an error.
If value is fuzzy greater-than maximum, throw an error.
Otherwise, return the result of Parsing a Channel Value.
This procedure takes a channel name, an object changes and a SassColor
initial and returns the result of applying the change for channel to
initial.
Let initialValue be the channel value in initial with name of channel.
If channel is not a key in changes, return initialValue.
Let changedValue be the value for channel in changes.
If changedValue is undefined and not null, return initialValue.
Otherwise, return changedValue.
This procedure takes an object options with unknown keys and returns a color
space for construction.
If options.space is set, return options.space.
If options.red is set, return "rgb".
If options.saturation is set, return "hsl".
If options.whiteness is set, return "hwb".
Otherwise, throw an error.
This introduces a breaking change in the Embedded Protocol, as it removes the legacy SassScript values.
message Color {
// The name of a known color space.
string space = 1;
// The value of the first channel associated with `space`.
double channel1 = 2;
// The value of the second channel associated with `space`.
double channel2 = 3;
// The value of the third channel associated with `space`.
double channel3 = 4;
// The color's alpha channel. Mandatory. Must be between 0 and 1, inclusive.
double alpha = 5;
}
The RgbColor, HslColor and HwbColor SassScript values will be removed from
the Embedded Protocol.