Skip to content

Commit dcb658c

Browse files
authored
[FEATURE] Support none as color function component value (#859)
Note that this keyword is only permitted in the "modern" syntax (and thus functions using it must be rendered in that syntax).
1 parent 6cbd495 commit dcb658c

File tree

3 files changed

+66
-18
lines changed

3 files changed

+66
-18
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Please also have a look at our
1414
- `rgb` and `rgba`, and `hsl` and `hsla` are now aliases (#797}
1515
- Parse color functions that use the "modern" syntax (#800)
1616
- Render RGB functions with "modern" syntax when required (#840)
17+
- Support `none` as color function component value (#859)
1718
- Add a class diagram to the README (#482)
1819
- Add more tests (#449)
1920

src/Value/Color.php

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,20 @@ private static function parseColorFunction(ParserState $parserState): CSSFunctio
116116
}
117117

118118
$containsVar = false;
119+
$containsNone = false;
119120
$isLegacySyntax = false;
120121
$expectedArgumentCount = $parserState->strlen($colorModeForParsing);
121122
for ($argumentIndex = 0; $argumentIndex < $expectedArgumentCount; ++$argumentIndex) {
122123
$parserState->consumeWhiteSpace();
124+
$valueKey = $colorModeForParsing[$argumentIndex];
123125
if ($parserState->comes('var')) {
124-
$colorValues[$colorModeForParsing[$argumentIndex]] = CSSFunction::parseIdentifierOrFunction($parserState);
126+
$colorValues[$valueKey] = CSSFunction::parseIdentifierOrFunction($parserState);
125127
$containsVar = true;
128+
} elseif (!$isLegacySyntax && $parserState->comes('none')) {
129+
$colorValues[$valueKey] = $parserState->parseIdentifier();
130+
$containsNone = true;
126131
} else {
127-
$colorValues[$colorModeForParsing[$argumentIndex]] = Size::parse($parserState, true);
132+
$colorValues[$valueKey] = Size::parse($parserState, true);
128133
}
129134

130135
// This must be done first, to consume comments as well, so that the `comes` test will work.
@@ -139,10 +144,10 @@ private static function parseColorFunction(ParserState $parserState): CSSFunctio
139144
break;
140145
}
141146

142-
// "Legacy" syntax is comma-delimited.
147+
// "Legacy" syntax is comma-delimited, and does not allow the `none` keyword.
143148
// "Modern" syntax is space-delimited, with `/` as alpha delimiter.
144149
// They cannot be mixed.
145-
if ($argumentIndex === 0) {
150+
if ($argumentIndex === 0 && !$containsNone) {
146151
// An immediate closing parenthesis is not valid.
147152
if ($parserState->comes(')')) {
148153
throw new UnexpectedTokenException(
@@ -291,7 +296,8 @@ private function renderAsHex(): string
291296
}
292297

293298
/**
294-
* The "legacy" syntax does not allow RGB colors to have a mixture of `percentage`s and `number`s.
299+
* The "legacy" syntax does not allow RGB colors to have a mixture of `percentage`s and `number`s,
300+
* and does not allow `none` as any component value.
295301
*
296302
* The "legacy" and "modern" monikers are part of the formal W3C syntax.
297303
* See the following for more information:
@@ -306,6 +312,10 @@ private function renderAsHex(): string
306312
*/
307313
private function shouldRenderInModernSyntax(): bool
308314
{
315+
if ($this->HasNoneAsComponentValue()) {
316+
return true;
317+
}
318+
309319
if (!$this->colorFunctionMayHaveMixedValueTypes($this->getRealName())) {
310320
return false;
311321
}
@@ -337,6 +347,11 @@ private function shouldRenderInModernSyntax(): bool
337347
return $hasPercentage && $hasNumber;
338348
}
339349

350+
private function hasNoneAsComponentValue(): bool
351+
{
352+
return \in_array('none', $this->aComponents, true);
353+
}
354+
340355
/**
341356
* Some color functions, such as `rgb`,
342357
* may have a mixture of `percentage`, `number`, or possibly other types in their arguments.

tests/Unit/Value/ColorTest.php

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,18 @@ public static function provideValidColorAndExpectedRendering(): array
114114
'rgb(0% 60% 0%)',
115115
'rgb(0%,60%,0%)',
116116
],
117-
/*
118-
'modern rgb with none' => [
117+
'modern rgb with none as red' => [
119118
'rgb(none 119 0)',
120119
'rgb(none 119 0)',
121120
],
122-
//*/
121+
'modern rgb with none as green' => [
122+
'rgb(0 none 0)',
123+
'rgb(0 none 0)',
124+
],
125+
'modern rgb with none as blue' => [
126+
'rgb(0 119 none)',
127+
'rgb(0 119 none)',
128+
],
123129
'modern rgba with fractional alpha' => [
124130
'rgb(0 119 0 / 0.5)',
125131
'rgba(0,119,0,.5)',
@@ -148,12 +154,10 @@ public static function provideValidColorAndExpectedRendering(): array
148154
'rgb(0% 60% 0% / 50%)',
149155
'rgba(0%,60%,0%,50%)',
150156
],
151-
/*
152157
'modern rgba with none as alpha' => [
153158
'rgb(0 119 0 / none)',
154-
'rgba(0 119 0 / none)',
159+
'rgba(0 119 0/none)',
155160
],
156-
//*/
157161
'legacy rgb with var for R' => [
158162
'rgb(var(--r), 119, 0)',
159163
'rgb(var(--r),119,0)',
@@ -310,22 +314,26 @@ public static function provideValidColorAndExpectedRendering(): array
310314
'hsl(120 100% 25%)',
311315
'hsl(120,100%,25%)',
312316
],
313-
/*
314-
'modern hsl with none' => [
317+
'modern hsl with none as hue' => [
315318
'hsl(none 100% 25%)',
316319
'hsl(none 100% 25%)',
317320
],
318-
//*/
321+
'modern hsl with none as saturation' => [
322+
'hsl(120 none 25%)',
323+
'hsl(120 none 25%)',
324+
],
325+
'modern hsl with none as lightness' => [
326+
'hsl(120 100% none)',
327+
'hsl(120 100% none)',
328+
],
319329
'modern hsla' => [
320330
'hsl(120 100% 25% / 0.5)',
321331
'hsla(120,100%,25%,.5)',
322332
],
323-
/*
324333
'modern hsla with none as alpha' => [
325-
'hsl(120 100% 25% none)',
326-
'hsla(120 100% 25% none)',
334+
'hsl(120 100% 25% / none)',
335+
'hsla(120 100% 25%/none)',
327336
],
328-
//*/
329337
];
330338
}
331339

@@ -386,6 +394,18 @@ public static function provideInvalidColor(): array
386394
'rgb(255, 0px, 0)',
387395
],
388396
//*/
397+
'legacy rgb color with none as red' => [
398+
'rgb(none, 0, 0)',
399+
],
400+
'legacy rgb color with none as green' => [
401+
'rgb(255, none, 0)',
402+
],
403+
'legacy rgb color with none as blue' => [
404+
'rgb(255, 0, none)',
405+
],
406+
'legacy rgba color with none as alpha' => [
407+
'rgba(255, 0, 0, none)',
408+
],
389409
'modern rgb color without slash separator for alpha' => [
390410
'rgb(255 0 0 0.5)',
391411
],
@@ -407,6 +427,18 @@ public static function provideInvalidColor(): array
407427
'legacy hsl color with 5 arguments' => [
408428
'hsl(0, 100%, 50%, 0.5, 0)',
409429
],
430+
'legacy hsl color with none as hue' => [
431+
'hsl(none, 100%, 50%)',
432+
],
433+
'legacy hsl color with none as saturation' => [
434+
'hsl(0, none, 50%)',
435+
],
436+
'legacy hsl color with none as lightness' => [
437+
'hsl(0, 100%, none)',
438+
],
439+
'legacy hsla color with none as alpha' => [
440+
'hsl(0, 100%, 50%, none)',
441+
],
410442
/*
411443
'legacy hsl color without % for S/L units' => [
412444
'hsl(0, 1, 0.5)'

0 commit comments

Comments
 (0)