Skip to content

Commit 2247887

Browse files
authored
css-color-parser : allow color channels to be normalized individually (#1097)
1 parent 1b74068 commit 2247887

26 files changed

+701
-743
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import type { ColorData } from '../color-data';
2-
import { CSSToken, TokenNumber } from '@csstools/css-tokenizer';
3-
export declare function normalize_Color_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
2+
import { CSSToken } from '@csstools/css-tokenizer';
3+
export declare function normalize_Color_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { ColorData } from '../color-data';
2-
import type { TokenNumber } from '@csstools/css-tokenizer';
32
import { CSSToken } from '@csstools/css-tokenizer';
4-
export declare function normalize_legacy_HSL_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
5-
export declare function normalize_modern_HSL_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
3+
export declare function normalize_legacy_HSL_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
4+
export declare function normalize_modern_HSL_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
import type { ColorData } from '../color-data';
2-
import type { TokenNumber } from '@csstools/css-tokenizer';
32
import { CSSToken } from '@csstools/css-tokenizer';
4-
export declare function normalize_HWB_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
3+
export declare function normalize_HWB_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
import type { ColorData } from '../color-data';
2-
import type { TokenNumber } from '@csstools/css-tokenizer';
32
import { CSSToken } from '@csstools/css-tokenizer';
4-
export declare function normalize_Lab_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
3+
export declare function normalize_Lab_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
import type { ColorData } from '../color-data';
2-
import type { TokenNumber } from '@csstools/css-tokenizer';
32
import { CSSToken } from '@csstools/css-tokenizer';
4-
export declare function normalize_LCH_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
3+
export declare function normalize_LCH_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
import type { ColorData } from '../color-data';
2-
import type { TokenNumber } from '@csstools/css-tokenizer';
32
import { CSSToken } from '@csstools/css-tokenizer';
4-
export type normalizeChannelValuesFn = (tokens: Array<CSSToken>, colorData: ColorData) => Array<TokenNumber> | false;
3+
export type normalizeChannelValuesFn = (token: CSSToken, index: number, colorData: ColorData) => CSSToken | false;
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
import type { ColorData } from '../color-data';
2-
import type { TokenNumber } from '@csstools/css-tokenizer';
32
import { CSSToken } from '@csstools/css-tokenizer';
4-
export declare function normalize_OKLab_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
3+
export declare function normalize_OKLab_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
import type { ColorData } from '../color-data';
2-
import type { TokenNumber } from '@csstools/css-tokenizer';
32
import { CSSToken } from '@csstools/css-tokenizer';
4-
export declare function normalize_OKLCH_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
3+
export declare function normalize_OKLCH_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { ColorData } from '../color-data';
2-
import type { TokenNumber } from '@csstools/css-tokenizer';
32
import { CSSToken } from '@csstools/css-tokenizer';
4-
export declare function normalize_legacy_sRGB_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
5-
export declare function normalize_modern_sRGB_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
3+
export declare function normalize_legacy_sRGB_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
4+
export declare function normalize_modern_sRGB_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;

packages/css-color-parser/dist/index.cjs

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

packages/css-color-parser/dist/index.mjs

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 50 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,68 @@
11
import type { ColorData } from '../color-data';
2-
import { CSSToken, NumberType, TokenNumber, TokenType } from '@csstools/css-tokenizer';
2+
import { CSSToken, NumberType, TokenType } from '@csstools/css-tokenizer';
33
import { SyntaxFlag } from '../color-data';
44
import { normalize } from './normalize';
55
import { toLowerCaseAZ } from '../util/to-lower-case-a-z';
66

7-
export function normalize_Color_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false {
8-
const result: Array<TokenNumber> = [];
7+
export function normalize_Color_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false {
8+
if (token[0] === TokenType.Ident && toLowerCaseAZ(token[4].value) === 'none') {
9+
colorData.syntaxFlags.add(SyntaxFlag.HasNoneKeywords);
910

10-
for (let index = 0; index < tokens.length; index++) {
11-
const token = tokens[index];
12-
13-
if (token[0] === TokenType.Ident && toLowerCaseAZ(token[4].value) === 'none') {
14-
colorData.syntaxFlags.add(SyntaxFlag.HasNoneKeywords);
11+
return [
12+
TokenType.Number,
13+
'none',
14+
token[2],
15+
token[3],
16+
{
17+
value: NaN,
18+
type: NumberType.Number,
19+
},
20+
];
21+
}
1522

16-
result.push([
17-
TokenType.Number,
18-
'none',
19-
token[2],
20-
token[3],
21-
{
22-
value: NaN,
23-
type: NumberType.Number,
24-
},
25-
]);
26-
continue;
23+
if (token[0] === TokenType.Percentage) {
24+
if (index !== 3) {
25+
colorData.syntaxFlags.add(SyntaxFlag.HasPercentageValues);
2726
}
2827

29-
if (token[0] === TokenType.Percentage) {
30-
if (index !== 3) {
31-
colorData.syntaxFlags.add(SyntaxFlag.HasPercentageValues);
32-
}
33-
34-
let value = normalize(token[4].value, 100, -Infinity, Infinity);
35-
if (index === 3) {
36-
value = normalize(token[4].value, 100, 0, 1);
37-
}
38-
39-
result.push([
40-
TokenType.Number,
41-
value.toString(),
42-
token[2],
43-
token[3],
44-
{
45-
value: value,
46-
type: NumberType.Number,
47-
},
48-
]);
49-
continue;
28+
let value = normalize(token[4].value, 100, -Infinity, Infinity);
29+
if (index === 3) {
30+
value = normalize(token[4].value, 100, 0, 1);
5031
}
5132

52-
if (token[0] === TokenType.Number) {
53-
if (index !== 3) {
54-
colorData.syntaxFlags.add(SyntaxFlag.HasNumberValues);
55-
}
33+
return [
34+
TokenType.Number,
35+
value.toString(),
36+
token[2],
37+
token[3],
38+
{
39+
value: value,
40+
type: NumberType.Number,
41+
},
42+
];
43+
}
5644

57-
let value = normalize(token[4].value, 1, -Infinity, Infinity);
58-
if (index === 3) {
59-
value = normalize(token[4].value, 1, 0, 1);
60-
}
45+
if (token[0] === TokenType.Number) {
46+
if (index !== 3) {
47+
colorData.syntaxFlags.add(SyntaxFlag.HasNumberValues);
48+
}
6149

62-
result.push([
63-
TokenType.Number,
64-
value.toString(),
65-
token[2],
66-
token[3],
67-
{
68-
value: value,
69-
type: NumberType.Number,
70-
},
71-
]);
72-
continue;
50+
let value = normalize(token[4].value, 1, -Infinity, Infinity);
51+
if (index === 3) {
52+
value = normalize(token[4].value, 1, 0, 1);
7353
}
7454

75-
return false;
55+
return [
56+
TokenType.Number,
57+
value.toString(),
58+
token[2],
59+
token[3],
60+
{
61+
value: value,
62+
type: NumberType.Number,
63+
},
64+
];
7665
}
7766

78-
return result;
67+
return false;
7968
}

packages/css-color-parser/src/functions/color.ts

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ColorData, SyntaxFlag, colorDataTo, noneToZeroInRelativeColorDataChanne
22
import type { ColorParser } from '../color-parser';
33
import { ColorNotation } from '../color-notation';
44
import { ComponentValue, FunctionNode, TokenNode, isCommentNode, isFunctionNode, isTokenNode, isWhitespaceNode } from '@csstools/css-parser-algorithms';
5-
import { CSSToken, TokenDimension, TokenNumber, TokenPercentage, TokenType } from '@csstools/css-tokenizer';
5+
import { TokenDimension, TokenNumber, TokenPercentage, TokenType } from '@csstools/css-tokenizer';
66
import { normalize_Color_ChannelValues } from './color-normalize-channel-values';
77
import { toLowerCaseAZ } from '../util/to-lower-case-a-z';
88
import { calcFromComponentValues, mathFunctionNames } from '@csstools/css-calc';
@@ -187,38 +187,58 @@ export function color(colorFunctionNode: FunctionNode, colorParser: ColorParser)
187187
return false;
188188
}
189189

190-
const channelValues: Array<CSSToken> = [
191-
channel1[0].value,
192-
channel2[0].value,
193-
channel3[0].value,
190+
const channelValue1 = normalize_Color_ChannelValues(channel1[0].value, 0, colorData);
191+
if (!channelValue1 || channelValue1[0] !== TokenType.Number) {
192+
return false;
193+
}
194+
195+
const channelValue2 = normalize_Color_ChannelValues(channel2[0].value, 1, colorData);
196+
if (!channelValue2 || channelValue2[0] !== TokenType.Number) {
197+
return false;
198+
}
199+
200+
const channelValue3 = normalize_Color_ChannelValues(channel3[0].value, 2, colorData);
201+
if (!channelValue3 || channelValue3[0] !== TokenType.Number) {
202+
return false;
203+
}
204+
205+
const channelValues: Array<TokenNumber> = [
206+
channelValue1,
207+
channelValue2,
208+
channelValue3,
194209
];
195210

196211
if (channelAlpha.length === 1) {
197212
colorData.syntaxFlags.add(SyntaxFlag.HasAlpha);
198213

199214
if (isTokenNode(channelAlpha[0])) {
200-
channelValues.push(channelAlpha[0].value);
215+
const channelValueAlpha = normalize_Color_ChannelValues(channelAlpha[0].value, 3, colorData);
216+
if (!channelValueAlpha || channelValueAlpha[0] !== TokenType.Number) {
217+
return false;
218+
}
219+
220+
channelValues.push(channelValueAlpha);
201221
} else {
202222
colorData.alpha = channelAlpha[0];
203223
}
204224
} else if (relativeColorChannels && relativeColorChannels.has('alpha')) {
205225
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
206-
channelValues.push(relativeColorChannels.get('alpha')!);
207-
}
226+
const channelValueAlpha = normalize_Color_ChannelValues(relativeColorChannels.get('alpha')!, 3, colorData);
227+
if (!channelValueAlpha || channelValueAlpha[0] !== TokenType.Number) {
228+
return false;
229+
}
208230

209-
const normalizedChannelValues = normalize_Color_ChannelValues(channelValues, colorData);
210-
if (normalizedChannelValues === false) {
211-
return false;
231+
channelValues.push(channelValueAlpha);
212232
}
213233

214234
colorData.channels = [
215-
normalizedChannelValues[0][4].value,
216-
normalizedChannelValues[1][4].value,
217-
normalizedChannelValues[2][4].value,
235+
channelValues[0][4].value,
236+
channelValues[1][4].value,
237+
channelValues[2][4].value,
218238
];
219239

220-
if (normalizedChannelValues.length === 4) {
221-
colorData.alpha = normalizedChannelValues[3][4].value;
240+
if (channelValues.length === 4) {
241+
colorData.alpha = channelValues[3][4].value;
222242
}
223243

224244
return colorData;

0 commit comments

Comments
 (0)