Skip to content
2 changes: 1 addition & 1 deletion packages/css-color-parser/dist/index.mjs

Large diffs are not rendered by default.

503 changes: 308 additions & 195 deletions packages/css-color-parser/src/color-data.ts

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions packages/css-color-parser/src/functions/color-mix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Color } from '@csstools/color-helpers';
import { ColorNotation } from '../color-notation';
import { isTokenIdent, isTokenNumeric, isTokenPercentage } from '@csstools/css-tokenizer';
import { calcFromComponentValues } from '@csstools/css-calc';
import { colorDataTo, SyntaxFlag } from '../color-data';
import { colorDataToForInterpolation, SyntaxFlag } from '../color-data';
import { isFunctionNode, isTokenNode, isWhiteSpaceOrCommentNode } from '@csstools/css-parser-algorithms';
import { toLowerCaseAZ } from '../util/to-lower-case-a-z';
import { mathFunctionNames } from '@csstools/css-calc';
Expand Down Expand Up @@ -279,7 +279,7 @@ function colorMixRectangular(colorSpace: string, items: Array<ColorMixEntry> | f

// 3. If items is length 1, set color to the color of that sole item, converted to the specified interpolation <color-space>.
if (normalizedItems.length === 1) {
const color = colorDataTo(normalizedItems[0].color, outputColorNotation);
const color = colorDataToForInterpolation(normalizedItems[0].color, outputColorNotation);
color.colorNotation = outputColorNotation;
color.syntaxFlags.add(SyntaxFlag.ColorMixVariadic);
color.syntaxFlags.add(SyntaxFlag.ColorMix);
Expand Down Expand Up @@ -369,8 +369,8 @@ function colorMixRectangularPair(colorNotation: ColorNotation, a_color: ColorDat
a_alpha = Number.isNaN(a_alpha) ? b_alpha : a_alpha;
b_alpha = Number.isNaN(b_alpha) ? a_alpha : b_alpha;

const a_channels = colorDataTo(a_color, colorNotation).channels;
const b_channels = colorDataTo(b_color, colorNotation).channels;
const a_channels = colorDataToForInterpolation(a_color, colorNotation).channels;
const b_channels = colorDataToForInterpolation(b_color, colorNotation).channels;

a_channels[0] = fillInMissingComponent(a_channels[0], b_channels[0]);
b_channels[0] = fillInMissingComponent(b_channels[0], a_channels[0]);
Expand Down Expand Up @@ -448,7 +448,7 @@ function colorMixPolar(colorSpace: string, hueInterpolationMethod: string, items

// 3. If items is length 1, set color to the color of that sole item, converted to the specified interpolation <color-space>.
if (normalizedItems.length === 1) {
const color = colorDataTo(normalizedItems[0].color, outputColorNotation);
const color = colorDataToForInterpolation(normalizedItems[0].color, outputColorNotation);
color.colorNotation = outputColorNotation;
color.syntaxFlags.add(SyntaxFlag.ColorMixVariadic);
color.syntaxFlags.add(SyntaxFlag.ColorMix);
Expand Down Expand Up @@ -547,8 +547,8 @@ function colorMixPolarPair(colorNotation: ColorNotation, hueInterpolationMethod:
a_alpha = Number.isNaN(a_alpha) ? b_alpha : a_alpha;
b_alpha = Number.isNaN(b_alpha) ? a_alpha : b_alpha;

const a_channels = colorDataTo(a_color, colorNotation).channels;
const b_channels = colorDataTo(b_color, colorNotation).channels;
const a_channels = colorDataToForInterpolation(a_color, colorNotation).channels;
const b_channels = colorDataToForInterpolation(b_color, colorNotation).channels;

switch (colorNotation) {
case ColorNotation.HSL:
Expand Down
4 changes: 2 additions & 2 deletions packages/css-color-parser/src/functions/color.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ColorData} from '../color-data';
import { SyntaxFlag, colorDataTo, noneToZeroInRelativeColorDataChannels, normalizeRelativeColorDataChannels } from '../color-data';
import { SyntaxFlag, colorDataToForRelativeColorSyntax, noneToZeroInRelativeColorDataChannels, normalizeRelativeColorDataChannels } from '../color-data';
import type { ColorParser } from '../color-parser';
import { ColorNotation } from '../color-notation';
import type { ComponentValue, FunctionNode} from '@csstools/css-parser-algorithms';
Expand Down Expand Up @@ -106,7 +106,7 @@ export function color(colorFunctionNode: FunctionNode, colorParser: ColorParser)
colorData.colorNotation = colorSpaceNameToColorNotation(colorSpace);

if (relativeToColor) {
relativeToColor = colorDataTo(relativeToColor, colorData.colorNotation);
relativeToColor = colorDataToForRelativeColorSyntax(relativeToColor, colorData.colorNotation);
relativeColorChannels = normalizeRelativeColorDataChannels(relativeToColor);
relativeColorChannelsWithoutNone = noneToZeroInRelativeColorDataChannels(relativeColorChannels);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { ColorData} from '../color-data';
import { noneToZeroInRelativeColorDataChannels, normalizeRelativeColorDataChannels } from '../color-data';
import { colorDataToForRelativeColorSyntax, noneToZeroInRelativeColorDataChannels, normalizeRelativeColorDataChannels } from '../color-data';
import type { ComponentValue, FunctionNode } from '@csstools/css-parser-algorithms';
import type { TokenNumber} from '@csstools/css-tokenizer';
import { isTokenDelim, isTokenIdent, isTokenNumber, isTokenNumeric } from '@csstools/css-tokenizer';
import type { ColorNotation } from '../color-notation';
import { SyntaxFlag, colorDataTo } from '../color-data';
import { SyntaxFlag } from '../color-data';
import { calcFromComponentValues } from '@csstools/css-calc';
import { isCommentNode, isFunctionNode, isTokenNode, isWhitespaceNode } from '@csstools/css-parser-algorithms';
import type { normalizeChannelValuesFn } from './normalize-channel-values';
Expand Down Expand Up @@ -122,7 +122,7 @@ export function threeChannelSpaceSeparated(

colorData.syntaxFlags.add(SyntaxFlag.RelativeColorSyntax);

relativeToColor = colorDataTo(relativeToColor, colorNotation);
relativeToColor = colorDataToForRelativeColorSyntax(relativeToColor, colorNotation);
relativeColorChannels = normalizeRelativeColorDataChannels(relativeToColor);
relativeColorChannelsWithoutNone = noneToZeroInRelativeColorDataChannels(relativeColorChannels);

Expand Down
2 changes: 1 addition & 1 deletion packages/css-color-parser/test/basic/basic.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ assert.deepStrictEqual(
color(parse('lch(from hwb(50deg none none) l c h)')),
{
colorNotation: 'lch',
channels: [NaN, NaN, NaN],
channels: [NaN, NaN, 87.26522367839932],
alpha: 1,
syntaxFlags: new Set(['relative-color-syntax', 'has-number-values']),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import { serialize_OKLCH_data } from '../util/serialize.mjs';

const tests = [
['color-mix(in oklch, oklch(100% 0% 60deg), oklch(50% 50% 0deg))', 'oklch(0.75 0.1 0)'],
['color-mix(in oklch, oklch(100% 0% none), oklch(50% 50% 0deg))', 'oklch(0.75 0.1 0)'],
['color-mix(in oklch, rgb(255, 255, 255), rgb(180, 6, 95))', 'oklch(0.75031 0.10016 359.858)'],
['color-mix(in lch, oklch(75% 0% 60deg), oklch(75% 50% 0deg))', 'oklch(0.74979 0.09824 0.10588)'],
['color-mix(in oklch, oklch(100% 0% none), oklch(50% 50% 0deg))', 'oklch(0.75 0.1 0)'],
['color-mix(in oklch, oklch(100% none 60deg), oklch(50% 50% 0deg))', 'oklch(0.75 0.2 0)'],

// Analogous sets
['color-mix(in oklch, rgb(none none none), oklch(0.5 0.2 50))', 'oklch(0.5 0.2 50)'],
['color-mix(in oklch, hwb(100deg none none), oklch(0.5 0.2 50deg))', 'oklch(0.5 0.2 50)'],
['color-mix(in oklch, hwb(100deg none none), oklch(0.5 0.2 50deg))', 'oklch(0.5 0.2 94.8876)'],
['color-mix(in oklch, lab(100 none none), oklch(0.5 0.2 50deg))', 'oklch(0.75 0.2 50)'],
];

Expand Down
16 changes: 13 additions & 3 deletions packages/css-color-parser/test/basic/color-mix-function.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ const tests = [
['color-mix(in hsl increasing hue, hsl(180deg 50% 50%), hsl(180deg 50% 50%))', canonicalize('hsl(180deg 50% 50%)')],
['color-mix(in hsl decreasing hue, hsl(180deg 50% 50%), hsl(180deg 50% 50%))', canonicalize('hsl(180deg 50% 50%)')],

['color-mix(in hsl longer hue, hsl(50deg 0% 50%), hsl(50deg 0% 50%))', canonicalize('hsl(230deg 0% 50%)')],
['color-mix(in hsl, color-mix(in hsl longer hue, hsl(50deg 0% 50%), hsl(50deg 0% 50%)), hsl(180deg 100% 50%))', canonicalize('hsl(180deg 50% 50%)')],

['color-mix(in hsl, hsl(30deg 40% 80% / 25%) 0%, hsl(90deg none none / none))', canonicalize('hsl(30deg 40% 80% / 25%)')],
Expand Down Expand Up @@ -188,6 +189,15 @@ for (const test of tests) {
);
}

assert.deepStrictEqual(
color(parse('color-mix(in lch, lch(50% 50% 180deg), lch(100% 0% 0deg))')),
{
colorNotation: 'lch',
channels: [75, 37.5, 180],
alpha: 1,
syntaxFlags: new Set(['color-mix']),
},
);

assert.deepStrictEqual(
color(parse('color-mix(in hsl, red 0%, blue 0%)')),
Expand Down Expand Up @@ -233,7 +243,7 @@ assert.deepStrictEqual(
color(parse('oklch(from lch(100 0 0deg) l c h)')),
{
colorNotation: 'oklch',
channels: [1, 4.996003610813204e-16, Number.NaN],
channels: [1, 0, Number.NaN],
alpha: 1,
syntaxFlags: new Set(['relative-color-syntax', 'has-number-values']),
},
Expand All @@ -243,7 +253,7 @@ assert.deepStrictEqual(
color(parse('lch(from oklch(100 0 0deg) l c h)')),
{
colorNotation: 'lch',
channels: [100, 1.1102230246251565e-13, Number.NaN],
channels: [100, 0, Number.NaN],
alpha: 1,
syntaxFlags: new Set(['relative-color-syntax', 'has-number-values']),
},
Expand All @@ -253,7 +263,7 @@ assert.deepStrictEqual(
color(parse('color-mix(in oklch, lch(100 0 40deg), lch(100 0 60deg))')),
{
colorNotation: 'oklch',
channels: [1.0000000000000002, 4.996003610813204e-16, Number.NaN],
channels: [1.0000000000000002, 0, Number.NaN],
alpha: 1,
syntaxFlags: new Set(['color-mix']),
},
Expand Down
24 changes: 12 additions & 12 deletions packages/css-color-parser/test/basic/none-exhaustive.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,31 @@ import { computedValue, reducePrecisionWholeValue } from '../util/serialize.mjs'
{
const tests = [
// https://github.com/w3c/csswg-drafts/issues/14095
['hsl(from hsl(180 none 50%) h s l)', 'hsl(none none 50%)'],
['hsl(from hsl(180 0 50%) h s l)', 'hsl(none 0% 50%)'],
['hsl(from hsl(180 none 50%) h s l)', 'hsl(180 none 50%)'],
['hsl(from hsl(180 0 50%) h s l)', 'color(srgb 0.5 0.5 0.5)'],
['hsl(from lch(20 none 180) h s l)', 'hsl(none none 18.93757452%)'],
['hsl(from lch(20 0 180) h s l)', 'hsl(none 0% 18.93757452%)'],

// https://github.com/w3c/csswg-drafts/issues/14100
['lch(from orchid l 0 h)', 'lch(62.75256542 0 326.96909222)'],
['lch(from lch(from orchid l 0 h) l c h)', 'lch(62.75256542 0 none)'],
['lch(from lch(from orchid l 0 h) l c h)', 'lch(62.75256542 0 326.96909222)'],
['color-mix(in lch, lch(from orchid l 0 h))', 'lch(62.75256542 0 none)'],

// exhaustive tests
// HSL
['hsl(from hsl(none 50% 50%) h s l)', 'hsl(none 50% 50%)'],
['hsl(from hsl(180 none 50%) h s l)', 'hsl(none none 50%)'],
['hsl(from hsl(180 none 50%) h s l)', 'hsl(180 none 50%)'],
['hsl(from hsl(180 50% none) h s l)', 'hsl(180 50% none)'],
['hsl(from hsl(none none 50%) h s l)', 'hsl(none none 50%)'],
['hsl(from hsl(180 none none) h s l)', 'hsl(none none none)'],
['hsl(from hsl(180 none none) h s l)', 'hsl(180 none none)'],
['hsl(from hsl(none 50% none) h s l)', 'hsl(none 50% none)'],
['hsl(from hsl(none none none) h s l)', 'hsl(none none none)'],

['hsl(from hwb(none 25% 25%) h s l)', 'hsl(none 50% 50%)'],
['hsl(from hwb(180 none 25%) h s l)', 'color(srgb 0 0.75 0.75)'],
['hsl(from hwb(180 25% none) h s l)', 'color(srgb 0.25 1 1)'],
['hsl(from hwb(none none 25%) h s l)', 'hsl(none 100% 37.5%)'],
['hsl(from hwb(180 none none) h s l)', 'hsl(none none none)'],
['hsl(from hwb(180 none none) h s l)', 'hsl(180 none none)'],
['hsl(from hwb(none 25% none) h s l)', 'hsl(none 100% 62.5%)'],
['hsl(from hwb(none none none) h s l)', 'hsl(none none none)'],

Expand Down Expand Up @@ -132,14 +132,14 @@ import { computedValue, reducePrecisionWholeValue } from '../util/serialize.mjs'
['lch(from hwb(180 none 25%) l c h)', 'lch(69.91337803 42.54334477 196.45478916)'],
['lch(from hwb(180 25% none) l c h)', 'lch(91.18116399 49.29673753 196.65803824)'],
['lch(from hwb(none none 25%) l c h)', 'lch(40.61501478 86.05118759 none)'],
['lch(from hwb(180 none none) l c h)', 'lch(none none none)'],
['lch(from hwb(180 none none) l c h)', 'lch(none none 196.45478916)'],
['lch(from hwb(none 25% none) l c h)', 'lch(58.23109529 85.49243054 none)'],
['lch(from hwb(none none none) l c h)', 'lch(none none none)'],

['lch(from lch(none 20 180) l c h)', 'lch(none 20 180)'],
['lch(from lch(20 none 180) l c h)', 'lch(20 none none)'],
['lch(from lch(20 none 180) l c h)', 'lch(20 none 180)'],
['lch(from lch(20 20 none) l c h)', 'lch(20 20 none)'],
['lch(from lch(none none 180) l c h)', 'lch(none none none)'],
['lch(from lch(none none 180) l c h)', 'lch(none none 180)'],
['lch(from lch(20 none none) l c h)', 'lch(20 none none)'],
['lch(from lch(none 20 none) l c h)', 'lch(none 20 none)'],
['lch(from lch(none none none) l c h)', 'lch(none none none)'],
Expand Down Expand Up @@ -184,7 +184,7 @@ import { computedValue, reducePrecisionWholeValue } from '../util/serialize.mjs'
['oklch(from hwb(180 none 25%) l c h)', 'oklch(0.72924735 0.12448121 194.7689599)'],
['oklch(from hwb(180 25% none) l c h)', 'oklch(0.91079253 0.14429702 194.91785641)'],
['oklch(from hwb(none none 25%) l c h)', 'oklch(0.50578216 0.20754918 none)'],
['oklch(from hwb(180 none none) l c h)', 'oklch(none none none)'],
['oklch(from hwb(180 none none) l c h)', 'oklch(none none 194.7689599)'],
['oklch(from hwb(none 25% none) l c h)', 'oklch(0.65951623 0.22690049 none)'],
['oklch(from hwb(none none none) l c h)', 'oklch(none none none)'],

Expand All @@ -197,9 +197,9 @@ import { computedValue, reducePrecisionWholeValue } from '../util/serialize.mjs'
['oklch(from lch(none none none) l c h)', 'oklch(none none none)'],

['oklch(from oklch(none 0.2 180) l c h)', 'oklch(none 0.2 180)'],
['oklch(from oklch(0.2 none 180) l c h)', 'oklch(0.2 none none)'],
['oklch(from oklch(0.2 none 180) l c h)', 'oklch(0.2 none 180)'],
['oklch(from oklch(0.2 0.2 none) l c h)', 'oklch(0.2 0.2 none)'],
['oklch(from oklch(none none 180) l c h)', 'oklch(none none none)'],
['oklch(from oklch(none none 180) l c h)', 'oklch(none none 180)'],
['oklch(from oklch(0.2 none none) l c h)', 'oklch(0.2 none none)'],
['oklch(from oklch(none 0.2 none) l c h)', 'oklch(none 0.2 none)'],
['oklch(from oklch(none none none) l c h)', 'oklch(none none none)'],
Expand Down
Loading
Loading