Skip to content

css-color-parser : allow color channels to be normalized individually #1097

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import type { ColorData } from '../color-data';
import { CSSToken, TokenNumber } from '@csstools/css-tokenizer';
export declare function normalize_Color_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
import { CSSToken } from '@csstools/css-tokenizer';
export declare function normalize_Color_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { ColorData } from '../color-data';
import type { TokenNumber } from '@csstools/css-tokenizer';
import { CSSToken } from '@csstools/css-tokenizer';
export declare function normalize_legacy_HSL_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
export declare function normalize_modern_HSL_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
export declare function normalize_legacy_HSL_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
export declare function normalize_modern_HSL_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { ColorData } from '../color-data';
import type { TokenNumber } from '@csstools/css-tokenizer';
import { CSSToken } from '@csstools/css-tokenizer';
export declare function normalize_HWB_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
export declare function normalize_HWB_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { ColorData } from '../color-data';
import type { TokenNumber } from '@csstools/css-tokenizer';
import { CSSToken } from '@csstools/css-tokenizer';
export declare function normalize_Lab_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
export declare function normalize_Lab_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { ColorData } from '../color-data';
import type { TokenNumber } from '@csstools/css-tokenizer';
import { CSSToken } from '@csstools/css-tokenizer';
export declare function normalize_LCH_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
export declare function normalize_LCH_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { ColorData } from '../color-data';
import type { TokenNumber } from '@csstools/css-tokenizer';
import { CSSToken } from '@csstools/css-tokenizer';
export type normalizeChannelValuesFn = (tokens: Array<CSSToken>, colorData: ColorData) => Array<TokenNumber> | false;
export type normalizeChannelValuesFn = (token: CSSToken, index: number, colorData: ColorData) => CSSToken | false;
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { ColorData } from '../color-data';
import type { TokenNumber } from '@csstools/css-tokenizer';
import { CSSToken } from '@csstools/css-tokenizer';
export declare function normalize_OKLab_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
export declare function normalize_OKLab_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { ColorData } from '../color-data';
import type { TokenNumber } from '@csstools/css-tokenizer';
import { CSSToken } from '@csstools/css-tokenizer';
export declare function normalize_OKLCH_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
export declare function normalize_OKLCH_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { ColorData } from '../color-data';
import type { TokenNumber } from '@csstools/css-tokenizer';
import { CSSToken } from '@csstools/css-tokenizer';
export declare function normalize_legacy_sRGB_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
export declare function normalize_modern_sRGB_ChannelValues(tokens: Array<CSSToken>, colorData: ColorData): Array<TokenNumber> | false;
export declare function normalize_legacy_sRGB_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
export declare function normalize_modern_sRGB_ChannelValues(token: CSSToken, index: number, colorData: ColorData): CSSToken | false;
2 changes: 1 addition & 1 deletion packages/css-color-parser/dist/index.cjs

Large diffs are not rendered by default.

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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,79 +1,68 @@
import type { ColorData } from '../color-data';
import { CSSToken, NumberType, TokenNumber, TokenType } from '@csstools/css-tokenizer';
import { CSSToken, NumberType, TokenType } from '@csstools/css-tokenizer';
import { SyntaxFlag } from '../color-data';
import { normalize } from './normalize';
import { toLowerCaseAZ } from '../util/to-lower-case-a-z';

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

for (let index = 0; index < tokens.length; index++) {
const token = tokens[index];

if (token[0] === TokenType.Ident && toLowerCaseAZ(token[4].value) === 'none') {
colorData.syntaxFlags.add(SyntaxFlag.HasNoneKeywords);
return [
TokenType.Number,
'none',
token[2],
token[3],
{
value: NaN,
type: NumberType.Number,
},
];
}

result.push([
TokenType.Number,
'none',
token[2],
token[3],
{
value: NaN,
type: NumberType.Number,
},
]);
continue;
if (token[0] === TokenType.Percentage) {
if (index !== 3) {
colorData.syntaxFlags.add(SyntaxFlag.HasPercentageValues);
}

if (token[0] === TokenType.Percentage) {
if (index !== 3) {
colorData.syntaxFlags.add(SyntaxFlag.HasPercentageValues);
}

let value = normalize(token[4].value, 100, -Infinity, Infinity);
if (index === 3) {
value = normalize(token[4].value, 100, 0, 1);
}

result.push([
TokenType.Number,
value.toString(),
token[2],
token[3],
{
value: value,
type: NumberType.Number,
},
]);
continue;
let value = normalize(token[4].value, 100, -Infinity, Infinity);
if (index === 3) {
value = normalize(token[4].value, 100, 0, 1);
}

if (token[0] === TokenType.Number) {
if (index !== 3) {
colorData.syntaxFlags.add(SyntaxFlag.HasNumberValues);
}
return [
TokenType.Number,
value.toString(),
token[2],
token[3],
{
value: value,
type: NumberType.Number,
},
];
}

let value = normalize(token[4].value, 1, -Infinity, Infinity);
if (index === 3) {
value = normalize(token[4].value, 1, 0, 1);
}
if (token[0] === TokenType.Number) {
if (index !== 3) {
colorData.syntaxFlags.add(SyntaxFlag.HasNumberValues);
}

result.push([
TokenType.Number,
value.toString(),
token[2],
token[3],
{
value: value,
type: NumberType.Number,
},
]);
continue;
let value = normalize(token[4].value, 1, -Infinity, Infinity);
if (index === 3) {
value = normalize(token[4].value, 1, 0, 1);
}

return false;
return [
TokenType.Number,
value.toString(),
token[2],
token[3],
{
value: value,
type: NumberType.Number,
},
];
}

return result;
return false;
}
52 changes: 36 additions & 16 deletions packages/css-color-parser/src/functions/color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ColorData, SyntaxFlag, colorDataTo, noneToZeroInRelativeColorDataChanne
import type { ColorParser } from '../color-parser';
import { ColorNotation } from '../color-notation';
import { ComponentValue, FunctionNode, TokenNode, isCommentNode, isFunctionNode, isTokenNode, isWhitespaceNode } from '@csstools/css-parser-algorithms';
import { CSSToken, TokenDimension, TokenNumber, TokenPercentage, TokenType } from '@csstools/css-tokenizer';
import { TokenDimension, TokenNumber, TokenPercentage, TokenType } from '@csstools/css-tokenizer';
import { normalize_Color_ChannelValues } from './color-normalize-channel-values';
import { toLowerCaseAZ } from '../util/to-lower-case-a-z';
import { calcFromComponentValues, mathFunctionNames } from '@csstools/css-calc';
Expand Down Expand Up @@ -187,38 +187,58 @@ export function color(colorFunctionNode: FunctionNode, colorParser: ColorParser)
return false;
}

const channelValues: Array<CSSToken> = [
channel1[0].value,
channel2[0].value,
channel3[0].value,
const channelValue1 = normalize_Color_ChannelValues(channel1[0].value, 0, colorData);
if (!channelValue1 || channelValue1[0] !== TokenType.Number) {
return false;
}

const channelValue2 = normalize_Color_ChannelValues(channel2[0].value, 1, colorData);
if (!channelValue2 || channelValue2[0] !== TokenType.Number) {
return false;
}

const channelValue3 = normalize_Color_ChannelValues(channel3[0].value, 2, colorData);
if (!channelValue3 || channelValue3[0] !== TokenType.Number) {
return false;
}

const channelValues: Array<TokenNumber> = [
channelValue1,
channelValue2,
channelValue3,
];

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

if (isTokenNode(channelAlpha[0])) {
channelValues.push(channelAlpha[0].value);
const channelValueAlpha = normalize_Color_ChannelValues(channelAlpha[0].value, 3, colorData);
if (!channelValueAlpha || channelValueAlpha[0] !== TokenType.Number) {
return false;
}

channelValues.push(channelValueAlpha);
} else {
colorData.alpha = channelAlpha[0];
}
} else if (relativeColorChannels && relativeColorChannels.has('alpha')) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
channelValues.push(relativeColorChannels.get('alpha')!);
}
const channelValueAlpha = normalize_Color_ChannelValues(relativeColorChannels.get('alpha')!, 3, colorData);
if (!channelValueAlpha || channelValueAlpha[0] !== TokenType.Number) {
return false;
}

const normalizedChannelValues = normalize_Color_ChannelValues(channelValues, colorData);
if (normalizedChannelValues === false) {
return false;
channelValues.push(channelValueAlpha);
}

colorData.channels = [
normalizedChannelValues[0][4].value,
normalizedChannelValues[1][4].value,
normalizedChannelValues[2][4].value,
channelValues[0][4].value,
channelValues[1][4].value,
channelValues[2][4].value,
];

if (normalizedChannelValues.length === 4) {
colorData.alpha = normalizedChannelValues[3][4].value;
if (channelValues.length === 4) {
colorData.alpha = channelValues[3][4].value;
}

return colorData;
Expand Down
Loading