diff --git a/php-transformer/src/HtmlToBlocks/HtmlTransformer.php b/php-transformer/src/HtmlToBlocks/HtmlTransformer.php index 19c6ac27..eeca1d72 100644 --- a/php-transformer/src/HtmlToBlocks/HtmlTransformer.php +++ b/php-transformer/src/HtmlToBlocks/HtmlTransformer.php @@ -3740,6 +3740,24 @@ private function visualTextWrapperBlockFromElement(DOMElement $element): ?array return null; } + // A pure-text styled wrapper whose CSS is typographic only (no box-model + // geometry) round-trips as a single styled `core/paragraph` carrying the + // wrapper class. The `core/group` + default inner paragraph form neither + // inherits the wrapper's typographic scale onto that inner paragraph nor + // suppresses default block spacing, so an eyebrow like `
+ // The Shop
` renders at the wrong size and pushes every following + // block down. The group form is retained only when the wrapper owns + // box-model geometry (padding/border/flex) that a block-level container + // must preserve. + if ( 0 === $this->childElementCount($element) && ! $this->hasBoxModelWrapperStyling($element) ) { + return $this->createBlock( + 'core/paragraph', + array_merge($this->presentationAttributes($element), array( 'content' => $content )), + array(), + $element + ); + } + return $this->createBlock( 'core/group', $this->presentationAttributes($element), @@ -3748,6 +3766,15 @@ private function visualTextWrapperBlockFromElement(DOMElement $element): ?array ); } + /** + * Box-model CSS declarations that give a text wrapper block-level geometry + * (padding, border, explicit sizing, or flex/grid layout) which must be + * preserved on a `core/group` rather than flattened onto a paragraph. + * + * @var array + */ + private const BOX_MODEL_WRAPPER_PROPERTIES = array( 'display', 'gap', 'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left', 'border', 'border-color', 'border-radius', 'width', 'height', 'min-width', 'max-width', 'min-height' ); + private function hasVisualTextWrapperSignal(DOMElement $element): bool { $className = strtolower($this->attr($element, 'class')); @@ -3759,8 +3786,16 @@ private function hasVisualTextWrapperSignal(DOMElement $element): bool return false; } - $declarations = $this->presentationDeclarations($element); - foreach ( array( 'display', 'gap', 'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left', 'border', 'border-color', 'border-radius', 'width', 'height', 'min-width', 'max-width', 'min-height' ) as $property ) { + return $this->hasBoxModelWrapperStyling($element); + } + + private function hasBoxModelWrapperStyling(DOMElement $element): bool + { + // Read the raw matched declarations rather than the post-projection + // presentation set: box-model properties such as padding are consumed + // into block-supports attributes and would otherwise be invisible here. + $declarations = $this->structuralPresentationDeclarations($element); + foreach ( self::BOX_MODEL_WRAPPER_PROPERTIES as $property ) { if ( isset($declarations[$property]) && '' !== trim((string) $declarations[$property]) ) { return true; } diff --git a/php-transformer/tests/unit/block-style-support-conversion.php b/php-transformer/tests/unit/block-style-support-conversion.php index b6bc2ab3..dca52009 100644 --- a/php-transformer/tests/unit/block-style-support-conversion.php +++ b/php-transformer/tests/unit/block-style-support-conversion.php @@ -187,11 +187,11 @@ $labelResult = ( new HtmlTransformer() )->transform($labelHtml, array('static_css' => $labelCss))->toArray(); $labelMarkup = (string) ($labelResult['serialized_blocks'] ?? ''); -$assert(str_contains($labelMarkup, '
Team

'), '26: typography-only card tier label collapses to a styled paragraph so its font scale applies', $labelMarkup); +$assert(str_contains($labelMarkup, '
]*"className":"tier-name"/', $labelMarkup), '29: typography-only tier label does not round-trip as a group wrapping a default paragraph', $labelMarkup); $stackHtml = '

Eyebrow

Low Tide Table

Local shrimp.

Next Run

Reserve
'; $stackResult = ( new HtmlTransformer() )->transform($stackHtml, array())->toArray();