diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 79bea8ee821fc..7823d69584338 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -276,7 +276,7 @@ Gather blocks in a layout container. ([Source](https://github.com/WordPress/gute - **Name:** core/group - **Category:** design - **Supports:** align (full, wide), anchor, ariaLabel, color (background, gradients, link, text), spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~html~~ -- **Attributes:** tagName, templateLock +- **Attributes:** layout, tagName, templateLock ## Heading diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 7047b4a3a28f0..2581b986508aa 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -42,6 +42,31 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default'; $layout_styles = array(); if ( 'default' === $layout_type ) { + if ( $has_block_gap_support ) { + if ( is_array( $gap_value ) ) { + $gap_value = isset( $gap_value['top'] ) ? $gap_value['top'] : null; + } + if ( $gap_value && ! $should_skip_gap_serialization ) { + array_push( + $layout_styles, + array( + 'selector' => "$selector > *", + 'declarations' => array( + 'margin-block-start' => '0', + 'margin-block-end' => '0', + ), + ), + array( + 'selector' => "$selector$selector > * + *", + 'declarations' => array( + 'margin-block-start' => $gap_value, + 'margin-block-end' => '0', + ), + ) + ); + } + } + } elseif ( 'constrained' === $layout_type ) { $content_size = isset( $layout['contentSize'] ) ? $layout['contentSize'] : ''; $wide_size = isset( $layout['wideSize'] ) ? $layout['wideSize'] : ''; @@ -254,11 +279,11 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $has_block_gap_support = isset( $block_gap ) ? null !== $block_gap : false; $default_block_layout = _wp_array_get( $block_type->supports, array( '__experimentalLayout', 'default' ), array() ); $used_layout = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : $default_block_layout; + if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] ) { if ( ! $global_layout_settings ) { return $block_content; } - $used_layout = $global_layout_settings; } $class_names = array(); @@ -268,6 +293,11 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $layout_classname = ''; $use_global_padding = gutenberg_get_global_settings( array( 'useRootPaddingAwareAlignments' ) ) && ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] || isset( $used_layout['contentSize'] ) && $used_layout['contentSize'] ); + // Set the correct layout type for blocks using legacy content width. + if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] || isset( $used_layout['contentSize'] ) && $used_layout['contentSize'] ) { + $used_layout['type'] = 'constrained'; + } + if ( $use_global_padding ) { $class_names[] = 'has-global-padding'; } diff --git a/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php b/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php index eb5b351dd67b1..f1371c04cacd3 100644 --- a/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php +++ b/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php @@ -758,18 +758,6 @@ function( $pseudo_selector ) use ( $selector ) { } } - /* - * Reset default browser margin on the root body element. - * This is set on the root selector **before** generating the ruleset - * from the `theme.json`. This is to ensure that if the `theme.json` declares - * `margin` in its `spacing` declaration for the `body` element then these - * user-generated values take precedence in the CSS cascade. - * @link https://github.com/WordPress/gutenberg/issues/36147. - */ - if ( static::ROOT_BLOCK_SELECTOR === $selector ) { - $block_rules .= 'body { margin: 0; }'; - } - // 2. Generate and append the rules that use the general selector. $block_rules .= static::to_ruleset( $selector, $declarations ); @@ -793,6 +781,34 @@ function( $pseudo_selector ) use ( $selector ) { } if ( static::ROOT_BLOCK_SELECTOR === $selector ) { + /* + * Reset default browser margin on the root body element. + * This is set on the root selector **before** generating the ruleset + * from the `theme.json`. This is to ensure that if the `theme.json` declares + * `margin` in its `spacing` declaration for the `body` element then these + * user-generated values take precedence in the CSS cascade. + * @link https://github.com/WordPress/gutenberg/issues/36147. + */ + $block_rules .= 'body { margin: 0;'; + + /* + * If there are content and wide widths in theme.json, output them + * as custom properties on the body element so all blocks can use them. + */ + if ( isset( $settings['layout']['contentSize'] ) || isset( $settings['layout']['wideSize'] ) ) { + $content_size = isset( $settings['layout']['contentSize'] ) ? $settings['layout']['contentSize'] : $settings['layout']['wideSize']; + $content_size = static::is_safe_css_declaration( 'max-width', $content_size ) ? $content_size : 'initial'; + $wide_size = isset( $settings['layout']['wideSize'] ) ? $settings['layout']['wideSize'] : $settings['layout']['contentSize']; + $wide_size = static::is_safe_css_declaration( 'max-width', $wide_size ) ? $wide_size : 'initial'; + $block_rules .= '--wp--style--global--content-size: ' . $content_size . ';'; + $block_rules .= '--wp--style--global--wide-size: ' . $wide_size . ';'; + } + + $block_rules .= '}'; + } + + if ( static::ROOT_BLOCK_SELECTOR === $selector ) { + if ( $use_root_padding ) { $block_rules .= '.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }'; $block_rules .= '.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; @@ -804,6 +820,7 @@ function( $pseudo_selector ) use ( $selector ) { $block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }'; $block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $block_gap_value = _wp_array_get( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ), '0.5em' ); $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; if ( $has_block_gap_support ) { $block_gap_value = static::get_property_value( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ) ); @@ -1295,7 +1312,7 @@ protected function get_layout_styles( $block_metadata ) { $has_fallback_gap_support = ! $has_block_gap_support; // This setting isn't useful yet: it exists as a placeholder for a future explicit fallback gap styles support. $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); $layout_definitions = _wp_array_get( $this->theme_json, array( 'settings', 'layout', 'definitions' ), array() ); - $layout_selector_pattern = '/^[a-zA-Z0-9\-\.\ *+>]*$/'; // Allow alphanumeric classnames, spaces, wildcard, sibling, and child combinator selectors. + $layout_selector_pattern = '/^[a-zA-Z0-9\-\.\ *+>:\(\)]*$/'; // Allow alphanumeric classnames, spaces, wildcard, sibling, child combinator and pseudo class selectors. // Gap styles will only be output if the theme has block gap support, or supports a fallback gap. // Default layout gap styles will be skipped for themes that do not explicitly opt-in to blockGap with a `true` or `false` value. diff --git a/lib/compat/wordpress-6.1/theme.json b/lib/compat/wordpress-6.1/theme.json index 5d06385c0bb81..40432cedf3877 100644 --- a/lib/compat/wordpress-6.1/theme.json +++ b/lib/compat/wordpress-6.1/theme.json @@ -234,6 +234,66 @@ } ] }, + "constrained": { + "name": "constrained", + "slug": "constrained", + "className": "is-layout-constrained", + "baseStyles": [ + { + "selector": " > .alignleft", + "rules": { + "float": "left", + "margin-inline-start": "0", + "margin-inline-end": "2em" + } + }, + { + "selector": " > .alignright", + "rules": { + "float": "right", + "margin-inline-start": "2em", + "margin-inline-end": "0" + } + }, + { + "selector": " > .aligncenter", + "rules": { + "margin-left": "auto !important", + "margin-right": "auto !important" + } + }, + { + "selector": " > :where(:not(.alignleft):not(.alignright):not(.alignfull))", + "rules": { + "max-width": "var(--wp--style--global--content-size)", + "margin-left": "auto !important", + "margin-right": "auto !important" + } + }, + { + "selector": " > .alignwide", + "rules": { + "max-width": "var(--wp--style--global--wide-size)" + } + } + ], + "spacingStyles": [ + { + "selector": " > *", + "rules": { + "margin-block-start": "0", + "margin-block-end": "0" + } + }, + { + "selector": " > * + *", + "rules": { + "margin-block-start": null, + "margin-block-end": "0" + } + } + ] + }, "flex": { "name": "flex", "slug": "flex", diff --git a/packages/block-editor/src/components/block-alignment-control/use-available-alignments.js b/packages/block-editor/src/components/block-alignment-control/use-available-alignments.js index d1d32f82d6d27..ba6f885a09cd5 100644 --- a/packages/block-editor/src/components/block-alignment-control/use-available-alignments.js +++ b/packages/block-editor/src/components/block-alignment-control/use-available-alignments.js @@ -46,7 +46,7 @@ export default function useAvailableAlignments( controls = DEFAULT_CONTROLS ) { } // Starting here, it's the fallback for themes not supporting the layout config. - if ( layoutType.name !== 'default' ) { + if ( layoutType.name !== 'default' && layoutType.name !== 'constrained' ) { return []; } const { alignments: availableAlignments = DEFAULT_CONTROLS } = layout; diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index 69b5810b0f106..30a5b265ca10a 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -110,25 +110,37 @@ function LayoutPanel( { setAttributes, attributes, name: blockName } ) { // Only show the inherit toggle if it's supported, // a default theme layout is set (e.g. one that provides `contentSize` and/or `wideSize` values), - // and that the default / flow layout type is in use, as this is the only one that supports inheritance. + // and either the default / flow or the constrained layout type is in use, as the toggle switches from one to the other. const showInheritToggle = !! ( allowInheriting && !! defaultThemeLayout && - ( ! layout?.type || layout?.type === 'default' || layout?.inherit ) + ( ! layout?.type || + layout?.type === 'default' || + layout?.type === 'constrained' || + layout?.inherit ) ); const usedLayout = layout || defaultBlockLayout || {}; - const { inherit = false, type = 'default' } = usedLayout; + const { + inherit = false, + type = 'default', + contentSize = null, + } = usedLayout; /** - * `themeSupportsLayout` is only relevant to the `default/flow` - * layout and it should not be taken into account when other + * `themeSupportsLayout` is only relevant to the `default/flow` or + * `constrained` layouts and it should not be taken into account when other * `layout` types are used. */ - if ( type === 'default' && ! themeSupportsLayout ) { + if ( + ( type === 'default' || type === 'constrained' ) && + ! themeSupportsLayout + ) { return null; } const layoutType = getLayoutType( type ); + const constrainedType = getLayoutType( 'constrained' ); + const onChangeType = ( newType ) => setAttributes( { layout: { type: newType } } ); const onChangeLayout = ( newLayout ) => @@ -141,18 +153,29 @@ function LayoutPanel( { setAttributes, attributes, name: blockName } ) { { showInheritToggle && ( <> <ToggleControl - label={ __( 'Inner blocks use full width' ) } - checked={ ! inherit } + label={ __( + 'Inner blocks respect content width' + ) } + checked={ + layoutType?.name === 'constrained' || + !! inherit || + !! contentSize + } onChange={ () => setAttributes( { layout: { - inherit: ! inherit, + type: + layoutType?.name === + 'constrained' + ? 'default' + : 'constrained', }, } ) } /> <p className="block-editor-hooks__layout-controls-helptext"> - { !! inherit + { !! inherit || + layoutType?.name === 'constrained' ? __( 'Nested blocks use theme content width with options for full and wide widths.' ) @@ -170,13 +193,20 @@ function LayoutPanel( { setAttributes, attributes, name: blockName } ) { /> ) } - { ! inherit && layoutType && ( + { layoutType && layoutType.name !== 'default' && ( <layoutType.inspectorControls layout={ usedLayout } onChange={ onChangeLayout } layoutBlockSupport={ layoutBlockSupport } /> ) } + { constrainedType && !! contentSize && ( + <constrainedType.inspectorControls + layout={ usedLayout } + onChange={ onChangeLayout } + layoutBlockSupport={ layoutBlockSupport } + /> + ) } </PanelBody> </InspectorControls> { ! inherit && layoutType && ( @@ -280,9 +310,10 @@ export const withLayoutStyles = createHigherOrderComponent( const { layout } = attributes; const { default: defaultBlockLayout } = getBlockSupport( name, layoutBlockSupportKey ) || {}; - const usedLayout = layout?.inherit - ? defaultThemeLayout - : layout || defaultBlockLayout || {}; + const usedLayout = + layout?.inherit || layout?.contentSize || layout?.wideSize + ? { ...layout, type: 'constrained' } + : layout || defaultBlockLayout || {}; const layoutClasses = hasLayoutBlockSupport ? useLayoutClasses( usedLayout, defaultThemeLayout?.definitions ) : null; diff --git a/packages/block-editor/src/layouts/constrained.js b/packages/block-editor/src/layouts/constrained.js new file mode 100644 index 0000000000000..8517382defcf8 --- /dev/null +++ b/packages/block-editor/src/layouts/constrained.js @@ -0,0 +1,217 @@ +/** + * WordPress dependencies + */ +import { + Button, + __experimentalUseCustomUnits as useCustomUnits, + __experimentalUnitControl as UnitControl, +} from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { Icon, positionCenter, stretchWide } from '@wordpress/icons'; +import { getCSSRules } from '@wordpress/style-engine'; + +/** + * Internal dependencies + */ +import useSetting from '../components/use-setting'; +import { appendSelectors, getBlockGapCSS, getAlignmentsInfo } from './utils'; +import { getGapBoxControlValueFromStyle } from '../hooks/gap'; +import { shouldSkipSerialization } from '../hooks/utils'; + +export default { + name: 'constrained', + label: __( 'Constrained' ), + inspectorControls: function DefaultLayoutInspectorControls( { + layout, + onChange, + } ) { + const { wideSize, contentSize } = layout; + const units = useCustomUnits( { + availableUnits: useSetting( 'spacing.units' ) || [ + '%', + 'px', + 'em', + 'rem', + 'vw', + ], + } ); + + return ( + <> + <div className="block-editor-hooks__layout-controls"> + <div className="block-editor-hooks__layout-controls-unit"> + <UnitControl + label={ __( 'Content' ) } + labelPosition="top" + __unstableInputWidth="80px" + value={ contentSize || wideSize || '' } + onChange={ ( nextWidth ) => { + nextWidth = + 0 > parseFloat( nextWidth ) + ? '0' + : nextWidth; + onChange( { + ...layout, + contentSize: nextWidth, + } ); + } } + units={ units } + /> + <Icon icon={ positionCenter } /> + </div> + <div className="block-editor-hooks__layout-controls-unit"> + <UnitControl + label={ __( 'Wide' ) } + labelPosition="top" + __unstableInputWidth="80px" + value={ wideSize || contentSize || '' } + onChange={ ( nextWidth ) => { + nextWidth = + 0 > parseFloat( nextWidth ) + ? '0' + : nextWidth; + onChange( { + ...layout, + wideSize: nextWidth, + } ); + } } + units={ units } + /> + <Icon icon={ stretchWide } /> + </div> + </div> + <div className="block-editor-hooks__layout-controls-reset"> + <Button + variant="secondary" + isSmall + disabled={ ! contentSize && ! wideSize } + onClick={ () => + onChange( { + contentSize: undefined, + wideSize: undefined, + inherit: false, + } ) + } + > + { __( 'Reset' ) } + </Button> + </div> + + <p className="block-editor-hooks__layout-controls-helptext"> + { __( + 'Customize the width for all elements that are assigned to the center or wide columns.' + ) } + </p> + </> + ); + }, + toolBarControls: function DefaultLayoutToolbarControls() { + return null; + }, + getLayoutStyle: function getLayoutStyle( { + selector, + layout = {}, + style, + blockName, + hasBlockGapSupport, + layoutDefinitions, + } ) { + const { contentSize, wideSize } = layout; + const blockGapStyleValue = getGapBoxControlValueFromStyle( + style?.spacing?.blockGap + ); + // If a block's block.json skips serialization for spacing or + // spacing.blockGap, don't apply the user-defined value to the styles. + const blockGapValue = + blockGapStyleValue?.top && + ! shouldSkipSerialization( blockName, 'spacing', 'blockGap' ) + ? blockGapStyleValue?.top + : ''; + + let output = + !! contentSize || !! wideSize + ? ` + ${ appendSelectors( + selector, + '> :where(:not(.alignleft):not(.alignright):not(.alignfull))' + ) } { + max-width: ${ contentSize ?? wideSize }; + margin-left: auto !important; + margin-right: auto !important; + } + ${ appendSelectors( selector, '> .alignwide' ) } { + max-width: ${ wideSize ?? contentSize }; + } + ${ appendSelectors( selector, '> .alignfull' ) } { + max-width: none; + } + ` + : ''; + + // If there is custom padding, add negative margins for alignfull blocks. + if ( style?.spacing?.padding ) { + // The style object might be storing a preset so we need to make sure we get a usable value. + const paddingValues = getCSSRules( style ); + paddingValues.forEach( ( rule ) => { + if ( rule.key === 'paddingRight' ) { + output += ` + ${ appendSelectors( selector, '> .alignfull' ) } { + margin-right: calc(${ rule.value } * -1); + } + `; + } else if ( rule.key === 'paddingLeft' ) { + output += ` + ${ appendSelectors( selector, '> .alignfull' ) } { + margin-left: calc(${ rule.value } * -1); + } + `; + } + } ); + } + + // Output blockGap styles based on rules contained in layout definitions in theme.json. + if ( hasBlockGapSupport && blockGapValue ) { + output += getBlockGapCSS( + selector, + layoutDefinitions, + 'constrained', + blockGapValue + ); + } + return output; + }, + getOrientation() { + return 'vertical'; + }, + getAlignments( layout ) { + const alignmentInfo = getAlignmentsInfo( layout ); + if ( layout.alignments !== undefined ) { + if ( ! layout.alignments.includes( 'none' ) ) { + layout.alignments.unshift( 'none' ); + } + return layout.alignments.map( ( alignment ) => ( { + name: alignment, + info: alignmentInfo[ alignment ], + } ) ); + } + const { contentSize, wideSize } = layout; + + const alignments = [ + { name: 'left' }, + { name: 'center' }, + { name: 'right' }, + ]; + + if ( contentSize ) { + alignments.unshift( { name: 'full' } ); + } + + if ( wideSize ) { + alignments.unshift( { name: 'wide', info: alignmentInfo.wide } ); + } + + alignments.unshift( { name: 'none', info: alignmentInfo.none } ); + + return alignments; + }, +}; diff --git a/packages/block-editor/src/layouts/flow.js b/packages/block-editor/src/layouts/flow.js index f0e084d623b17..a41ced61cb6ab 100644 --- a/packages/block-editor/src/layouts/flow.js +++ b/packages/block-editor/src/layouts/flow.js @@ -1,122 +1,32 @@ /** * WordPress dependencies */ -import { - Button, - __experimentalUseCustomUnits as useCustomUnits, - __experimentalUnitControl as UnitControl, -} from '@wordpress/components'; -import { __, sprintf } from '@wordpress/i18n'; -import { Icon, positionCenter, stretchWide } from '@wordpress/icons'; -import { getCSSRules } from '@wordpress/style-engine'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import useSetting from '../components/use-setting'; -import { appendSelectors, getBlockGapCSS } from './utils'; + +import { getBlockGapCSS, getAlignmentsInfo } from './utils'; import { getGapBoxControlValueFromStyle } from '../hooks/gap'; import { shouldSkipSerialization } from '../hooks/utils'; export default { name: 'default', label: __( 'Flow' ), - inspectorControls: function DefaultLayoutInspectorControls( { - layout, - onChange, - } ) { - const { wideSize, contentSize } = layout; - const units = useCustomUnits( { - availableUnits: useSetting( 'spacing.units' ) || [ - '%', - 'px', - 'em', - 'rem', - 'vw', - ], - } ); - - return ( - <> - <div className="block-editor-hooks__layout-controls"> - <div className="block-editor-hooks__layout-controls-unit"> - <UnitControl - label={ __( 'Content' ) } - labelPosition="top" - __unstableInputWidth="80px" - value={ contentSize || wideSize || '' } - onChange={ ( nextWidth ) => { - nextWidth = - 0 > parseFloat( nextWidth ) - ? '0' - : nextWidth; - onChange( { - ...layout, - contentSize: nextWidth, - } ); - } } - units={ units } - /> - <Icon icon={ positionCenter } /> - </div> - <div className="block-editor-hooks__layout-controls-unit"> - <UnitControl - label={ __( 'Wide' ) } - labelPosition="top" - __unstableInputWidth="80px" - value={ wideSize || contentSize || '' } - onChange={ ( nextWidth ) => { - nextWidth = - 0 > parseFloat( nextWidth ) - ? '0' - : nextWidth; - onChange( { - ...layout, - wideSize: nextWidth, - } ); - } } - units={ units } - /> - <Icon icon={ stretchWide } /> - </div> - </div> - <div className="block-editor-hooks__layout-controls-reset"> - <Button - variant="secondary" - isSmall - disabled={ ! contentSize && ! wideSize } - onClick={ () => - onChange( { - contentSize: undefined, - wideSize: undefined, - inherit: false, - } ) - } - > - { __( 'Reset' ) } - </Button> - </div> - - <p className="block-editor-hooks__layout-controls-helptext"> - { __( - 'Customize the width for all elements that are assigned to the center or wide columns.' - ) } - </p> - </> - ); + inspectorControls: function DefaultLayoutInspectorControls() { + return null; }, toolBarControls: function DefaultLayoutToolbarControls() { return null; }, getLayoutStyle: function getLayoutStyle( { selector, - layout = {}, style, blockName, hasBlockGapSupport, layoutDefinitions, } ) { - const { contentSize, wideSize } = layout; const blockGapStyleValue = getGapBoxControlValueFromStyle( style?.spacing?.blockGap ); @@ -128,46 +38,7 @@ export default { ? blockGapStyleValue?.top : ''; - let output = - !! contentSize || !! wideSize - ? ` - ${ appendSelectors( - selector, - '> :where(:not(.alignleft):not(.alignright):not(.alignfull))' - ) } { - max-width: ${ contentSize ?? wideSize }; - margin-left: auto !important; - margin-right: auto !important; - } - ${ appendSelectors( selector, '> .alignwide' ) } { - max-width: ${ wideSize ?? contentSize }; - } - ${ appendSelectors( selector, '> .alignfull' ) } { - max-width: none; - } - ` - : ''; - - // If there is custom padding, add negative margins for alignfull blocks. - if ( style?.spacing?.padding ) { - // The style object might be storing a preset so we need to make sure we get a usable value. - const paddingValues = getCSSRules( style ); - paddingValues.forEach( ( rule ) => { - if ( rule.key === 'paddingRight' ) { - output += ` - ${ appendSelectors( selector, '> .alignfull' ) } { - margin-right: calc(${ rule.value } * -1); - } - `; - } else if ( rule.key === 'paddingLeft' ) { - output += ` - ${ appendSelectors( selector, '> .alignfull' ) } { - margin-left: calc(${ rule.value } * -1); - } - `; - } - } ); - } + let output = ''; // Output blockGap styles based on rules contained in layout definitions in theme.json. if ( hasBlockGapSupport && blockGapValue ) { @@ -194,7 +65,6 @@ export default { info: alignmentInfo[ alignment ], } ) ); } - const { contentSize, wideSize } = layout; const alignments = [ { name: 'left' }, @@ -202,45 +72,8 @@ export default { { name: 'right' }, ]; - if ( contentSize ) { - alignments.unshift( { name: 'full' } ); - } - - if ( wideSize ) { - alignments.unshift( { name: 'wide', info: alignmentInfo.wide } ); - } - alignments.unshift( { name: 'none', info: alignmentInfo.none } ); return alignments; }, }; - -/** - * Helper method to assign contextual info to clarify - * alignment settings. - * - * Besides checking if `contentSize` and `wideSize` have a - * value, we now show this information only if their values - * are not a `css var`. This needs to change when parsing - * css variables land. - * - * @see https://github.com/WordPress/gutenberg/pull/34710#issuecomment-918000752 - * - * @param {Object} layout The layout object. - * @return {Object} An object with contextual info per alignment. - */ -function getAlignmentsInfo( layout ) { - const { contentSize, wideSize } = layout; - const alignmentInfo = {}; - const sizeRegex = /^(?!0)\d+(px|em|rem|vw|vh|%)?$/i; - if ( sizeRegex.test( contentSize ) ) { - // translators: %s: container size (i.e. 600px etc) - alignmentInfo.none = sprintf( __( 'Max %s wide' ), contentSize ); - } - if ( sizeRegex.test( wideSize ) ) { - // translators: %s: container size (i.e. 600px etc) - alignmentInfo.wide = sprintf( __( 'Max %s wide' ), wideSize ); - } - return alignmentInfo; -} diff --git a/packages/block-editor/src/layouts/index.js b/packages/block-editor/src/layouts/index.js index 928876c1365f7..4ec1ff6f33191 100644 --- a/packages/block-editor/src/layouts/index.js +++ b/packages/block-editor/src/layouts/index.js @@ -3,8 +3,9 @@ */ import flex from './flex'; import flow from './flow'; +import constrained from './constrained'; -const layoutTypes = [ flow, flex ]; +const layoutTypes = [ flow, flex, constrained ]; /** * Retrieves a layout type by name. diff --git a/packages/block-editor/src/layouts/test/constrained.js b/packages/block-editor/src/layouts/test/constrained.js new file mode 100644 index 0000000000000..5ac1d00c1874f --- /dev/null +++ b/packages/block-editor/src/layouts/test/constrained.js @@ -0,0 +1,21 @@ +/** + * Internal dependencies + */ +import constrained from '../constrained'; + +describe( 'getLayoutStyle', () => { + it( 'should return an empty string if no non-default params are provided', () => { + const expected = ''; + + const result = constrained.getLayoutStyle( { + selector: '.my-container', + layout: {}, + style: {}, + blockName: 'test-block', + hasBlockGapSupport: false, + layoutDefinitions: undefined, + } ); + + expect( result ).toBe( expected ); + } ); +} ); diff --git a/packages/block-editor/src/layouts/utils.js b/packages/block-editor/src/layouts/utils.js index e2a27f7d7b121..11996d4715312 100644 --- a/packages/block-editor/src/layouts/utils.js +++ b/packages/block-editor/src/layouts/utils.js @@ -1,3 +1,8 @@ +/** + * WordPress dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; + /** * Utility to generate the proper CSS selector for layout styles. * @@ -62,3 +67,32 @@ export function getBlockGapCSS( } return output; } + +/** + * Helper method to assign contextual info to clarify + * alignment settings. + * + * Besides checking if `contentSize` and `wideSize` have a + * value, we now show this information only if their values + * are not a `css var`. This needs to change when parsing + * css variables land. + * + * @see https://github.com/WordPress/gutenberg/pull/34710#issuecomment-918000752 + * + * @param {Object} layout The layout object. + * @return {Object} An object with contextual info per alignment. + */ +export function getAlignmentsInfo( layout ) { + const { contentSize, wideSize } = layout; + const alignmentInfo = {}; + const sizeRegex = /^(?!0)\d+(px|em|rem|vw|vh|%)?$/i; + if ( sizeRegex.test( contentSize ) ) { + // translators: %s: container size (i.e. 600px etc) + alignmentInfo.none = sprintf( __( 'Max %s wide' ), contentSize ); + } + if ( sizeRegex.test( wideSize ) ) { + // translators: %s: container size (i.e. 600px etc) + alignmentInfo.wide = sprintf( __( 'Max %s wide' ), wideSize ); + } + return alignmentInfo; +} diff --git a/packages/block-library/src/group/block.json b/packages/block-library/src/group/block.json index cfe942dfc5a48..cfc07d59d15b4 100644 --- a/packages/block-library/src/group/block.json +++ b/packages/block-library/src/group/block.json @@ -15,6 +15,12 @@ "templateLock": { "type": [ "string", "boolean" ], "enum": [ "all", "insert", false ] + }, + "layout": { + "type": "object", + "default": { + "type": "constrained" + } } }, "supports": { diff --git a/packages/block-library/src/group/deprecated.js b/packages/block-library/src/group/deprecated.js index 63e0c5fef3674..2a3ec02c5ed96 100644 --- a/packages/block-library/src/group/deprecated.js +++ b/packages/block-library/src/group/deprecated.js @@ -10,6 +10,7 @@ import { InnerBlocks, getColorClassName, useBlockProps, + useInnerBlocksProps, } from '@wordpress/block-editor'; const migrateAttributes = ( attributes ) => { @@ -41,6 +42,89 @@ const migrateAttributes = ( attributes ) => { }; const deprecated = [ + // Version with default layout. + { + attributes: { + tagName: { + type: 'string', + default: 'div', + }, + templateLock: { + type: 'string', + }, + }, + supports: { + __experimentalOnEnter: true, + __experimentalSettings: true, + align: [ 'wide', 'full' ], + anchor: true, + ariaLabel: true, + html: false, + color: { + gradients: true, + link: true, + __experimentalDefaultControls: { + background: true, + text: true, + }, + }, + spacing: { + margin: [ 'top', 'bottom' ], + padding: true, + blockGap: true, + __experimentalDefaultControls: { + padding: true, + blockGap: true, + }, + }, + __experimentalBorder: { + color: true, + radius: true, + style: true, + width: true, + __experimentalDefaultControls: { + color: true, + radius: true, + style: true, + width: true, + }, + }, + typography: { + fontSize: true, + lineHeight: true, + __experimentalFontStyle: true, + __experimentalFontWeight: true, + __experimentalLetterSpacing: true, + __experimentalTextTransform: true, + __experimentalDefaultControls: { + fontSize: true, + }, + }, + __experimentalLayout: true, + }, + save( { attributes: { tagName: Tag } } ) { + return ( + <Tag { ...useInnerBlocksProps.save( useBlockProps.save() ) } /> + ); + }, + isEligible: ( { layout } ) => + ! layout || layout.inherit || layout.contentSize, + migrate: ( attributes ) => { + const { layout = null } = attributes; + if ( ! layout ) { + return attributes; + } + if ( layout.inherit || layout.contentSize ) { + return { + ...attributes, + layout: { + ...layout, + type: 'constrained', + }, + }; + } + }, + }, // Version of the block with the double div. { attributes: { diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index e45613bbba25d..6f1b45462dd92 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -1,7 +1,8 @@ /** * WordPress dependencies */ -import { useSelect } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEffect } from '@wordpress/element'; import { InnerBlocks, useBlockProps, @@ -48,7 +49,9 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { ); const defaultLayout = useSetting( 'layout' ) || {}; const { tagName: TagName = 'div', templateLock, layout = {} } = attributes; - const usedLayout = !! layout && layout.inherit ? defaultLayout : layout; + const usedLayout = ! layout?.type + ? { ...defaultLayout, ...layout, type: 'default' } + : { ...defaultLayout, ...layout }; const { type = 'default' } = usedLayout; const layoutSupportEnabled = themeSupportsLayout || type !== 'default'; @@ -67,6 +70,16 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { } ); + const { __unstableMarkNextChangeAsNotPersistent } = + useDispatch( blockEditorStore ); + const { type: layoutType = null } = layout; + useEffect( () => { + if ( layoutType ) { + __unstableMarkNextChangeAsNotPersistent(); + setAttributes( { layout: { ...layout, type: layoutType } } ); + } + }, [ layoutType ] ); + return ( <> <InspectorControls __experimentalGroup="advanced"> diff --git a/packages/block-library/src/group/variations.js b/packages/block-library/src/group/variations.js index bbae57a0031c0..2b47fdb2a555c 100644 --- a/packages/block-library/src/group/variations.js +++ b/packages/block-library/src/group/variations.js @@ -9,12 +9,13 @@ const variations = [ name: 'group', title: __( 'Group' ), description: __( 'Gather blocks in a layout container.' ), - attributes: { layout: { type: 'default' } }, + attributes: { layout: { type: 'constrained' } }, scope: [ 'transform' ], isActive: ( blockAttributes ) => ! blockAttributes.layout || ! blockAttributes.layout?.type || - blockAttributes.layout?.type === 'default', + blockAttributes.layout?.type === 'default' || + blockAttributes.layout?.type === 'constrained', icon: group, }, { diff --git a/packages/e2e-tests/specs/editor/plugins/__snapshots__/cpt-locking.test.js.snap b/packages/e2e-tests/specs/editor/plugins/__snapshots__/cpt-locking.test.js.snap index 4f502b2fd29b0..fcacbe069610c 100644 --- a/packages/e2e-tests/specs/editor/plugins/__snapshots__/cpt-locking.test.js.snap +++ b/packages/e2e-tests/specs/editor/plugins/__snapshots__/cpt-locking.test.js.snap @@ -41,7 +41,7 @@ exports[`cpt locking template_lock all should not error when deleting the cotent `; exports[`cpt locking template_lock all unlocked group should allow blocks to be moved 1`] = ` -"<!-- wp:group {\\"templateLock\\":false} --> +"<!-- wp:group {\\"templateLock\\":false,\\"layout\\":{\\"type\\":\\"constrained\\"}} --> <div class=\\"wp-block-group\\"><!-- wp:paragraph {\\"placeholder\\":\\"Add a description\\"} --> <p>p1</p> <!-- /wp:paragraph --> @@ -55,7 +55,7 @@ exports[`cpt locking template_lock all unlocked group should allow blocks to be `; exports[`cpt locking template_lock all unlocked group should allow blocks to be removed 1`] = ` -"<!-- wp:group {\\"templateLock\\":false} --> +"<!-- wp:group {\\"templateLock\\":false,\\"layout\\":{\\"type\\":\\"constrained\\"}} --> <div class=\\"wp-block-group\\"><!-- wp:quote --> <blockquote class=\\"wp-block-quote\\"><!-- wp:paragraph --> <p></p> diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/block-grouping.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/block-grouping.test.js.snap index f3c24c200b971..ff3a356078f28 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/block-grouping.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/block-grouping.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Block Grouping Group creation creates a group from multiple blocks of different types via block transforms 1`] = ` -"<!-- wp:group --> +"<!-- wp:group {\\"layout\\":{\\"type\\":\\"constrained\\"}} --> <div class=\\"wp-block-group\\"><!-- wp:heading --> <h2>Group Heading</h2> <!-- /wp:heading --> @@ -17,7 +17,7 @@ exports[`Block Grouping Group creation creates a group from multiple blocks of d `; exports[`Block Grouping Group creation creates a group from multiple blocks of the same type via block transforms 1`] = ` -"<!-- wp:group --> +"<!-- wp:group {\\"layout\\":{\\"type\\":\\"constrained\\"}} --> <div class=\\"wp-block-group\\"><!-- wp:paragraph --> <p>First Paragraph</p> <!-- /wp:paragraph --> @@ -33,7 +33,7 @@ exports[`Block Grouping Group creation creates a group from multiple blocks of t `; exports[`Block Grouping Group creation creates a group from multiple blocks of the same type via options toolbar 1`] = ` -"<!-- wp:group --> +"<!-- wp:group {\\"layout\\":{\\"type\\":\\"constrained\\"}} --> <div class=\\"wp-block-group\\"><!-- wp:paragraph --> <p>First Paragraph</p> <!-- /wp:paragraph --> @@ -49,7 +49,7 @@ exports[`Block Grouping Group creation creates a group from multiple blocks of t `; exports[`Block Grouping Group creation groups and ungroups multiple blocks of different types via options toolbar 1`] = ` -"<!-- wp:group --> +"<!-- wp:group {\\"layout\\":{\\"type\\":\\"constrained\\"}} --> <div class=\\"wp-block-group\\"><!-- wp:heading --> <h2>Group Heading</h2> <!-- /wp:heading --> @@ -79,7 +79,7 @@ exports[`Block Grouping Group creation groups and ungroups multiple blocks of di `; exports[`Block Grouping Preserving selected blocks attributes preserves width alignment settings of selected blocks 1`] = ` -"<!-- wp:group {\\"align\\":\\"full\\"} --> +"<!-- wp:group {\\"layout\\":{\\"type\\":\\"constrained\\"},\\"align\\":\\"full\\"} --> <div class=\\"wp-block-group alignfull\\"><!-- wp:heading --> <h2>Group Heading</h2> <!-- /wp:heading --> diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap index eb52e25922a66..7a9abf86fc42b 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap @@ -51,7 +51,7 @@ exports[`Navigating the block hierarchy should navigate using the list view side `; exports[`Navigating the block hierarchy should select the wrapper div for a group 1`] = ` -"<!-- wp:group --> +"<!-- wp:group {\\"layout\\":{\\"type\\":\\"constrained\\"}} --> <div class=\\"wp-block-group\\"><!-- wp:paragraph --> <p>just a paragraph</p> <!-- /wp:paragraph --> diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/inserting-blocks.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/inserting-blocks.test.js.snap index aa75e5d5ef89c..42789fa855236 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/inserting-blocks.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/inserting-blocks.test.js.snap @@ -54,7 +54,7 @@ lines preserved[/myshortcode] `; exports[`Inserting blocks inserts a block in proper place after having clicked \`Browse All\` from block appender 1`] = ` -"<!-- wp:group --> +"<!-- wp:group {\\"layout\\":{\\"type\\":\\"constrained\\"}} --> <div class=\\"wp-block-group\\"><!-- wp:paragraph --> <p>Paragraph inside group</p> <!-- /wp:paragraph --></div> diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/keep-styles-on-block-transforms.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/keep-styles-on-block-transforms.test.js.snap index 14a9797eca4c3..c8ec4b42cb346 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/keep-styles-on-block-transforms.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/keep-styles-on-block-transforms.test.js.snap @@ -27,7 +27,7 @@ exports[`Keep styles on block transforms Should keep the font size during a tran `; exports[`Keep styles on block transforms Should not include styles in the group block when grouping a block 1`] = ` -"<!-- wp:group --> +"<!-- wp:group {\\"layout\\":{\\"type\\":\\"constrained\\"}} --> <div class=\\"wp-block-group\\"><!-- wp:paragraph {\\"fontSize\\":\\"large\\"} --> <p class=\\"has-large-font-size\\">Line 1 to be made large</p> <!-- /wp:paragraph --></div> diff --git a/packages/e2e-tests/specs/editor/various/block-grouping.test.js b/packages/e2e-tests/specs/editor/various/block-grouping.test.js index 7f12a9fccfeea..dd51f31016c8d 100644 --- a/packages/e2e-tests/specs/editor/various/block-grouping.test.js +++ b/packages/e2e-tests/specs/editor/various/block-grouping.test.js @@ -148,8 +148,8 @@ describe( 'Block Grouping', () => { await clickBlockToolbarButton( 'Options' ); await clickMenuItem( 'Group' ); expect( await getEditedPostContent() ).toMatchInlineSnapshot( ` - "<!-- wp:group --> - <div class=\\"wp-block-group\\"><!-- wp:group --> + "<!-- wp:group {\\"layout\\":{\\"type\\":\\"constrained\\"}} --> + <div class=\\"wp-block-group\\"><!-- wp:group {\\"layout\\":{\\"type\\":\\"constrained\\"}} --> <div class=\\"wp-block-group\\"><!-- wp:paragraph --> <p>1</p> <!-- /wp:paragraph --></div> diff --git a/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js b/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js index 79d26ada4cea4..33d7295a4ab46 100644 --- a/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js +++ b/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js @@ -356,7 +356,7 @@ describe( 'Multi-block selection', () => { await page.mouse.up(); await page.keyboard.type( 'hi' ); expect( await getEditedPostContent() ).toMatchInlineSnapshot( ` - "<!-- wp:group --> + "<!-- wp:group {\\"layout\\":{\\"type\\":\\"constrained\\"}} --> <div class=\\"wp-block-group\\"><!-- wp:paragraph --> <p>hih text in group</p> <!-- /wp:paragraph --></div> diff --git a/packages/edit-post/src/components/visual-editor/index.js b/packages/edit-post/src/components/visual-editor/index.js index 0d8614946a814..a3c910be1db4d 100644 --- a/packages/edit-post/src/components/visual-editor/index.js +++ b/packages/edit-post/src/components/visual-editor/index.js @@ -181,10 +181,12 @@ export default function VisualEditor( { styles } ) { } if ( themeSupportsLayout ) { - return defaultLayout; + // We need to ensure support for wide and full alignments, + // so we add the constrained type. + return { ...defaultLayout, type: 'constrained' }; } - - return undefined; + // Set constrained layout for classic themes so all alignments are supported. + return { type: 'constrained' }; }, [ isTemplateMode, themeSupportsLayout, defaultLayout ] ); const titleRef = useRef(); @@ -243,7 +245,7 @@ export default function VisualEditor( { styles } ) { ! isTemplateMode && ( <LayoutStyle selector=".edit-post-visual-editor__post-title-wrapper, .block-editor-block-list__layout.is-root-container" - layout={ defaultLayout } + layout={ layout } layoutDefinitions={ defaultLayout?.definitions } @@ -265,7 +267,7 @@ export default function VisualEditor( { styles } ) { className={ isTemplateMode ? 'wp-site-blocks' - : 'is-layout-flow' // Ensure root level blocks receive default/flow blockGap styling rules. + : 'is-layout-constrained' // Ensure root level blocks receive default/flow blockGap styling rules. } __experimentalLayout={ layout } /> diff --git a/packages/edit-site/src/components/global-styles/test/use-global-styles-output.js b/packages/edit-site/src/components/global-styles/test/use-global-styles-output.js index b524d041abfdd..8e8686ca4eed8 100644 --- a/packages/edit-site/src/components/global-styles/test/use-global-styles-output.js +++ b/packages/edit-site/src/components/global-styles/test/use-global-styles-output.js @@ -484,6 +484,19 @@ describe( 'global styles renderer', () => { '.has-white-color{color: var(--wp--preset--color--white) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}h1.has-blue-color,h2.has-blue-color,h3.has-blue-color,h4.has-blue-color,h5.has-blue-color,h6.has-blue-color{color: var(--wp--preset--color--blue) !important;}h1.has-blue-background-color,h2.has-blue-background-color,h3.has-blue-background-color,h4.has-blue-background-color,h5.has-blue-background-color,h6.has-blue-background-color{background-color: var(--wp--preset--color--blue) !important;}h1.has-blue-border-color,h2.has-blue-border-color,h3.has-blue-border-color,h4.has-blue-border-color,h5.has-blue-border-color,h6.has-blue-border-color{border-color: var(--wp--preset--color--blue) !important;}' ); } ); + it( 'should output content and wide size variables if values are specified', () => { + const tree = { + settings: { + layout: { + contentSize: '840px', + wideSize: '1100px', + }, + }, + }; + expect( toStyles( tree, 'body' ) ).toEqual( + 'body {margin: 0; --wp--style--global--content-size: 840px; --wp--style--global--wide-size: 1100px;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }' + ); + } ); } ); describe( 'getLayoutStyles', () => { diff --git a/packages/edit-site/src/components/global-styles/use-global-styles-output.js b/packages/edit-site/src/components/global-styles/use-global-styles-output.js index ca8ed71c2fd08..16f2dacba411f 100644 --- a/packages/edit-site/src/components/global-styles/use-global-styles-output.js +++ b/packages/edit-site/src/components/global-styles/use-global-styles-output.js @@ -580,6 +580,7 @@ export const toStyles = ( const nodesWithStyles = getNodesWithStyles( tree, blockSelectors ); const nodesWithSettings = getNodesWithSettings( tree, blockSelectors ); const useRootPaddingAlign = tree?.settings?.useRootPaddingAwareAlignments; + const { contentSize, wideSize } = tree?.settings?.layout || {}; /* * Reset default browser margin on the root body element. @@ -589,13 +590,23 @@ export const toStyles = ( * user-generated values take precedence in the CSS cascade. * @link https://github.com/WordPress/gutenberg/issues/36147. */ - let ruleset = 'body {margin: 0;}'; + let ruleset = 'body {margin: 0;'; + + if ( contentSize ) { + ruleset += ` --wp--style--global--content-size: ${ contentSize };`; + } + + if ( wideSize ) { + ruleset += ` --wp--style--global--wide-size: ${ wideSize };`; + } if ( useRootPaddingAlign ) { - ruleset = - 'body { margin: 0; padding-right: 0; padding-left: 0; padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom) } .has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); } .has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); } .has-global-padding > .alignfull > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; + ruleset += + 'padding-right: 0; padding-left: 0; padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom) } .has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); } .has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); } .has-global-padding > .alignfull > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left);'; } + ruleset += '}'; + nodesWithStyles.forEach( ( { selector, diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 993675fd4d4fd..31e86ef79beec 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -35,7 +35,7 @@ public function test_get_stylesheet_generates_layout_styles( $layout_definitions // Results also include root site blocks styles. $this->assertEquals( - 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: 1em; }body { --wp--style--block-gap: 1em; }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: 1em;margin-block-end: 0;}body .is-layout-flex{gap: 1em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}', + 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: 1em; }body { --wp--style--block-gap: 1em; }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: 1em;margin-block-end: 0;}body .is-layout-flex{gap: 1em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}', $theme_json->get_stylesheet( array( 'styles' ) ) ); } @@ -68,7 +68,7 @@ public function test_get_stylesheet_generates_layout_styles_with_spacing_presets // Results also include root site blocks styles. $this->assertEquals( - 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var(--wp--preset--spacing--60); }body { --wp--style--block-gap: var(--wp--preset--spacing--60); }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}body .is-layout-flex{gap: var(--wp--preset--spacing--60);}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}', + 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var(--wp--preset--spacing--60); }body { --wp--style--block-gap: var(--wp--preset--spacing--60); }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}body .is-layout-flex{gap: var(--wp--preset--spacing--60);}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}', $theme_json->get_stylesheet( array( 'styles' ) ) ); } @@ -102,7 +102,7 @@ public function test_get_stylesheet_generates_fallback_gap_layout_styles( $layou // Results also include root site blocks styles. $this->assertEquals( - 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}', + 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}', $stylesheet ); } @@ -282,7 +282,7 @@ function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors() { ) ); - $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $base_styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; $element_styles = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}a:where(:not(.wp-element-button)):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:where(:not(.wp-element-button)):focus{background-color: black;color: yellow;}'; @@ -321,7 +321,7 @@ function test_get_stylesheet_handles_only_pseudo_selector_rules_for_given_proper ) ); - $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $base_styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; $element_styles = 'a:where(:not(.wp-element-button)):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:where(:not(.wp-element-button)):focus{background-color: black;color: yellow;}'; @@ -360,7 +360,7 @@ function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_element ) ); - $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $base_styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; $element_styles = 'h4{background-color: red;color: green;}'; @@ -399,7 +399,7 @@ function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() { ) ); - $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $base_styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; $element_styles = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}a:where(:not(.wp-element-button)):hover{background-color: green;color: red;}'; @@ -447,7 +447,7 @@ function test_get_stylesheet_handles_priority_of_elements_vs_block_elements_pseu ) ); - $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $base_styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; $element_styles = '.wp-block-group a:where(:not(.wp-element-button)){background-color: red;color: green;}.wp-block-group a:where(:not(.wp-element-button)):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}.wp-block-group a:where(:not(.wp-element-button)):focus{background-color: black;color: yellow;}'; @@ -494,7 +494,7 @@ function test_get_stylesheet_handles_whitelisted_block_level_element_pseudo_sele ) ); - $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $base_styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; $element_styles = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}a:where(:not(.wp-element-button)):hover{background-color: green;color: red;}.wp-block-group a:where(:not(.wp-element-button)):hover{background-color: black;color: yellow;}'; @@ -557,7 +557,7 @@ function test_get_stylesheet_with_block_support_feature_level_selectors() { ) ); - $base_styles = 'body{--wp--preset--color--green: green;}body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $base_styles = 'body{--wp--preset--color--green: green;}body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; $block_styles = '.wp-block-test, .wp-block-test__wrapper{color: green;}.wp-block-test .inner, .wp-block-test__wrapper .inner{border-radius: 9999px;padding: 20px;}.wp-block-test .sub-heading, .wp-block-test__wrapper .sub-heading{font-size: 3em;}'; $preset_styles = '.has-green-color{color: var(--wp--preset--color--green) !important;}.has-green-background-color{background-color: var(--wp--preset--color--green) !important;}.has-green-border-color{border-color: var(--wp--preset--color--green) !important;}'; $expected = $base_styles . $block_styles . $preset_styles; @@ -651,7 +651,7 @@ function test_get_property_value_valid() { ) ); - $expected = 'body { margin: 0; }body{background-color: #ffffff;color: #000000;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{background-color: #000000;color: #ffffff;}'; + $expected = 'body{background-color: #ffffff;color: #000000;}body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{background-color: #000000;color: #ffffff;}'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); } @@ -683,7 +683,7 @@ function test_get_property_value_loop() { ) ); - $expected = 'body { margin: 0; }body{background-color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{color: #ffffff;}'; + $expected = 'body{background-color: #ffffff;}body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{color: #ffffff;}'; $this->assertSame( $expected, $theme_json->get_stylesheet() ); } @@ -714,7 +714,7 @@ function test_get_property_value_recursion() { ) ); - $expected = 'body { margin: 0; }body{background-color: #ffffff;color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{color: #ffffff;}'; + $expected = 'body{background-color: #ffffff;color: #ffffff;}body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{color: #ffffff;}'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); } @@ -737,7 +737,7 @@ function test_get_property_value_self() { ) ); - $expected = 'body { margin: 0; }body{background-color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $expected = 'body{background-color: #ffffff;}body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); } @@ -1095,7 +1095,7 @@ function test_get_styles_for_block_with_padding_aware_alignments() { 'selector' => 'body', ); - $expected = 'body { margin: 0; }body{--wp--style--root--padding-top: 10px;--wp--style--root--padding-right: 12px;--wp--style--root--padding-bottom: 10px;--wp--style--root--padding-left: 12px;}.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }.has-global-padding > .alignfull > :where([class*="wp-block-"]:not(.alignfull):not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $expected = 'body{--wp--style--root--padding-top: 10px;--wp--style--root--padding-right: 12px;--wp--style--root--padding-bottom: 10px;--wp--style--root--padding-left: 12px;}body { margin: 0;}.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }.has-global-padding > .alignfull > :where([class*="wp-block-"]:not(.alignfull):not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; $this->assertEquals( $expected, $theme_json->get_styles_for_block( $metadata ) ); } @@ -1123,7 +1123,31 @@ function test_get_styles_for_block_without_padding_aware_alignments() { 'selector' => 'body', ); - $expected = 'body { margin: 0; }body{padding-top: 10px;padding-right: 12px;padding-bottom: 10px;padding-left: 12px;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $expected = 'body{padding-top: 10px;padding-right: 12px;padding-bottom: 10px;padding-left: 12px;}body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $this->assertEquals( $expected, $theme_json->get_styles_for_block( $metadata ) ); + } + + function test_get_styles_for_block_with_content_width() { + $theme_json = new WP_Theme_JSON_Gutenberg( + array( + 'version' => 2, + 'settings' => array( + 'layout' => array( + 'contentSize' => '800px', + 'wideSize' => '1000px', + ), + ), + ) + ); + + $metadata = array( + 'path' => array( + '0' => 'settings', + ), + 'selector' => 'body', + ); + + $expected = 'body { margin: 0;--wp--style--global--content-size: 800px;--wp--style--global--wide-size: 1000px;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; $this->assertEquals( $expected, $theme_json->get_styles_for_block( $metadata ) ); } } diff --git a/test/e2e/specs/editor/blocks/__snapshots__/Group-can-be-created-using-the-block-inserter-1-chromium.txt b/test/e2e/specs/editor/blocks/__snapshots__/Group-can-be-created-using-the-block-inserter-1-chromium.txt index 44774b1bf7680..d98255c8f1b6a 100644 --- a/test/e2e/specs/editor/blocks/__snapshots__/Group-can-be-created-using-the-block-inserter-1-chromium.txt +++ b/test/e2e/specs/editor/blocks/__snapshots__/Group-can-be-created-using-the-block-inserter-1-chromium.txt @@ -1,3 +1,3 @@ -<!-- wp:group --> +<!-- wp:group {"layout":{"type":"constrained"}} --> <div class="wp-block-group"></div> <!-- /wp:group --> \ No newline at end of file diff --git a/test/e2e/specs/editor/blocks/__snapshots__/Group-can-be-created-using-the-slash-inserter-1-chromium.txt b/test/e2e/specs/editor/blocks/__snapshots__/Group-can-be-created-using-the-slash-inserter-1-chromium.txt index 44774b1bf7680..d98255c8f1b6a 100644 --- a/test/e2e/specs/editor/blocks/__snapshots__/Group-can-be-created-using-the-slash-inserter-1-chromium.txt +++ b/test/e2e/specs/editor/blocks/__snapshots__/Group-can-be-created-using-the-slash-inserter-1-chromium.txt @@ -1,3 +1,3 @@ -<!-- wp:group --> +<!-- wp:group {"layout":{"type":"constrained"}} --> <div class="wp-block-group"></div> <!-- /wp:group --> \ No newline at end of file diff --git a/test/e2e/specs/editor/blocks/__snapshots__/Group-can-have-other-blocks-appended-to-it-using-the-button-appender-1-chromium.txt b/test/e2e/specs/editor/blocks/__snapshots__/Group-can-have-other-blocks-appended-to-it-using-the-button-appender-1-chromium.txt index 09839ec996353..64b6642785081 100644 --- a/test/e2e/specs/editor/blocks/__snapshots__/Group-can-have-other-blocks-appended-to-it-using-the-button-appender-1-chromium.txt +++ b/test/e2e/specs/editor/blocks/__snapshots__/Group-can-have-other-blocks-appended-to-it-using-the-button-appender-1-chromium.txt @@ -1,4 +1,4 @@ -<!-- wp:group --> +<!-- wp:group {"layout":{"type":"constrained"}} --> <div class="wp-block-group"><!-- wp:paragraph --> <p>Group Block with a Paragraph</p> <!-- /wp:paragraph --></div> diff --git a/test/e2e/specs/editor/blocks/__snapshots__/Group-can-merge-into-group-with-Backspace-1-chromium.txt b/test/e2e/specs/editor/blocks/__snapshots__/Group-can-merge-into-group-with-Backspace-1-chromium.txt index 11f6c1766c3d1..a7a6267ccc392 100644 --- a/test/e2e/specs/editor/blocks/__snapshots__/Group-can-merge-into-group-with-Backspace-1-chromium.txt +++ b/test/e2e/specs/editor/blocks/__snapshots__/Group-can-merge-into-group-with-Backspace-1-chromium.txt @@ -1,4 +1,4 @@ -<!-- wp:group --> +<!-- wp:group {"layout":{"type":"constrained"}} --> <div class="wp-block-group"><!-- wp:paragraph --> <p>1</p> <!-- /wp:paragraph --></div> diff --git a/test/e2e/specs/editor/blocks/__snapshots__/Group-can-merge-into-group-with-Backspace-2-chromium.txt b/test/e2e/specs/editor/blocks/__snapshots__/Group-can-merge-into-group-with-Backspace-2-chromium.txt index b7bf710d8b9e9..d3ea494878214 100644 --- a/test/e2e/specs/editor/blocks/__snapshots__/Group-can-merge-into-group-with-Backspace-2-chromium.txt +++ b/test/e2e/specs/editor/blocks/__snapshots__/Group-can-merge-into-group-with-Backspace-2-chromium.txt @@ -1,4 +1,4 @@ -<!-- wp:group --> +<!-- wp:group {"layout":{"type":"constrained"}} --> <div class="wp-block-group"><!-- wp:paragraph --> <p>1</p> <!-- /wp:paragraph --> diff --git a/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-can-copy-group-onto-non-textual-element-image-spacer-1-chromium.txt b/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-can-copy-group-onto-non-textual-element-image-spacer-1-chromium.txt index 201bddd839014..ff0c2245d9394 100644 --- a/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-can-copy-group-onto-non-textual-element-image-spacer-1-chromium.txt +++ b/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-can-copy-group-onto-non-textual-element-image-spacer-1-chromium.txt @@ -2,8 +2,8 @@ <p></p> <!-- /wp:paragraph --> -<!-- wp:group --> -<div class="wp-block-group"><!-- wp:paragraph --> -<p>P</p> -<!-- /wp:paragraph --></div> -<!-- /wp:group --> \ No newline at end of file +<!-- wp:buttons --> +<div class="wp-block-buttons"><!-- wp:button --> +<div class="wp-block-button"><a class="wp-block-button__link wp-element-button">Click</a></div> +<!-- /wp:button --></div> +<!-- /wp:buttons --> \ No newline at end of file diff --git a/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-handle-paste-events-once-1-chromium.txt b/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-handle-paste-events-once-1-chromium.txt index 201bddd839014..ff0c2245d9394 100644 --- a/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-handle-paste-events-once-1-chromium.txt +++ b/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-handle-paste-events-once-1-chromium.txt @@ -2,8 +2,8 @@ <p></p> <!-- /wp:paragraph --> -<!-- wp:group --> -<div class="wp-block-group"><!-- wp:paragraph --> -<p>P</p> -<!-- /wp:paragraph --></div> -<!-- /wp:group --> \ No newline at end of file +<!-- wp:buttons --> +<div class="wp-block-buttons"><!-- wp:button --> +<div class="wp-block-button"><a class="wp-block-button__link wp-element-button">Click</a></div> +<!-- /wp:button --></div> +<!-- /wp:buttons --> \ No newline at end of file diff --git a/test/e2e/specs/editor/various/copy-cut-paste.spec.js b/test/e2e/specs/editor/various/copy-cut-paste.spec.js index 3c1ecad1a9da1..c7041a8634e32 100644 --- a/test/e2e/specs/editor/various/copy-cut-paste.spec.js +++ b/test/e2e/specs/editor/various/copy-cut-paste.spec.js @@ -134,11 +134,11 @@ test.describe( 'Copy/cut/paste', () => { } ) => { // Add group block with paragraph. await editor.insertBlock( { - name: 'core/group', + name: 'core/buttons', innerBlocks: [ { - name: 'core/paragraph', - attributes: { content: 'P' }, + name: 'core/button', + attributes: { text: 'Click' }, }, ], } ); @@ -188,11 +188,11 @@ test.describe( 'Copy/cut/paste', () => { } ) => { // Add group block with paragraph. await editor.insertBlock( { - name: 'core/group', + name: 'core/buttons', innerBlocks: [ { - name: 'core/paragraph', - attributes: { content: 'P' }, + name: 'core/button', + attributes: { text: 'Click' }, }, ], } ); diff --git a/test/integration/fixtures/blocks/core__comments.json b/test/integration/fixtures/blocks/core__comments.json index 1ea7dcae007f6..3eacd7349eda8 100644 --- a/test/integration/fixtures/blocks/core__comments.json +++ b/test/integration/fixtures/blocks/core__comments.json @@ -74,6 +74,9 @@ "isValid": true, "attributes": { "tagName": "div", + "layout": { + "type": "flex" + }, "style": { "spacing": { "margin": { @@ -81,9 +84,6 @@ "bottom": "0px" } } - }, - "layout": { - "type": "flex" } }, "innerBlocks": [ diff --git a/test/integration/fixtures/blocks/core__comments.serialized.html b/test/integration/fixtures/blocks/core__comments.serialized.html index 6a4e6c09df37d..dc37e5ec93370 100644 --- a/test/integration/fixtures/blocks/core__comments.serialized.html +++ b/test/integration/fixtures/blocks/core__comments.serialized.html @@ -10,7 +10,7 @@ <!-- wp:column --> <div class="wp-block-column"><!-- wp:comment-author-name {"fontSize":"small"} /--> -<!-- wp:group {"style":{"spacing":{"margin":{"top":"0px","bottom":"0px"}}},"layout":{"type":"flex"}} --> +<!-- wp:group {"layout":{"type":"flex"},"style":{"spacing":{"margin":{"top":"0px","bottom":"0px"}}}} --> <div class="wp-block-group" style="margin-top:0px;margin-bottom:0px"><!-- wp:comment-date {"fontSize":"small"} /--> <!-- wp:comment-edit-link {"fontSize":"small"} /--></div> diff --git a/test/integration/fixtures/blocks/core__comments__deprecated-1.json b/test/integration/fixtures/blocks/core__comments__deprecated-1.json index ff97b76a5f383..abde5c6008aa8 100644 --- a/test/integration/fixtures/blocks/core__comments__deprecated-1.json +++ b/test/integration/fixtures/blocks/core__comments__deprecated-1.json @@ -74,6 +74,9 @@ "isValid": true, "attributes": { "tagName": "div", + "layout": { + "type": "flex" + }, "style": { "spacing": { "margin": { @@ -81,9 +84,6 @@ "bottom": "0px" } } - }, - "layout": { - "type": "flex" } }, "innerBlocks": [ diff --git a/test/integration/fixtures/blocks/core__comments__deprecated-1.serialized.html b/test/integration/fixtures/blocks/core__comments__deprecated-1.serialized.html index 33d5b11b2b9e0..9cf437715f0f7 100644 --- a/test/integration/fixtures/blocks/core__comments__deprecated-1.serialized.html +++ b/test/integration/fixtures/blocks/core__comments__deprecated-1.serialized.html @@ -10,7 +10,7 @@ <!-- wp:column --> <div class="wp-block-column"><!-- wp:comment-author-name {"fontSize":"small"} /--> -<!-- wp:group {"style":{"spacing":{"margin":{"top":"0px","bottom":"0px"}}},"layout":{"type":"flex"}} --> +<!-- wp:group {"layout":{"type":"flex"},"style":{"spacing":{"margin":{"top":"0px","bottom":"0px"}}}} --> <div class="wp-block-group" style="margin-top:0px;margin-bottom:0px"><!-- wp:comment-date {"fontSize":"small"} /--> <!-- wp:comment-edit-link {"fontSize":"small"} /--></div> diff --git a/test/integration/fixtures/blocks/core__group-layout-content-size.html b/test/integration/fixtures/blocks/core__group-layout-content-size.html new file mode 100644 index 0000000000000..40c7086854dc0 --- /dev/null +++ b/test/integration/fixtures/blocks/core__group-layout-content-size.html @@ -0,0 +1,11 @@ +<!-- wp:group {"align":"full","backgroundColor":"secondary","layout":{"type":"constrained"}} --> +<div class="wp-block-group alignfull has-secondary-background-color has-background"> + <!-- wp:paragraph --> + <p>This is a group block.</p> + <!-- /wp:paragraph --> + + <!-- wp:paragraph --> + <p>Group block content.</p> + <!-- /wp:paragraph --> +</div> +<!-- /wp:group --> \ No newline at end of file diff --git a/test/integration/fixtures/blocks/core__group-layout-content-size.json b/test/integration/fixtures/blocks/core__group-layout-content-size.json new file mode 100644 index 0000000000000..8bc6a699a3b99 --- /dev/null +++ b/test/integration/fixtures/blocks/core__group-layout-content-size.json @@ -0,0 +1,34 @@ +[ + { + "name": "core/group", + "isValid": true, + "attributes": { + "tagName": "div", + "layout": { + "type": "constrained" + }, + "align": "full", + "backgroundColor": "secondary" + }, + "innerBlocks": [ + { + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "This is a group block.", + "dropCap": false + }, + "innerBlocks": [] + }, + { + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "Group block content.", + "dropCap": false + }, + "innerBlocks": [] + } + ] + } +] diff --git a/test/integration/fixtures/blocks/core__group-layout-content-size.parsed.json b/test/integration/fixtures/blocks/core__group-layout-content-size.parsed.json new file mode 100644 index 0000000000000..70d856933edb2 --- /dev/null +++ b/test/integration/fixtures/blocks/core__group-layout-content-size.parsed.json @@ -0,0 +1,36 @@ +[ + { + "blockName": "core/group", + "attrs": { + "align": "full", + "backgroundColor": "secondary", + "layout": { + "type": "constrained" + } + }, + "innerBlocks": [ + { + "blockName": "core/paragraph", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n\t<p>This is a group block.</p>\n\t", + "innerContent": [ "\n\t<p>This is a group block.</p>\n\t" ] + }, + { + "blockName": "core/paragraph", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n\t<p>Group block content.</p>\n\t", + "innerContent": [ "\n\t<p>Group block content.</p>\n\t" ] + } + ], + "innerHTML": "\n<div class=\"wp-block-group alignfull has-secondary-background-color has-background\">\n\t\n\n\t\n</div>\n", + "innerContent": [ + "\n<div class=\"wp-block-group alignfull has-secondary-background-color has-background\">\n\t", + null, + "\n\n\t", + null, + "\n</div>\n" + ] + } +] diff --git a/test/integration/fixtures/blocks/core__group-layout-content-size.serialized.html b/test/integration/fixtures/blocks/core__group-layout-content-size.serialized.html new file mode 100644 index 0000000000000..d75a5324df28f --- /dev/null +++ b/test/integration/fixtures/blocks/core__group-layout-content-size.serialized.html @@ -0,0 +1,9 @@ +<!-- wp:group {"layout":{"type":"constrained"},"align":"full","backgroundColor":"secondary"} --> +<div class="wp-block-group alignfull has-secondary-background-color has-background"><!-- wp:paragraph --> +<p>This is a group block.</p> +<!-- /wp:paragraph --> + +<!-- wp:paragraph --> +<p>Group block content.</p> +<!-- /wp:paragraph --></div> +<!-- /wp:group --> diff --git a/test/integration/fixtures/blocks/core__group-layout-content-size__deprecated.html b/test/integration/fixtures/blocks/core__group-layout-content-size__deprecated.html new file mode 100644 index 0000000000000..d09dc3afbbd58 --- /dev/null +++ b/test/integration/fixtures/blocks/core__group-layout-content-size__deprecated.html @@ -0,0 +1,11 @@ +<!-- wp:group {"align":"full","backgroundColor":"secondary","layout":{"inherit":true}} --> +<div class="wp-block-group alignfull has-secondary-background-color has-background"> + <!-- wp:paragraph --> + <p>This is a group block.</p> + <!-- /wp:paragraph --> + + <!-- wp:paragraph --> + <p>Group block content.</p> + <!-- /wp:paragraph --> +</div> +<!-- /wp:group --> \ No newline at end of file diff --git a/test/integration/fixtures/blocks/core__group-layout-content-size__deprecated.json b/test/integration/fixtures/blocks/core__group-layout-content-size__deprecated.json new file mode 100644 index 0000000000000..152c3e1750778 --- /dev/null +++ b/test/integration/fixtures/blocks/core__group-layout-content-size__deprecated.json @@ -0,0 +1,35 @@ +[ + { + "name": "core/group", + "isValid": true, + "attributes": { + "tagName": "div", + "align": "full", + "backgroundColor": "secondary", + "layout": { + "inherit": true, + "type": "constrained" + } + }, + "innerBlocks": [ + { + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "This is a group block.", + "dropCap": false + }, + "innerBlocks": [] + }, + { + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "Group block content.", + "dropCap": false + }, + "innerBlocks": [] + } + ] + } +] diff --git a/test/integration/fixtures/blocks/core__group-layout-content-size__deprecated.parsed.json b/test/integration/fixtures/blocks/core__group-layout-content-size__deprecated.parsed.json new file mode 100644 index 0000000000000..e3dbea323bded --- /dev/null +++ b/test/integration/fixtures/blocks/core__group-layout-content-size__deprecated.parsed.json @@ -0,0 +1,36 @@ +[ + { + "blockName": "core/group", + "attrs": { + "align": "full", + "backgroundColor": "secondary", + "layout": { + "inherit": true + } + }, + "innerBlocks": [ + { + "blockName": "core/paragraph", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n\t<p>This is a group block.</p>\n\t", + "innerContent": [ "\n\t<p>This is a group block.</p>\n\t" ] + }, + { + "blockName": "core/paragraph", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n\t<p>Group block content.</p>\n\t", + "innerContent": [ "\n\t<p>Group block content.</p>\n\t" ] + } + ], + "innerHTML": "\n<div class=\"wp-block-group alignfull has-secondary-background-color has-background\">\n\t\n\n\t\n</div>\n", + "innerContent": [ + "\n<div class=\"wp-block-group alignfull has-secondary-background-color has-background\">\n\t", + null, + "\n\n\t", + null, + "\n</div>\n" + ] + } +] diff --git a/test/integration/fixtures/blocks/core__group-layout-content-size__deprecated.serialized.html b/test/integration/fixtures/blocks/core__group-layout-content-size__deprecated.serialized.html new file mode 100644 index 0000000000000..11749e1e2cfac --- /dev/null +++ b/test/integration/fixtures/blocks/core__group-layout-content-size__deprecated.serialized.html @@ -0,0 +1,9 @@ +<!-- wp:group {"layout":{"inherit":true,"type":"constrained"},"align":"full","backgroundColor":"secondary"} --> +<div class="wp-block-group alignfull has-secondary-background-color has-background"><!-- wp:paragraph --> +<p>This is a group block.</p> +<!-- /wp:paragraph --> + +<!-- wp:paragraph --> +<p>Group block content.</p> +<!-- /wp:paragraph --></div> +<!-- /wp:group --> diff --git a/test/integration/fixtures/blocks/core__group.html b/test/integration/fixtures/blocks/core__group.html index df7eef39e3898..72241dc5c83f3 100644 --- a/test/integration/fixtures/blocks/core__group.html +++ b/test/integration/fixtures/blocks/core__group.html @@ -1,9 +1,11 @@ -<!-- wp:group {"align":"full","backgroundColor":"secondary"} --> -<div class="wp-block-group alignfull has-secondary-background-color has-background"><!-- wp:paragraph --> -<p>This is a group block.</p> -<!-- /wp:paragraph --> +<!-- wp:group {"align":"full","backgroundColor":"secondary","layout":{"type":"default"}} --> +<div class="wp-block-group alignfull has-secondary-background-color has-background"> + <!-- wp:paragraph --> + <p>This is a group block.</p> + <!-- /wp:paragraph --> -<!-- wp:paragraph --> -<p>Group block content.</p> -<!-- /wp:paragraph --></div> -<!-- /wp:group --> + <!-- wp:paragraph --> + <p>Group block content.</p> + <!-- /wp:paragraph --> + </div> + <!-- /wp:group --> \ No newline at end of file diff --git a/test/integration/fixtures/blocks/core__group.json b/test/integration/fixtures/blocks/core__group.json index 2582fe6b87c4e..3d2cc933d7957 100644 --- a/test/integration/fixtures/blocks/core__group.json +++ b/test/integration/fixtures/blocks/core__group.json @@ -4,6 +4,9 @@ "isValid": true, "attributes": { "tagName": "div", + "layout": { + "type": "default" + }, "align": "full", "backgroundColor": "secondary" }, diff --git a/test/integration/fixtures/blocks/core__group.parsed.json b/test/integration/fixtures/blocks/core__group.parsed.json index fcfcf54234c0f..86a14e755531e 100644 --- a/test/integration/fixtures/blocks/core__group.parsed.json +++ b/test/integration/fixtures/blocks/core__group.parsed.json @@ -3,31 +3,34 @@ "blockName": "core/group", "attrs": { "align": "full", - "backgroundColor": "secondary" + "backgroundColor": "secondary", + "layout": { + "type": "default" + } }, "innerBlocks": [ { "blockName": "core/paragraph", "attrs": {}, "innerBlocks": [], - "innerHTML": "\n<p>This is a group block.</p>\n", - "innerContent": [ "\n<p>This is a group block.</p>\n" ] + "innerHTML": "\n\t<p>This is a group block.</p>\n\t", + "innerContent": [ "\n\t<p>This is a group block.</p>\n\t" ] }, { "blockName": "core/paragraph", "attrs": {}, "innerBlocks": [], - "innerHTML": "\n<p>Group block content.</p>\n", - "innerContent": [ "\n<p>Group block content.</p>\n" ] + "innerHTML": "\n\t<p>Group block content.</p>\n\t", + "innerContent": [ "\n\t<p>Group block content.</p>\n\t" ] } ], - "innerHTML": "\n<div class=\"wp-block-group alignfull has-secondary-background-color has-background\">\n\n</div>\n", + "innerHTML": "\n<div class=\"wp-block-group alignfull has-secondary-background-color has-background\">\n\t\n\n\t\n\t</div>\n\t", "innerContent": [ - "\n<div class=\"wp-block-group alignfull has-secondary-background-color has-background\">", + "\n<div class=\"wp-block-group alignfull has-secondary-background-color has-background\">\n\t", null, - "\n\n", + "\n\n\t", null, - "</div>\n" + "\n\t</div>\n\t" ] } ] diff --git a/test/integration/fixtures/blocks/core__group.serialized.html b/test/integration/fixtures/blocks/core__group.serialized.html index df7eef39e3898..06deee1387809 100644 --- a/test/integration/fixtures/blocks/core__group.serialized.html +++ b/test/integration/fixtures/blocks/core__group.serialized.html @@ -1,4 +1,4 @@ -<!-- wp:group {"align":"full","backgroundColor":"secondary"} --> +<!-- wp:group {"layout":{"type":"default"},"align":"full","backgroundColor":"secondary"} --> <div class="wp-block-group alignfull has-secondary-background-color has-background"><!-- wp:paragraph --> <p>This is a group block.</p> <!-- /wp:paragraph --> diff --git a/test/integration/fixtures/blocks/core__group__deprecated-3.html b/test/integration/fixtures/blocks/core__group__deprecated-3.html new file mode 100644 index 0000000000000..df7eef39e3898 --- /dev/null +++ b/test/integration/fixtures/blocks/core__group__deprecated-3.html @@ -0,0 +1,9 @@ +<!-- wp:group {"align":"full","backgroundColor":"secondary"} --> +<div class="wp-block-group alignfull has-secondary-background-color has-background"><!-- wp:paragraph --> +<p>This is a group block.</p> +<!-- /wp:paragraph --> + +<!-- wp:paragraph --> +<p>Group block content.</p> +<!-- /wp:paragraph --></div> +<!-- /wp:group --> diff --git a/test/integration/fixtures/blocks/core__group__deprecated-3.json b/test/integration/fixtures/blocks/core__group__deprecated-3.json new file mode 100644 index 0000000000000..2582fe6b87c4e --- /dev/null +++ b/test/integration/fixtures/blocks/core__group__deprecated-3.json @@ -0,0 +1,31 @@ +[ + { + "name": "core/group", + "isValid": true, + "attributes": { + "tagName": "div", + "align": "full", + "backgroundColor": "secondary" + }, + "innerBlocks": [ + { + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "This is a group block.", + "dropCap": false + }, + "innerBlocks": [] + }, + { + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "Group block content.", + "dropCap": false + }, + "innerBlocks": [] + } + ] + } +] diff --git a/test/integration/fixtures/blocks/core__group__deprecated-3.parsed.json b/test/integration/fixtures/blocks/core__group__deprecated-3.parsed.json new file mode 100644 index 0000000000000..fcfcf54234c0f --- /dev/null +++ b/test/integration/fixtures/blocks/core__group__deprecated-3.parsed.json @@ -0,0 +1,33 @@ +[ + { + "blockName": "core/group", + "attrs": { + "align": "full", + "backgroundColor": "secondary" + }, + "innerBlocks": [ + { + "blockName": "core/paragraph", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n<p>This is a group block.</p>\n", + "innerContent": [ "\n<p>This is a group block.</p>\n" ] + }, + { + "blockName": "core/paragraph", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n<p>Group block content.</p>\n", + "innerContent": [ "\n<p>Group block content.</p>\n" ] + } + ], + "innerHTML": "\n<div class=\"wp-block-group alignfull has-secondary-background-color has-background\">\n\n</div>\n", + "innerContent": [ + "\n<div class=\"wp-block-group alignfull has-secondary-background-color has-background\">", + null, + "\n\n", + null, + "</div>\n" + ] + } +] diff --git a/test/integration/fixtures/blocks/core__group__deprecated-3.serialized.html b/test/integration/fixtures/blocks/core__group__deprecated-3.serialized.html new file mode 100644 index 0000000000000..df7eef39e3898 --- /dev/null +++ b/test/integration/fixtures/blocks/core__group__deprecated-3.serialized.html @@ -0,0 +1,9 @@ +<!-- wp:group {"align":"full","backgroundColor":"secondary"} --> +<div class="wp-block-group alignfull has-secondary-background-color has-background"><!-- wp:paragraph --> +<p>This is a group block.</p> +<!-- /wp:paragraph --> + +<!-- wp:paragraph --> +<p>Group block content.</p> +<!-- /wp:paragraph --></div> +<!-- /wp:group -->