Skip to content
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
33 changes: 16 additions & 17 deletions php-transformer/src/HtmlToBlocks/HtmlTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,6 @@ private function createStyleResolutionContext(): StyleResolutionContext
fn (string $value): string => $this->cssComparableValue($value),
fn (string $selector): array => $this->parsedCssSelector($selector),
fn (string $className): string => $this->promotedClassName($className),
fn (string $value, ?DOMElement $element = null): string => $this->resolveCssVariablesInValue($value, $element),
fn (string $url): string => $this->resolvedAssetImageUrl($url),
fn (string $id): string => $this->safeAnchor($id)
);
Expand Down Expand Up @@ -3519,7 +3518,7 @@ function (DOMElement $sourceElement, array $excludedTags): PatternConversionResu
new NavigationPatternContext(
$includeRuntimeDomTarget ? fn (DOMElement $sourceElement): bool => $this->runtimeIslands->isRuntimeDomTarget($sourceElement) : null,
fn (DOMElement $item, DOMElement $anchor): string => $this->navigationUnderlineColor($item, $anchor),
fn (DOMElement $sourceElement): string => $this->resolveCssVariablesInValue($this->styleResolver->specificityResolvedPresentationStyle($sourceElement)),
fn (DOMElement $sourceElement): string => $this->styleResolver->resolveCssVariablesInValue($this->styleResolver->specificityResolvedPresentationStyle($sourceElement)),
fn (DOMElement $sourceElement): array => $this->navigationStyleProjector->navigationColorInteractionStates($sourceElement),
fn (DOMElement $sourceElement): string => $this->navigationToggleSuppressor->navigationOverlayMenu($sourceElement)
),
Expand All @@ -3539,7 +3538,7 @@ function (DOMElement $sourceElement, array $excludedTags): PatternConversionResu
),
new ButtonPatternContext(
fn (DOMElement $anchor): ?array => $this->fileBlockFromAnchor($anchor),
fn (DOMElement $sourceElement): string => $this->resolveCssVariablesInValue($this->styleResolver->specificityResolvedPresentationStyle($sourceElement)),
fn (DOMElement $sourceElement): string => $this->styleResolver->resolveCssVariablesInValue($this->styleResolver->specificityResolvedPresentationStyle($sourceElement)),
fn (DOMElement $sourceElement): string => $this->richTextContentWithMaterializedInlineStyles($sourceElement),
fn (DOMElement $sourceElement, string $content): ?string => $this->richTextContentWithMaterializedSvgImages($sourceElement, $content),
fn (DOMElement $sourceElement, string $name): string => $this->attr($sourceElement, $name),
Expand Down Expand Up @@ -3606,7 +3605,7 @@ private function createProbePatternContext(): PatternContext
navigationContext: new NavigationPatternContext(
null,
fn (DOMElement $item, DOMElement $anchor): string => $this->navigationUnderlineColor($item, $anchor),
fn (DOMElement $sourceElement): string => $this->resolveCssVariablesInValue($this->styleResolver->specificityResolvedPresentationStyle($sourceElement))
fn (DOMElement $sourceElement): string => $this->styleResolver->resolveCssVariablesInValue($this->styleResolver->specificityResolvedPresentationStyle($sourceElement))
),
markupContext: new MarkupPatternContext(
fn (DOMElement $sourceElement): string => $this->safeFallbackHtml($sourceElement),
Expand Down Expand Up @@ -4483,12 +4482,12 @@ private function applySyntheticHeaderAnchorCarrier(array &$attrs, DOMElement $an
foreach ( array( 'display', 'align-items', 'justify-content' ) as $property ) {
$value = trim((string) ($direct[$property] ?? ''));
if ( '' !== $value && ! str_contains(strtolower($value), '!important') ) {
$declarations[$property] = $this->resolveCssVariablesInValue($value);
$declarations[$property] = $this->styleResolver->resolveCssVariablesInValue($value);
}
}
foreach ( $this->styleResolver->specificityResolvedGapDeclarations($anchor) as $property => $value ) {
if ( ! str_contains(strtolower($value), '!important') ) {
$declarations[$property] = $this->resolveCssVariablesInValue($value);
$declarations[$property] = $this->styleResolver->resolveCssVariablesInValue($value);
}
}
if ( array() === $declarations ) {
Expand Down Expand Up @@ -4792,7 +4791,7 @@ private function sourceAnchorHasNoTextDecoration(DOMElement $anchor): bool
{
$decorationLine = null;
foreach ( $this->styleResolver->cssDeclarations($this->styleResolver->mergedPresentationStyle($anchor)) as $property => $value ) {
$value = $this->cssComparableValue($this->resolveCssVariablesInValue($value));
$value = $this->cssComparableValue($this->styleResolver->resolveCssVariablesInValue($value));
if ( 'text-decoration' === $property ) {
if ( preg_match('/\b(?:underline|overline|line-through)\b/', $value) ) {
$decorationLine = 'line';
Expand Down Expand Up @@ -6981,7 +6980,7 @@ private function hasRenderableEmptyBlockBox(DOMElement $element): bool
{
$declarations = $this->styleResolver->structuralPresentationDeclarations($element);
foreach ( array( 'height', 'min-height', 'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left' ) as $property ) {
if ( isset($declarations[$property]) && $this->isPositiveCssLength($this->resolveCssVariablesInValue($declarations[$property], $element)) ) {
if ( isset($declarations[$property]) && $this->isPositiveCssLength($this->styleResolver->resolveCssVariablesInValue($declarations[$property], $element)) ) {
return true;
}
}
Expand Down Expand Up @@ -7162,8 +7161,8 @@ private function emptyVisualSpacerBlock(DOMElement $element): array
if ( array() !== $paint['style'] ) {
$attrs['style'] = array_replace_recursive($attrs['style'] ?? array(), $paint['style']);
}
$attrs['height'] = $this->resolveCssVariablesInValue($declarations['height']);
$attrs['width'] = $this->resolveCssVariablesInValue($declarations['width']);
$attrs['height'] = $this->styleResolver->resolveCssVariablesInValue($declarations['height']);
$attrs['width'] = $this->styleResolver->resolveCssVariablesInValue($declarations['width']);

return $this->createBlock('core/spacer', $attrs, array(), $element);
}
Expand Down Expand Up @@ -7200,7 +7199,7 @@ private function flankedSeparatorBlockFromElement(DOMElement $element): ?array
}

$height = SpacerPattern::heightFromStyle($this->attr($flank, 'style'));
if ( '' === $height || ! $this->isPositiveCssLength($this->resolveCssVariablesInValue($height, $flank)) ) {
if ( '' === $height || ! $this->isPositiveCssLength($this->styleResolver->resolveCssVariablesInValue($height, $flank)) ) {
return null;
}
$margins[ $side ] = $height;
Expand All @@ -7227,7 +7226,7 @@ private function isEmptyVisualInlineCandidate(DOMElement $element): bool
private function hasExplicitEmptyVisualDimensions(array $declarations): bool
{
foreach ( array( 'width', 'height' ) as $property ) {
if ( ! isset($declarations[$property]) || ! $this->isPositiveCssLength($this->resolveCssVariablesInValue($declarations[$property])) ) {
if ( ! isset($declarations[$property]) || ! $this->isPositiveCssLength($this->styleResolver->resolveCssVariablesInValue($declarations[$property])) ) {
return false;
}
}
Expand All @@ -7248,20 +7247,20 @@ private function isPositiveCssLength(string $value): bool
private function hasVisibleEmptyVisualPaint(array $declarations, ?DOMElement $element = null): bool
{
foreach ( array( 'background', 'background-color', 'box-shadow', 'outline' ) as $property ) {
if ( isset($declarations[$property]) && $this->isVisibleEmptyVisualPaint($this->resolveCssVariablesInValue($declarations[$property], $element)) ) {
if ( isset($declarations[$property]) && $this->isVisibleEmptyVisualPaint($this->styleResolver->resolveCssVariablesInValue($declarations[$property], $element)) ) {
return true;
}
}

foreach ( array( 'border', 'border-top', 'border-right', 'border-bottom', 'border-left' ) as $property ) {
if ( isset($declarations[$property]) && $this->isVisibleEmptyVisualBorder($this->resolveCssVariablesInValue($declarations[$property], $element)) ) {
if ( isset($declarations[$property]) && $this->isVisibleEmptyVisualBorder($this->styleResolver->resolveCssVariablesInValue($declarations[$property], $element)) ) {
return true;
}
}

return isset($declarations['border-color'], $declarations['border-width'])
&& $this->isVisibleEmptyVisualPaint($this->resolveCssVariablesInValue($declarations['border-color'], $element))
&& $this->isPositiveCssLength($this->resolveCssVariablesInValue($declarations['border-width'], $element));
&& $this->isVisibleEmptyVisualPaint($this->styleResolver->resolveCssVariablesInValue($declarations['border-color'], $element))
&& $this->isPositiveCssLength($this->styleResolver->resolveCssVariablesInValue($declarations['border-width'], $element));
}

private function isVisibleEmptyVisualPaint(string $value): bool
Expand Down Expand Up @@ -9414,7 +9413,7 @@ private function shouldPreserveEmptyVisualFigure(DOMElement $figure): bool
$declarations = $this->styleResolver->structuralPresentationDeclarations($figure);
$hasBoundedHeight = false;
foreach ( array( 'height', 'min-height' ) as $property ) {
if ( isset($declarations[$property]) && $this->isPositiveCssLength($this->resolveCssVariablesInValue($declarations[$property], $figure)) ) {
if ( isset($declarations[$property]) && $this->isPositiveCssLength($this->styleResolver->resolveCssVariablesInValue($declarations[$property], $figure)) ) {
$hasBoundedHeight = true;
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ final class StyleResolutionContext
* @param Closure(string): string $cssComparableValue
* @param Closure(string): array<string, mixed> $parsedCssSelector
* @param Closure(string): string $promotedClassName
* @param Closure(string, ?DOMElement): string $resolveCssVariablesInValue
* @param Closure(string): string $resolvedAssetImageUrl
* @param Closure(string): string $safeAnchor
*/
Expand All @@ -47,7 +46,6 @@ public function __construct(
private readonly Closure $cssComparableValue,
private readonly Closure $parsedCssSelector,
private readonly Closure $promotedClassName,
private readonly Closure $resolveCssVariablesInValue,
private readonly Closure $resolvedAssetImageUrl,
private readonly Closure $safeAnchor
) {
Expand Down Expand Up @@ -116,11 +114,6 @@ public function promotedClassName(string $className): string
return ($this->promotedClassName)($className);
}

public function resolveCssVariablesInValue(string $value, ?DOMElement $element = null): string
{
return ($this->resolveCssVariablesInValue)($value, $element);
}

public function resolvedAssetImageUrl(string $url): string
{
return ($this->resolvedAssetImageUrl)($url);
Expand Down
54 changes: 51 additions & 3 deletions php-transformer/src/HtmlToBlocks/Style/StyleResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ private function resolvedPresentationAttributes(
$declarations = $this->classOwnedBackgroundPaintDeclarations($element, $declarations);
$mapped = $this->styleAttributeMapper()->map(
$declarations,
fn (string $value): string => $this->context->resolveCssVariablesInValue($value, $element)
fn (string $value): string => $this->resolveCssVariablesInValue($value, $element)
);
$forcedGeometryDeclarations = array() === $forcedGeometryProperties
? array()
Expand Down Expand Up @@ -762,7 +762,7 @@ private function inlineAuthorOverrideDeclarations(
): array {
$candidates = $this->styleAttributeMapper()->map(
$inlineDeclarations,
fn (string $value): string => $this->context->resolveCssVariablesInValue($value, $element)
fn (string $value): string => $this->resolveCssVariablesInValue($value, $element)
)['leftover'] ?? array();
if ( isset($inlineDeclarations['box-shadow']) ) {
$candidates['box-shadow'] = $inlineDeclarations['box-shadow'];
Expand Down Expand Up @@ -1884,7 +1884,7 @@ public function authoredInheritedPropertyWinner(DOMElement $element, string $pro
return '';
}

return $this->context->resolveCssVariablesInValue($value);
return $this->resolveCssVariablesInValue($value);
}

return '';
Expand Down Expand Up @@ -2824,4 +2824,52 @@ private function authorClassTokens(DOMElement $element): string

return implode(' ', array_filter($tokens, static fn (string $token): bool => '' !== $token && ! GeneratedGutenbergClassPolicy::isGeneratedClassName($token) && ! self::isTransformerMarkerClassName($token)));
}

/**
* Expand `var(--token)` references against source custom properties, with
* ancestor-declared properties layered over them when an element is given.
*
* Lives here rather than beside SVG materialization because it is CSS
* custom-property resolution and already depends on this resolver's own
* structural declarations.
*/
public function resolveCssVariablesInValue(string $value, ?DOMElement $element = null): string
{
if ( false === strpos($value, 'var(') ) {
return $value;
}

$customProperties = $this->context->sourceStyles()->customProperties();
if ( $element instanceof DOMElement ) {
$ancestors = array();
for ( $current = $element; $current instanceof DOMElement; $current = $current->parentNode instanceof DOMElement ? $current->parentNode : null ) {
$ancestors[] = $current;
}
foreach ( array_reverse($ancestors) as $ancestor ) {
foreach ( $this->structuralPresentationDeclarations($ancestor) as $name => $propertyValue ) {
if ( str_starts_with($name, '--') ) {
$customProperties[$name] = $propertyValue;
}
}
}
}

for ( $pass = 0; $pass < 5; ++$pass ) {
$expanded = preg_replace_callback('/var\(\s*(--[A-Za-z0-9_-]+)\s*(?:,\s*([^()]*))?\)/', static function (array $matches) use ($customProperties): string {
$name = (string) $matches[1];
if ( isset($customProperties[$name]) && '' !== $customProperties[$name] ) {
return $customProperties[$name];
}

return isset($matches[2]) && '' !== trim((string) $matches[2]) ? trim((string) $matches[2]) : (string) $matches[0];
}, $value);

if ( ! is_string($expanded) || $expanded === $value ) {
break;
}
$value = $expanded;
}

return trim($value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ private function ensureSvgImageNamespace(string $html): string

private function resolveMaterializedSvgColors(string $html, DOMElement $element): string
{
$html = $this->resolveCssVariablesInValue($html);
$html = $this->styleResolver->resolveCssVariablesInValue($html);
if ( false === stripos($html, 'currentColor') ) {
return $html;
}
Expand All @@ -498,7 +498,7 @@ private function inheritedSvgColor(DOMElement $element): string
continue;
}

$color = $this->resolveCssVariablesInValue(trim((string) $declarations['color']));
$color = $this->styleResolver->resolveCssVariablesInValue(trim((string) $declarations['color']));
if ( '' !== $color && ! preg_match('/\bcurrentColor\b|var\s*\(|[<>]/i', $color) ) {
return $color;
}
Expand All @@ -507,45 +507,6 @@ private function inheritedSvgColor(DOMElement $element): string
return '#000000';
}

private function resolveCssVariablesInValue(string $value, ?DOMElement $element = null): string
{
if ( false === strpos($value, 'var(') ) {
return $value;
}

$customProperties = $this->sourceStyles()->customProperties();
if ( $element instanceof DOMElement ) {
$ancestors = array();
for ( $current = $element; $current instanceof DOMElement; $current = $current->parentNode instanceof DOMElement ? $current->parentNode : null ) {
$ancestors[] = $current;
}
foreach ( array_reverse($ancestors) as $ancestor ) {
foreach ( $this->styleResolver->structuralPresentationDeclarations($ancestor) as $name => $propertyValue ) {
if ( str_starts_with($name, '--') ) {
$customProperties[$name] = $propertyValue;
}
}
}
}

for ( $pass = 0; $pass < 5; ++$pass ) {
$expanded = preg_replace_callback('/var\(\s*(--[A-Za-z0-9_-]+)\s*(?:,\s*([^()]*))?\)/', static function (array $matches) use ($customProperties): string {
$name = (string) $matches[1];
if ( isset($customProperties[$name]) && '' !== $customProperties[$name] ) {
return $customProperties[$name];
}

return isset($matches[2]) && '' !== trim((string) $matches[2]) ? trim((string) $matches[2]) : (string) $matches[0];
}, $value);

if ( ! is_string($expanded) || $expanded === $value ) {
break;
}
$value = $expanded;
}

return trim($value);
}

/**
* @return array<string, string>
Expand Down
Loading