diff --git a/src/Value/Color.php b/src/Value/Color.php index b8f2aff1..29dd935e 100644 --- a/src/Value/Color.php +++ b/src/Value/Color.php @@ -78,6 +78,7 @@ public static function parse(ParserState $oParserState, bool $bIgnoreCase = fals } else { $sColorTarget = $sColorMode; } + $iLength = $oParserState->strlen($sColorTarget); for ($i = 0; $i < $iLength; ++$i) { $oParserState->consumeWhiteSpace(); @@ -85,7 +86,7 @@ public static function parse(ParserState $oParserState, bool $bIgnoreCase = fals $aColor[$sColorTarget[$i]] = CSSFunction::parseIdentifierOrFunction($oParserState); $bContainsVarOrCalc = true; } elseif ($oParserState->comes('calc')) { - $aColor[$sColorMode[$i]] = CalcFunction::parse($oParserState); + $aColor[$sColorTarget[$i]] = CalcFunction::parse($oParserState); $bContainsVarOrCalc = true; } else { $aColor[$sColorTarget[$i]] = Size::parse($oParserState, true); @@ -101,6 +102,33 @@ public static function parse(ParserState $oParserState, bool $bIgnoreCase = fals if ($oParserState->comes(',')) { $oParserState->consume(','); } elseif ($oParserState->comes('/')) { + // According to https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb + // and https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl + // '/' is used to separate the color from the alpha channel information + // in rgb or hsl color functions (it is placed before the fourth argument). + + if (in_array($sColorMode, ["hsl", "rgb"]) && count($aColor) !== 3) { + throw new UnexpectedTokenException( + 'Unexpected token', + '/', + 'custom', + $oParserState->currentLine() + ); + } + + // If we have a hsl or rgb color function with an alpha channel, + // we need to switch the color mode to rgba or hsla accordingly. + switch ($sColorMode) { + case "rgb": + $sColorMode = "rgba"; + break; + case "hsl": + $sColorMode = "hsla"; + break; + default: + break; + } + $oParserState->consume('/'); } elseif ($oParserState->comes(')')) { // No alpha channel information diff --git a/tests/ParserTest.php b/tests/ParserTest.php index 8f1422a7..2c36caf9 100644 --- a/tests/ParserTest.php +++ b/tests/ParserTest.php @@ -169,7 +169,15 @@ public function colorParsing(): void . '#css4-rgba {background-color: rgba(242,245,249,45%);background-color: #f2f5f9;}' . "\n" . '#calc {background-color: rgba(var(--some-rgb),calc(var(--some-alpha) * .1));' - . 'background-color: hsla(var(--some-hsl),calc(var(--some-alpha) * .1));}', + . 'background-color: hsla(var(--some-hsl),calc(var(--some-alpha) * .1));}' + . "\n" + . '#hsl-calc {background-color: hsla(0,0%,10%,calc(1 - var(--hover,0) * .25));}' + . "\n" + . "#hsl-alpha-numeric {background-color: hsla(0,0%,10%,.5);}" + . "\n" + . '#rgb-calc {background-color: rgba(0,0%,10%,calc(1 - var(--hover,0) * .25));}' + . "\n" + . "#rgb-alpha-numeric {background-color: rgba(0,0%,10%,.5);}", $oDoc->render() ); } @@ -862,6 +870,30 @@ public function invalidRulesInFile(): void self::assertSame($sExpected, $oDoc->render()); } + /** + * @test + */ + public function invalidHslOrRgbInFile(): void + { + $oDoc = self::parsedStructureForFile('invalid-hsl-rgb', Settings::create()->withMultibyteSupport(true)); + $sExpected = '#hsl-1 {}' + . "\n" + . '#hsl-2 {}' + . "\n" + . '#hsl-3 {}' + . "\n" + . '#hsl-4 {}' + . "\n" + . "#rgb-1 {}" + . "\n" + . '#rgb-2 {}' + . "\n" + . '#rgb-3 {}' + . "\n" + . '#rgb-4 {}'; + self::assertSame($sExpected, $oDoc->render()); + } + /** * @test */ diff --git a/tests/fixtures/colortest.css b/tests/fixtures/colortest.css index 90640fb1..c22bb180 100644 --- a/tests/fixtures/colortest.css +++ b/tests/fixtures/colortest.css @@ -37,3 +37,20 @@ background-color: rgba(var(--some-rgb), calc(var(--some-alpha) * 0.1)); background-color: hsla(var(--some-hsl), calc(var(--some-alpha) * 0.1)); } + +#hsl-calc { + background-color: hsl(0 0% 10% / calc(1 - var(--hover, 0) * 0.25)); +} + +#hsl-alpha-numeric { + background-color: hsl(0 0% 10% / 0.5); +} + +#rgb-calc { + background-color: rgb(0 0% 10% / calc(1 - var(--hover, 0) * 0.25)); +} + +#rgb-alpha-numeric { + background-color: rgb(0 0% 10% / 0.5); +} + diff --git a/tests/fixtures/invalid-hsl-rgb.css b/tests/fixtures/invalid-hsl-rgb.css new file mode 100644 index 00000000..14eba7f2 --- /dev/null +++ b/tests/fixtures/invalid-hsl-rgb.css @@ -0,0 +1,31 @@ +#hsl-1 { + background-color: hsl(0 / 0% 10% 0.5); +} + +#hsl-2 { + background-color: hsl(0 0% / 10% 0.5); +} + +#hsl-3 { + background-color: hsl(0 0%/10% 0.5); +} + +#hsl-4 { + background-color: hsl(0 / 0% 10% calc(1 - var(--hover, 0) * 0.25)); +} + +#rgb-1 { + background-color: rgb(0 / 0% 10% 0.5); +} + +#rgb-2 { + background-color: rgb(0 0% / 10% 0.5); +} + +#rgb-3 { + background-color: rgb(0 0%/10% 0.5); +} + +#rgb-4 { + background-color: rgb(0 / 0% 10% calc(1 - var(--hover, 0) * 0.25)); +} \ No newline at end of file