diff --git a/package-lock.json b/package-lock.json index c88a8110f32830..a4660b08d53c13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45216,6 +45216,7 @@ "@wordpress/dom": "file:../dom", "@wordpress/element": "file:../element", "@wordpress/escape-html": "file:../escape-html", + "@wordpress/global-styles-engine": "file:../global-styles-engine", "@wordpress/hooks": "file:../hooks", "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", diff --git a/packages/block-library/package.json b/packages/block-library/package.json index a224510b32422d..fa560e8e14de56 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -108,6 +108,7 @@ "@wordpress/dom": "file:../dom", "@wordpress/element": "file:../element", "@wordpress/escape-html": "file:../escape-html", + "@wordpress/global-styles-engine": "file:../global-styles-engine", "@wordpress/hooks": "file:../hooks", "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", diff --git a/packages/block-library/src/gallery/README.md b/packages/block-library/src/gallery/README.md index 165ba870be28bf..7a09359acaba2f 100644 --- a/packages/block-library/src/gallery/README.md +++ b/packages/block-library/src/gallery/README.md @@ -47,7 +47,7 @@ _Defined via the [`supports`](https://developer.wordpress.org/block-editor/refer - [`spacing`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#spacing): - `margin`: `true` - `padding`: `true` - - `blockGap`: `["horizontal","vertical"]` + - `blockGap`: `{"sides":["horizontal","vertical"],"__experimentalDefault":"var( --wp--style--gallery-gap-default, var( --gallery-block--gutter-size, var( --wp--style--block-gap, 0.5em ) ) )"}` - [`color`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#color): - [`text`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#color-text): `false` - [`background`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#color-background): `true` diff --git a/packages/block-library/src/gallery/block.json b/packages/block-library/src/gallery/block.json index 0d63ad7332b480..1c539217579189 100644 --- a/packages/block-library/src/gallery/block.json +++ b/packages/block-library/src/gallery/block.json @@ -142,8 +142,10 @@ "spacing": { "margin": true, "padding": true, - "blockGap": [ "horizontal", "vertical" ], - "__experimentalSkipSerialization": [ "blockGap" ], + "blockGap": { + "sides": [ "horizontal", "vertical" ], + "__experimentalDefault": "var( --wp--style--gallery-gap-default, var( --gallery-block--gutter-size, var( --wp--style--block-gap, 0.5em ) ) )" + }, "__experimentalDefaultControls": { "blockGap": true, "margin": false, diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 9d98022490e17b..d892b53e90a701 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -66,7 +66,7 @@ import { import useImageSizes from './use-image-sizes'; import useGetNewImages from './use-get-new-images'; import useGetMedia from './use-get-media'; -import GapStyles from './gap-styles'; +import GalleryGapCustomProperties from './gap-styles'; import useDynamicGallery from './use-dynamic-gallery'; import { GallerySourcePanel, GalleryDynamicView } from './dynamic-gallery'; import { getDynamicSource, ATTACHED_MEDIA } from './dynamic-source'; @@ -941,8 +941,8 @@ export default function GalleryEdit( props ) { /> ) } - diff --git a/packages/block-library/src/gallery/gap-styles.js b/packages/block-library/src/gallery/gap-styles.js index a1ad61f02b9955..b56987139e9050 100644 --- a/packages/block-library/src/gallery/gap-styles.js +++ b/packages/block-library/src/gallery/gap-styles.js @@ -4,34 +4,57 @@ import { __experimentalGetGapCSSValue as getGapCSSValue, useStyleOverride, + useSettings, } from '@wordpress/block-editor'; +import { privateApis as globalStylesEnginePrivateApis } from '@wordpress/global-styles-engine'; -export default function GapStyles( { blockGap, clientId } ) { - // --gallery-block--gutter-size is deprecated. --wp--style--gallery-gap-default should be used by themes that want to set a default - // gap on the gallery. - const fallbackValue = `var( --wp--style--gallery-gap-default, var( --gallery-block--gutter-size, var( --wp--style--block-gap, 0.5em ) ) )`; - let gapValue = fallbackValue; - let column = fallbackValue; - let row; - - // Check for the possibility of split block gap values. See: https://github.com/WordPress/gutenberg/pull/37736 - if ( !! blockGap ) { - row = - typeof blockGap === 'string' - ? getGapCSSValue( blockGap ) - : getGapCSSValue( blockGap?.top ) || fallbackValue; +/** + * Internal dependencies + */ +import { unlock } from '../lock-unlock'; + +const { getResponsiveMediaQueries } = unlock( globalStylesEnginePrivateApis ); + +// --gallery-block--gutter-size is deprecated. --wp--style--gallery-gap-default should be used by themes that want to set a default +// gap on the gallery. +const FALLBACK_VALUE = `var( --wp--style--gallery-gap-default, var( --gallery-block--gutter-size, var( --wp--style--block-gap, 0.5em ) ) )`; + +function getGalleryGapCustomPropertyStyle( selector, blockGap ) { + let column = FALLBACK_VALUE; + if ( blockGap ) { column = typeof blockGap === 'string' - ? getGapCSSValue( blockGap ) - : getGapCSSValue( blockGap?.left ) || fallbackValue; - gapValue = row === column ? row : `${ row } ${ column }`; + ? getGapCSSValue( blockGap ) || FALLBACK_VALUE + : getGapCSSValue( blockGap?.left ) || FALLBACK_VALUE; } // The unstable gallery gap calculation requires a real value (such as `0px`) and not `0`. - const gap = `#block-${ clientId } { - --wp--style--unstable-gallery-gap: ${ column === '0' ? '0px' : column }; - gap: ${ gapValue } + return `${ selector } { + --wp--style--unstable-gallery-gap: ${ column === '0' ? '0px' : column } }`; +} + +export default function GalleryGapCustomProperties( { style, clientId } ) { + const selector = `#block-${ clientId }`; + const [ viewportSettings ] = useSettings( 'viewport' ); + let gap = getGalleryGapCustomPropertyStyle( + selector, + style?.spacing?.blockGap + ); + + Object.entries( getResponsiveMediaQueries( viewportSettings ) ).forEach( + ( [ viewport, mediaQuery ] ) => { + const viewportBlockGap = style?.[ viewport ]?.spacing?.blockGap; + if ( viewportBlockGap === undefined || viewportBlockGap === null ) { + return; + } + + gap += `${ mediaQuery }{${ getGalleryGapCustomPropertyStyle( + selector, + viewportBlockGap + ) }}`; + } + ); useStyleOverride( { css: gap } ); diff --git a/packages/block-library/src/gallery/index.php b/packages/block-library/src/gallery/index.php index 4ab641d9233006..fac0c115640928 100644 --- a/packages/block-library/src/gallery/index.php +++ b/packages/block-library/src/gallery/index.php @@ -52,6 +52,41 @@ function block_core_gallery_render_context( $context, $parsed_block ) { add_filter( 'render_block_context', 'block_core_gallery_render_context', 10, 2 ); +/** + * Returns the column gap value used for Gallery image width calculations. + * + * @since 7.1.0 + * + * @param string|array|null $gap Gallery block gap value. + * @param string $fallback_gap Fallback gap value. + * @return string Gallery column gap value. + */ +function block_core_gallery_get_column_gap_value( $gap, $fallback_gap ) { + if ( is_array( $gap ) ) { + $gap = $gap['left'] ?? $fallback_gap; + } + + // Make sure $gap is a string to avoid PHP 8.1 deprecation error in preg_match() when the value is null. + $gap = is_string( $gap ) ? $gap : ''; + + // Skip if gap value contains unsupported characters. + // Regex for CSS value borrowed from `safecss_filter_attr`, and used here + // because we only want to match against the value, not the CSS attribute. + $gap = $gap && preg_match( '%[\\\(&=}]|/\*%', $gap ) ? null : $gap; + + // Get spacing CSS variable from preset value if provided. + if ( is_string( $gap ) && str_contains( $gap, 'var:preset|spacing|' ) ) { + $index_to_splice = strrpos( $gap, '|' ) + 1; + $slug = _wp_to_kebab_case( substr( $gap, $index_to_splice ) ); + $gap = "var(--wp--preset--spacing--$slug)"; + } + + $gap_column = ( null !== $gap && '' !== $gap ) ? $gap : $fallback_gap; + + // The unstable gallery gap calculation requires a real value (such as `0px`) and not `0`. + return '0' === $gap_column ? '0px' : $gap_column; +} + /** * Resolves a Gallery block's `dynamicContent` to an ordered list of image * attachment IDs. @@ -345,36 +380,15 @@ function block_core_gallery_render( $attributes, $content, $block ) { // the current gap setting in order to maintain the number of flex columns // so a css var is added to allow this. - $gap = $attributes['style']['spacing']['blockGap'] ?? null; - // Skip if gap value contains unsupported characters. - // Regex for CSS value borrowed from `safecss_filter_attr`, and used here - // because we only want to match against the value, not the CSS attribute. - if ( is_array( $gap ) ) { - foreach ( $gap as $key => $value ) { - // Make sure $value is a string to avoid PHP 8.1 deprecation error in preg_match() when the value is null. - $value = is_string( $value ) ? $value : ''; - $value = $value && preg_match( '%[\\\(&=}]|/\*%', $value ) ? null : $value; - - // Get spacing CSS variable from preset value if provided. - if ( is_string( $value ) && str_contains( $value, 'var:preset|spacing|' ) ) { - $index_to_splice = strrpos( $value, '|' ) + 1; - $slug = _wp_to_kebab_case( substr( $value, $index_to_splice ) ); - $value = "var(--wp--preset--spacing--$slug)"; - } - - $gap[ $key ] = $value; - } - } else { - // Make sure $gap is a string to avoid PHP 8.1 deprecation error in preg_match() when the value is null. - $gap = is_string( $gap ) ? $gap : ''; - $gap = $gap && preg_match( '%[\\\(&=}]|/\*%', $gap ) ? null : $gap; - - // Get spacing CSS variable from preset value if provided. - if ( is_string( $gap ) && str_contains( $gap, 'var:preset|spacing|' ) ) { - $index_to_splice = strrpos( $gap, '|' ) + 1; - $slug = _wp_to_kebab_case( substr( $gap, $index_to_splice ) ); - $gap = "var(--wp--preset--spacing--$slug)"; - } + $style_attr = is_array( $attributes['style'] ?? null ) + ? $attributes['style'] + : array(); + if ( + defined( 'IS_GUTENBERG_PLUGIN' ) && + IS_GUTENBERG_PLUGIN && + function_exists( 'gutenberg_resolve_style_state_aliases' ) + ) { + $style_attr = gutenberg_resolve_style_state_aliases( $style_attr, 'core/gallery' ); } $unique_gallery_classname = wp_unique_id( 'wp-block-gallery-' ); @@ -385,31 +399,46 @@ function block_core_gallery_render( $attributes, $content, $block ) { // --gallery-block--gutter-size is deprecated. --wp--style--gallery-gap-default should be used by themes that want to set a default // gap on the gallery. $fallback_gap = 'var( --wp--style--gallery-gap-default, var( --gallery-block--gutter-size, var( --wp--style--block-gap, 0.5em ) ) )'; - $gap_value = $gap ? $gap : $fallback_gap; - $gap_column = $gap_value; - - if ( is_array( $gap_value ) ) { - $gap_row = $gap_value['top'] ?? $fallback_gap; - $gap_column = $gap_value['left'] ?? $fallback_gap; - $gap_value = $gap_row === $gap_column ? $gap_row : $gap_row . ' ' . $gap_column; - } + $gap_column = block_core_gallery_get_column_gap_value( $style_attr['spacing']['blockGap'] ?? null, $fallback_gap ); - // The unstable gallery gap calculation requires a real value (such as `0px`) and not `0`. - if ( '0' === $gap_column ) { - $gap_column = '0px'; - } - - // Set the CSS variable to the column value, and the `gap` property to the combined gap value. + // Set the CSS variable to the column value for Gallery's flex width calculations. $gallery_styles = array( array( 'selector' => ".wp-block-gallery.{$unique_gallery_classname}", 'declarations' => array( '--wp--style--unstable-gallery-gap' => $gap_column, - 'gap' => $gap_value, ), ), ); + $global_settings = wp_get_global_settings(); + $viewport_settings = $global_settings['viewport'] ?? null; + $responsive_media_queries = array(); + foreach ( array( 'WP_Theme_JSON_Gutenberg', 'WP_Theme_JSON' ) as $theme_json_class_name ) { + if ( method_exists( $theme_json_class_name, 'get_viewport_media_queries' ) ) { + $responsive_media_queries = $theme_json_class_name::get_viewport_media_queries( $viewport_settings ); + break; + } + } + + foreach ( $responsive_media_queries as $breakpoint => $media_query ) { + $viewport_style = $style_attr[ $breakpoint ] ?? null; + if ( ! is_array( $viewport_style ) || ! isset( $viewport_style['spacing']['blockGap'] ) ) { + continue; + } + + $gallery_styles[] = array( + 'selector' => ".wp-block-gallery.{$unique_gallery_classname}", + 'declarations' => array( + '--wp--style--unstable-gallery-gap' => block_core_gallery_get_column_gap_value( + $viewport_style['spacing']['blockGap'], + $fallback_gap + ), + ), + 'rules_group' => $media_query, + ); + } + wp_style_engine_get_stylesheet_from_css_rules( $gallery_styles, array( 'context' => 'block-supports' ) diff --git a/packages/block-library/tsconfig.json b/packages/block-library/tsconfig.json index 13581ab393bb6e..bb1821a17c5024 100644 --- a/packages/block-library/tsconfig.json +++ b/packages/block-library/tsconfig.json @@ -21,6 +21,7 @@ { "path": "../dom" }, { "path": "../element" }, { "path": "../escape-html" }, + { "path": "../global-styles-engine" }, { "path": "../private-apis" }, { "path": "../hooks" }, { "path": "../html-entities" },