Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Please also have a look at our
- Partial support for CSS Color Module Level 4:
- `rgb` and `rgba`, and `hsl` and `hsla` are now aliases (#797}
- Parse color functions that use the "modern" syntax (#800)
- Render RGB functions with "modern" syntax when required (#840)
- Add a class diagram to the README (#482)
- Add more tests (#449)

Expand Down
76 changes: 76 additions & 0 deletions src/Value/Color.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ public function render(OutputFormat $outputFormat): string
return $this->renderAsHex();
}

if ($this->shouldRenderInModernSyntax()) {
return $this->renderInModernSyntax($outputFormat);
}

return parent::render($outputFormat);
}

Expand Down Expand Up @@ -282,4 +286,76 @@ private function renderAsHex(): string

return '#' . ($canUseShortVariant ? $result[0] . $result[2] . $result[4] : $result);
}

/**
* The "legacy" syntax does not allow RGB colors to have a mixture of `percentage`s and `number`s.
*
* The "legacy" and "modern" monikers are part of the formal W3C syntax.
* See the following for more information:
* - {@link
* https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb#formal_syntax
* Description of the formal syntax for `rgb()` on MDN
* };
* - {@link
* https://www.w3.org/TR/css-color-4/#rgb-functions
* The same in the CSS Color Module Level 4 W3C Candidate Recommendation Draft
* } (as of 13 February 2024, at time of writing).
*/
private function shouldRenderInModernSyntax(): bool
{
static $colorFunctionsThatWithMixedValueTypesCannotBeRenderedInLegacySyntax = ['rgb', 'rgba'];
$colorFunction = $this->getRealName();
if (!\in_array($colorFunction, $colorFunctionsThatWithMixedValueTypesCannotBeRenderedInLegacySyntax, true)) {
return false;
}

$hasPercentage = false;
$hasNumber = false;
foreach ($this->aComponents as $key => $value) {
if ($key === 'a') {
// Alpha can have units that don't match those of the RGB components in the "legacy" syntax.
// So it is not necessary to check it. It's also always last, hence `break` rather than `continue`.
break;
}
if (!$value instanceof Size) {
// Unexpected, unknown, or modified via the API
return false;
}
$unit = $value->getUnit();
// `switch` only does loose comparison
if ($unit === null) {
$hasNumber = true;
} elseif ($unit === '%') {
$hasPercentage = true;
} else {
// Invalid unit
return false;
}
}

return $hasPercentage && $hasNumber;
}

/**
* @return non-empty-string
*/
private function renderInModernSyntax(OutputFormat $outputFormat): string
{
// Maybe not yet without alpha, but will be...
$componentsWithoutAlpha = $this->aComponents;
\end($componentsWithoutAlpha);
if (\key($componentsWithoutAlpha) === 'a') {
$alpha = $this->aComponents['a'];
unset($componentsWithoutAlpha['a']);
}

$arguments = $outputFormat->implode(' ', $componentsWithoutAlpha);
if (isset($alpha)) {
$separator = $outputFormat->spaceBeforeListArgumentSeparator('/')
. '/' . $outputFormat->spaceAfterListArgumentSeparator('/');
$arguments = $outputFormat->implode($separator, [$arguments, $alpha]);
}

return $this->getName() . '(' . $arguments . ')';
}
}
5 changes: 0 additions & 5 deletions tests/Unit/Value/ColorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,6 @@ public static function provideValidColorAndExpectedRendering(): array
'rgb(0 119 0)',
'#070',
],
// The "legacy" syntax currently used for rendering does not allow a mixture of percentages and numbers.
/*
'modern rgb with percentage R' => [
'rgb(0% 119 0)',
'rgb(0% 119 0)',
Expand All @@ -112,7 +110,6 @@ public static function provideValidColorAndExpectedRendering(): array
'rgb(0 60% 0%)',
'rgb(0 60% 0%)',
],
//*/
'modern rgb with percentage components' => [
'rgb(0% 60% 0%)',
'rgb(0%,60%,0%)',
Expand All @@ -131,7 +128,6 @@ public static function provideValidColorAndExpectedRendering(): array
'rgb(0 119 0 / 50%)',
'rgba(0,119,0,50%)',
],
/*
'modern rgba with percentage R' => [
'rgb(0% 119 0 / 0.5)',
'rgba(0% 119 0/.5)',
Expand All @@ -144,7 +140,6 @@ public static function provideValidColorAndExpectedRendering(): array
'rgb(0 119 0% / 0.5)',
'rgba(0 119 0%/.5)',
],
//*/
'modern rgba with percentage RGB' => [
'rgb(0% 60% 0% / 0.5)',
'rgba(0%,60%,0%,.5)',
Expand Down