diff --git a/backport-changelog/6.6/6522.md b/backport-changelog/6.6/6522.md new file mode 100644 index 00000000000000..172464cf664de9 --- /dev/null +++ b/backport-changelog/6.6/6522.md @@ -0,0 +1,5 @@ +https://github.com/WordPress/wordpress-develop/pull/6522 + +* https://github.com/WordPress/gutenberg/pull/60106 +* https://github.com/WordPress/gutenberg/pull/60228 +* https://github.com/WordPress/gutenberg/pull/61638 diff --git a/backport-changelog/6.6/6656.md b/backport-changelog/6.6/6656.md new file mode 100644 index 00000000000000..f0bf8900335f49 --- /dev/null +++ b/backport-changelog/6.6/6656.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6656 + +* https://github.com/WordPress/gutenberg/pull/60715 \ No newline at end of file diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 1dec7b164d880b..b5636ad7c8dc57 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -1293,7 +1293,7 @@ protected function process_blocks_custom_css( $css, $selector ) { $is_root_css = ( ! str_contains( $part, '{' ) ); if ( $is_root_css ) { // If the part doesn't contain braces, it applies to the root level. - $processed_css .= trim( $selector ) . '{' . trim( $part ) . '}'; + $processed_css .= ':root :where(' . trim( $selector ) . '){' . trim( $part ) . '}'; } else { // If the part contains braces, it's a nested CSS rule. $part = explode( '{', str_replace( '}', '', $part ) ); @@ -1305,7 +1305,8 @@ protected function process_blocks_custom_css( $css, $selector ) { $part_selector = str_starts_with( $nested_selector, ' ' ) ? static::scope_selector( $selector, $nested_selector ) : static::append_to_selector( $selector, $nested_selector ); - $processed_css .= $part_selector . '{' . trim( $css_value ) . '}'; + $final_selector = ":root :where($part_selector)"; + $processed_css .= $final_selector . '{' . trim( $css_value ) . '}'; } } return $processed_css; @@ -1322,6 +1323,7 @@ public function get_custom_css() { $block_custom_css = ''; $block_nodes = $this->get_block_custom_css_nodes(); foreach ( $block_nodes as $node ) { + // The node selector will have its specificity set to 0-1-0 within process_blocks_custom_css. $block_custom_css .= $this->get_block_custom_css( $node['css'], $node['selector'] ); } @@ -1564,7 +1566,7 @@ protected function get_layout_styles( $block_metadata, $types = array() ) { $spacing_rule['selector'] ); } else { - $format = static::ROOT_BLOCK_SELECTOR === $selector ? ':where(.%2$s) %3$s' : ':where(%1$s-%2$s) %3$s'; + $format = static::ROOT_BLOCK_SELECTOR === $selector ? '.%2$s %3$s' : '%1$s-%2$s %3$s'; $layout_selector = sprintf( $format, $selector, @@ -2745,7 +2747,7 @@ static function ( $pseudo_selector ) use ( $selector ) { } // 2. Generate and append the rules that use the general selector. - $block_rules .= static::to_ruleset( ":where($selector)", $declarations ); + $block_rules .= static::to_ruleset( ":root :where($selector)", $declarations ); // 3. Generate and append the rules that use the duotone selector. if ( isset( $block_metadata['duotone'] ) && ! empty( $declarations_duotone ) ) { @@ -2762,12 +2764,12 @@ static function ( $pseudo_selector ) use ( $selector ) { // 5. Generate and append the feature level rulesets. foreach ( $feature_declarations as $feature_selector => $individual_feature_declarations ) { - $block_rules .= static::to_ruleset( ":where($feature_selector)", $individual_feature_declarations ); + $block_rules .= static::to_ruleset( ":root :where($feature_selector)", $individual_feature_declarations ); } // 6. Generate and append the style variation rulesets. foreach ( $style_variation_declarations as $style_variation_selector => $individual_style_variation_declarations ) { - $block_rules .= static::to_ruleset( $style_variation_selector, $individual_style_variation_declarations ); + $block_rules .= static::to_ruleset( ":root :where($style_variation_selector)", $individual_style_variation_declarations ); } return $block_rules; @@ -2816,16 +2818,12 @@ public function get_root_layout_rules( $selector, $block_metadata ) { $css .= '.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }'; // Right and left padding are applied to the first container with `.has-global-padding` class. $css .= '.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; - // Nested containers with `.has-global-padding` class do not get padding. - $css .= '.has-global-padding :where(.has-global-padding:not(.wp-block-block)) { padding-right: 0; padding-left: 0; }'; // Alignfull children of the container with left and right padding have negative margins so they can still be full width. $css .= '.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }'; - // The above rule is negated for alignfull children of nested containers. - $css .= '.has-global-padding :where(.has-global-padding:not(.wp-block-block)) > .alignfull { margin-right: 0; margin-left: 0; }'; - // Some of the children of alignfull blocks without content width should also get padding: text blocks and non-alignfull container blocks. - $css .= '.has-global-padding > .alignfull:where(:not(.has-global-padding):not(.is-layout-flex):not(.is-layout-grid)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),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); }'; - // The above rule also has to be negated for blocks inside nested `.has-global-padding` blocks. - $css .= '.has-global-padding :where(.has-global-padding) > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: 0; padding-left: 0; }'; + // Nested children of the container with left and right padding that are not wide or full aligned do not get padding. + $css .= '.has-global-padding :where(.has-global-padding:not(.wp-block-block, .alignfull, .alignwide)) { padding-right: 0; padding-left: 0; }'; + // Nested children of the container with left and right padding that are not wide or full aligned do not get negative margin applied. + $css .= '.has-global-padding :where(.has-global-padding:not(.wp-block-block, .alignfull, .alignwide)) > .alignfull { margin-left: 0; margin-right: 0; }'; } $css .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }'; diff --git a/lib/experimental/full-page-client-side-navigation.php b/lib/experimental/full-page-client-side-navigation.php index ebfddf4aaf4369..621502912a668a 100644 --- a/lib/experimental/full-page-client-side-navigation.php +++ b/lib/experimental/full-page-client-side-navigation.php @@ -33,25 +33,69 @@ function _gutenberg_add_enhanced_pagination_to_query_block( $parsed_block ) { add_filter( 'render_block_data', '_gutenberg_add_enhanced_pagination_to_query_block' ); /** - * Add directives to all links. + * Adds client-side navigation directives to BODY tag. * * Note: This should probably be done per site, not by default when this option is enabled. * - * @param array $content The block content. + * @param string $response_body The response body. * - * @return array The same block content with the directives needed. + * @return string The rendered template with modified BODY attributes. */ -function _gutenberg_add_client_side_navigation_directives( $content ) { - $p = new WP_HTML_Tag_Processor( $content ); - // Hack to add the necessary directives to the body tag. - // TODO: Find a proper way to add directives to the body tag. - static $body_interactive_added; - if ( ! $body_interactive_added ) { - $body_interactive_added = true; - return (string) $p . ''; +function _gutenberg_add_client_side_navigation_directives( $response_body ) { + $is_html_content_type = false; + foreach ( headers_list() as $header ) { + $header_parts = preg_split( '/\s*[:;]\s*/', strtolower( $header ) ); + if ( count( $header_parts ) >= 2 && 'content-type' === $header_parts[0] ) { + $is_html_content_type = in_array( $header_parts[1], array( 'text/html', 'application/xhtml+xml' ), true ); + } } - return (string) $p; + if ( ! $is_html_content_type ) { + return $response_body; + } + + $p = new WP_HTML_Tag_Processor( $response_body ); + if ( $p->next_tag( array( 'tag_name' => 'BODY' ) ) ) { + $p->set_attribute( 'data-wp-interactive', 'core/experimental' ); + $p->set_attribute( 'data-wp-context', '{}' ); + $response_body = $p->get_updated_html(); + } + return $response_body; } // TODO: Explore moving this to the server directive processing. -add_filter( 'render_block', '_gutenberg_add_client_side_navigation_directives' ); +add_filter( 'gutenberg_template_output_buffer', '_gutenberg_add_client_side_navigation_directives' ); + +/** + * Starts output buffering at the end of the 'template_include' filter. + * + * This is to implement #43258 in core. + * + * This is a hack which would eventually be replaced with something like this in wp-includes/template-loader.php: + * + * $template = apply_filters( 'template_include', $template ); + * + ob_start( 'wp_template_output_buffer_callback' ); + * if ( $template ) { + * include $template; + * } elseif ( current_user_can( 'switch_themes' ) ) { + * + * @link https://core.trac.wordpress.org/ticket/43258 + * + * @param string $passthrough Value for the template_include filter which is passed through. + * + * @return string Unmodified value of $passthrough. + */ +function _gutenberg_buffer_template_output( string $passthrough ): string { + ob_start( + static function ( string $output ): string { + /** + * Filters the template output buffer prior to sending to the client. + * + * @param string $output Output buffer. + * @return string Filtered output buffer. + */ + return (string) apply_filters( 'gutenberg_template_output_buffer', $output ); + } + ); + return $passthrough; +} +add_filter( 'template_include', '_gutenberg_buffer_template_output', PHP_INT_MAX ); diff --git a/lib/theme.json b/lib/theme.json index 7cd6129923df2a..2f1f723bf75f7f 100644 --- a/lib/theme.json +++ b/lib/theme.json @@ -370,6 +370,40 @@ "bottom": "0px", "left": "0px" } + }, + "blocks": { + "core/button": { + "variations": { + "outline": { + "border": { + "width": "2px", + "style": "solid", + "color": "currentColor" + }, + "color": { + "text": "currentColor", + "gradient": "transparent none" + }, + "spacing": { + "padding": { + "top": "0.667em", + "right": "1.33em", + "bottom": "0.667em", + "left": "1.33em" + } + } + } + } + }, + "core/site-logo": { + "variations": { + "rounded": { + "border": { + "radius": "9999px" + } + } + } + } } } } diff --git a/package.json b/package.json index ac50b0caf19479..f218f9ca808205 100644 --- a/package.json +++ b/package.json @@ -276,7 +276,7 @@ "clean:packages": "rimraf \"./packages/*/@(build|build-module|build-style)\"", "dev": "npm run build:packages && concurrently \"wp-scripts start\" \"npm run dev:packages\"", "dev:packages": "concurrently \"node ./bin/packages/watch.js\" \"tsc --build --watch\"", - "distclean": "rimraf node_modules packages/*/node_modules", + "distclean": "git clean --force -d -X", "docs:api-ref": "node ./bin/api-docs/update-api-docs.js", "docs:blocks": "node ./bin/api-docs/gen-block-lib-list.js", "docs:build": "npm-run-all docs:gen docs:blocks docs:api-ref docs:theme-ref", diff --git a/packages/block-editor/src/components/global-styles/background-panel.js b/packages/block-editor/src/components/global-styles/background-panel.js index 2e73f52564362e..b7cf7f2bbc493d 100644 --- a/packages/block-editor/src/components/global-styles/background-panel.js +++ b/packages/block-editor/src/components/global-styles/background-panel.js @@ -102,7 +102,7 @@ function backgroundSizeHelpText( value ) { if ( value === 'contain' ) { return __( 'Image is contained without distortion.' ); } - return __( 'Specify a fixed width.' ); + return __( 'Image has a fixed width.' ); } /** @@ -174,13 +174,13 @@ function InspectorImagePreview( { label, filename, url: imgUrl } ) { { imgLabel } - { filename + { imgUrl ? sprintf( /* translators: %s: file name */ - __( 'Selected image: %s' ), - filename + __( 'Background image: %s' ), + filename || imgLabel ) - : __( 'No image selected' ) } + : __( 'No background image selected' ) } @@ -321,7 +321,7 @@ function BackgroundImageToolsPanelItem( { name={ - { currentValueForToggle !== undefined && - currentValueForToggle !== 'cover' && - currentValueForToggle !== 'contain' ? ( - - ) : null } - { currentValueForToggle !== 'cover' && ( - - ) } + + { currentValueForToggle !== undefined && + currentValueForToggle !== 'cover' && + currentValueForToggle !== 'contain' ? ( + + ) : null } + { currentValueForToggle !== 'cover' && ( + + ) } + ); } diff --git a/packages/block-editor/src/components/global-styles/test/use-global-styles-output.js b/packages/block-editor/src/components/global-styles/test/use-global-styles-output.js index 95de3d4007079c..b858a2e4140ea9 100644 --- a/packages/block-editor/src/components/global-styles/test/use-global-styles-output.js +++ b/packages/block-editor/src/components/global-styles/test/use-global-styles-output.js @@ -480,7 +480,7 @@ describe( 'global styles renderer', () => { }; expect( toStyles( tree, blockSelectors ) ).toEqual( - ':where(body) {margin: 0;}.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-constrained > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-constrained > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) { max-width: var(--wp--style--global--content-size); margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignwide { max-width: var(--wp--style--global--wide-size); }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > :is(*, div) { margin: 0; }body .is-layout-grid { display:grid; }.is-layout-grid > :is(*, div) { margin: 0; }:where(body){background-color: red;margin: 10px;padding: 10px;}:where(a:where(:not(.wp-element-button))){color: blue;}a:where(:not(.wp-element-button)):hover{color: orange;}a:where(:not(.wp-element-button)):focus{color: orange;}:where(h1){font-size: 42px;}:where(.wp-block-group){margin-top: 10px;margin-right: 20px;margin-bottom: 30px;margin-left: 40px;padding-top: 11px;padding-right: 22px;padding-bottom: 33px;padding-left: 44px;}:where(h1,h2,h3,h4,h5,h6){color: orange;}:where(h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button))){color: hotpink;}h1 a:where(:not(.wp-element-button)):hover,h2 a:where(:not(.wp-element-button)):hover,h3 a:where(:not(.wp-element-button)):hover,h4 a:where(:not(.wp-element-button)):hover,h5 a:where(:not(.wp-element-button)):hover,h6 a:where(:not(.wp-element-button)):hover{color: red;}h1 a:where(:not(.wp-element-button)):focus,h2 a:where(:not(.wp-element-button)):focus,h3 a:where(:not(.wp-element-button)):focus,h4 a:where(:not(.wp-element-button)):focus,h5 a:where(:not(.wp-element-button)):focus,h6 a:where(:not(.wp-element-button)):focus{color: red;}:where(.wp-block-image img, .wp-block-image .wp-crop-area){border-radius: 9999px;}:where(.wp-block-image){color: red;}.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; }.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;}' + ':where(body) {margin: 0;}.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-constrained > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-constrained > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) { max-width: var(--wp--style--global--content-size); margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignwide { max-width: var(--wp--style--global--wide-size); }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > :is(*, div) { margin: 0; }body .is-layout-grid { display:grid; }.is-layout-grid > :is(*, div) { margin: 0; }:root :where(body){background-color: red;margin: 10px;padding: 10px;}:root :where(a:where(:not(.wp-element-button))){color: blue;}a:where(:not(.wp-element-button)):hover{color: orange;}a:where(:not(.wp-element-button)):focus{color: orange;}:root :where(h1){font-size: 42px;}:root :where(.wp-block-group){margin-top: 10px;margin-right: 20px;margin-bottom: 30px;margin-left: 40px;padding-top: 11px;padding-right: 22px;padding-bottom: 33px;padding-left: 44px;}:root :where(h1,h2,h3,h4,h5,h6){color: orange;}:root :where(h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button))){color: hotpink;}h1 a:where(:not(.wp-element-button)):hover,h2 a:where(:not(.wp-element-button)):hover,h3 a:where(:not(.wp-element-button)):hover,h4 a:where(:not(.wp-element-button)):hover,h5 a:where(:not(.wp-element-button)):hover,h6 a:where(:not(.wp-element-button)):hover{color: red;}h1 a:where(:not(.wp-element-button)):focus,h2 a:where(:not(.wp-element-button)):focus,h3 a:where(:not(.wp-element-button)):focus,h4 a:where(:not(.wp-element-button)):focus,h5 a:where(:not(.wp-element-button)):focus,h6 a:where(:not(.wp-element-button)):focus{color: red;}:root :where(.wp-block-image img, .wp-block-image .wp-crop-area){border-radius: 9999px;}:root :where(.wp-block-image){color: red;}.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; }.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;}' ); } ); @@ -520,7 +520,7 @@ describe( 'global styles renderer', () => { }; expect( toStyles( Object.freeze( tree ), blockSelectors ) ).toEqual( - ':where(body) {margin: 0;}.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-constrained > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-constrained > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) { max-width: var(--wp--style--global--content-size); margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignwide { max-width: var(--wp--style--global--wide-size); }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > :is(*, div) { margin: 0; }body .is-layout-grid { display:grid; }.is-layout-grid > :is(*, div) { margin: 0; }:where(.wp-image-spacing){padding-top: 1px;}:where(.wp-image-border-color){border-color: red;}:where(.wp-image-border){border-radius: 9999px;}:where(.wp-image){color: red;}.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(body) {margin: 0;}.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-constrained > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-constrained > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) { max-width: var(--wp--style--global--content-size); margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignwide { max-width: var(--wp--style--global--wide-size); }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > :is(*, div) { margin: 0; }body .is-layout-grid { display:grid; }.is-layout-grid > :is(*, div) { margin: 0; }:root :where(.wp-image-spacing){padding-top: 1px;}:root :where(.wp-image-border-color){border-color: red;}:root :where(.wp-image-border){border-radius: 9999px;}:root :where(.wp-image){color: red;}.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; }' ); } ); @@ -566,7 +566,8 @@ describe( 'global styles renderer', () => { }; expect( toStyles( Object.freeze( tree ), blockSelectors ) ).toEqual( - ':where(body) {margin: 0;}.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-constrained > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-constrained > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) { max-width: var(--wp--style--global--content-size); margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignwide { max-width: var(--wp--style--global--wide-size); }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > :is(*, div) { margin: 0; }body .is-layout-grid { display:grid; }.is-layout-grid > :is(*, div) { margin: 0; }.is-style-foo.wp-image.wp-image-spacing{padding-top: 2px;}.is-style-foo.wp-image.wp-image-border-color{border-color: blue;}.is-style-foo.wp-image{color: blue;}.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(body) {margin: 0;}.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-constrained > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-constrained > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) { max-width: var(--wp--style--global--content-size); margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignwide { max-width: var(--wp--style--global--wide-size); }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > :is(*, div) { margin: 0; }body .is-layout-grid { display:grid; }.is-layout-grid > :is(*, div) { margin: 0; }' + + ':root :where(.is-style-foo.wp-image.wp-image-spacing){padding-top: 2px;}:root :where(.is-style-foo.wp-image.wp-image-border-color){border-color: blue;}:root :where(.is-style-foo.wp-image){color: blue;}.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; }' ); } ); @@ -725,7 +726,7 @@ describe( 'global styles renderer', () => { } ); expect( layoutStyles ).toEqual( - ':where(.is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:where(.is-layout-flow) > * + * { margin-block-start: 0.5em; margin-block-end: 0; }:where(.is-layout-flex) { gap: 0.5em; }:root { --wp--style--block-gap: 0.5em; }.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > * { margin: 0; }' + '.is-layout-flow > * { margin-block-start: 0; margin-block-end: 0; }.is-layout-flow > * + * { margin-block-start: 0.5em; margin-block-end: 0; }.is-layout-flex { gap: 0.5em; }:root { --wp--style--block-gap: 0.5em; }.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > * { margin: 0; }' ); } ); @@ -742,7 +743,7 @@ describe( 'global styles renderer', () => { } ); expect( layoutStyles ).toEqual( - ':where(.is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:where(.is-layout-flow) > * + * { margin-block-start: 12px; margin-block-end: 0; }:where(.is-layout-flex) { gap: 12px; }:root { --wp--style--block-gap: 12px; }.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > * { margin: 0; }' + '.is-layout-flow > * { margin-block-start: 0; margin-block-end: 0; }.is-layout-flow > * + * { margin-block-start: 12px; margin-block-end: 0; }.is-layout-flex { gap: 12px; }:root { --wp--style--block-gap: 12px; }.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > * { margin: 0; }' ); } ); @@ -759,7 +760,7 @@ describe( 'global styles renderer', () => { } ); expect( layoutStyles ).toEqual( - ':where(.wp-block-group-is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:where(.wp-block-group-is-layout-flow) > * + * { margin-block-start: 12px; margin-block-end: 0; }:where(.wp-block-group-is-layout-flex) { gap: 12px; }' + '.wp-block-group-is-layout-flow > * { margin-block-start: 0; margin-block-end: 0; }.wp-block-group-is-layout-flow > * + * { margin-block-start: 12px; margin-block-end: 0; }.wp-block-group-is-layout-flex { gap: 12px; }' ); } ); @@ -996,7 +997,7 @@ describe( 'global styles renderer', () => { it( 'should return processed CSS without any nested selectors', () => { expect( processCSSNesting( 'color: red; margin: auto;', '.foo' ) - ).toEqual( '.foo{color: red; margin: auto;}' ); + ).toEqual( ':root :where(.foo){color: red; margin: auto;}' ); } ); it( 'should return processed CSS with nested selectors', () => { expect( @@ -1005,7 +1006,7 @@ describe( 'global styles renderer', () => { '.foo' ) ).toEqual( - '.foo{color: red; margin: auto;}.foo.one{color: blue;}.foo .two{color: green;}' + ':root :where(.foo){color: red; margin: auto;}:root :where(.foo.one){color: blue;}:root :where(.foo .two){color: green;}' ); } ); it( 'should return processed CSS with pseudo elements', () => { @@ -1015,7 +1016,7 @@ describe( 'global styles renderer', () => { '.foo' ) ).toEqual( - '.foo{color: red; margin: auto;}.foo::before{color: blue;}.foo ::before{color: green;}.foo.one::before{color: yellow;}.foo .two::before{color: purple;}' + ':root :where(.foo){color: red; margin: auto;}:root :where(.foo::before){color: blue;}:root :where(.foo ::before){color: green;}:root :where(.foo.one::before){color: yellow;}:root :where(.foo .two::before){color: purple;}' ); } ); it( 'should return processed CSS with multiple root selectors', () => { @@ -1025,7 +1026,7 @@ describe( 'global styles renderer', () => { '.foo, .bar' ) ).toEqual( - '.foo, .bar{color: red; margin: auto;}.foo.one, .bar.one{color: blue;}.foo .two, .bar .two{color: green;}.foo::before, .bar::before{color: yellow;}.foo ::before, .bar ::before{color: purple;}.foo.three::before, .bar.three::before{color: orange;}.foo .four::before, .bar .four::before{color: skyblue;}' + ':root :where(.foo, .bar){color: red; margin: auto;}:root :where(.foo.one, .bar.one){color: blue;}:root :where(.foo .two, .bar .two){color: green;}:root :where(.foo::before, .bar::before){color: yellow;}:root :where(.foo ::before, .bar ::before){color: purple;}:root :where(.foo.three::before, .bar.three::before){color: orange;}:root :where(.foo .four::before, .bar .four::before){color: skyblue;}' ); } ); } ); diff --git a/packages/block-editor/src/components/global-styles/use-global-styles-output.js b/packages/block-editor/src/components/global-styles/use-global-styles-output.js index 981189309f828b..f2eaa50a890a9b 100644 --- a/packages/block-editor/src/components/global-styles/use-global-styles-output.js +++ b/packages/block-editor/src/components/global-styles/use-global-styles-output.js @@ -522,10 +522,10 @@ export function getLayoutStyles( { } else { combinedSelector = selector === ROOT_BLOCK_SELECTOR - ? `:where(.${ className })${ + ? `.${ className }${ spacingStyle?.selector || '' }` - : `:where(${ selector }-${ className })${ + : `${ selector }-${ className }${ spacingStyle?.selector || '' }`; } @@ -815,23 +815,18 @@ export const toStyles = ( */ ruleset += ':where(body) {margin: 0;'; - // Root padding styles should only be output for full templates, not patterns or template parts. - if ( - options.rootPadding && - useRootPaddingAlign && - ! disableRootPadding - ) { + // Root padding styles should be output for full templates, patterns and template parts. + if ( options.rootPadding && useRootPaddingAlign ) { /* * These rules reproduce the ones from https://github.com/WordPress/gutenberg/blob/79103f124925d1f457f627e154f52a56228ed5ad/lib/class-wp-theme-json-gutenberg.php#L2508 * almost exactly, but for the selectors that target block wrappers in the front end. This code only runs in the editor, so it doesn't need those selectors. */ 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 :where(.has-global-padding:not(.wp-block-block)) { padding-right: 0; padding-left: 0; } .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 :where(.has-global-padding:not(.wp-block-block)) > .alignfull { margin-right: 0; margin-left: 0; } - .has-global-padding > .alignfull:where(:not(.has-global-padding):not(.is-layout-flex):not(.is-layout-grid)) > :where(.wp-block:not(.alignfull),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); } - .has-global-padding :where(.has-global-padding) > .alignfull:where(:not(.has-global-padding)) > :where(.wp-block:not(.alignfull),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: 0; padding-left: 0;`; + .has-global-padding :where(.has-global-padding:not(.wp-block-block, .alignfull, .alignwide)) { padding-right: 0; padding-left: 0; } + .has-global-padding :where(.has-global-padding:not(.wp-block-block, .alignfull, .alignwide)) > .alignfull { margin-left: 0; margin-right: 0; } + `; } ruleset += '}'; @@ -860,12 +855,56 @@ export const toStyles = ( ( [ cssSelector, declarations ] ) => { if ( declarations.length ) { const rules = declarations.join( ';' ); - ruleset += `:where(${ cssSelector }){${ rules };}`; + ruleset += `:root :where(${ cssSelector }){${ rules };}`; } } ); } + // Process duotone styles. + if ( duotoneSelector ) { + const duotoneStyles = {}; + if ( styles?.filter ) { + duotoneStyles.filter = styles.filter; + delete styles.filter; + } + const duotoneDeclarations = + getStylesDeclarations( duotoneStyles ); + if ( duotoneDeclarations.length ) { + ruleset += `${ duotoneSelector }{${ duotoneDeclarations.join( + ';' + ) };}`; + } + } + + // Process blockGap and layout styles. + if ( + ! disableLayoutStyles && + ( ROOT_BLOCK_SELECTOR === selector || hasLayoutSupport ) + ) { + ruleset += getLayoutStyles( { + style: styles, + selector, + hasBlockGapSupport, + hasFallbackGapSupport, + fallbackGapValue, + } ); + } + + // Process the remaining block styles (they use either normal block class or __experimentalSelector). + const styleDeclarations = getStylesDeclarations( + styles, + selector, + useRootPaddingAlign, + tree, + disableRootPadding + ); + if ( styleDeclarations?.length ) { + ruleset += `:root :where(${ selector }){${ styleDeclarations.join( + ';' + ) };}`; + } + if ( styleVariationSelectors ) { Object.entries( styleVariationSelectors ).forEach( ( [ styleVariationName, styleVariationSelector ] ) => { @@ -892,7 +931,7 @@ export const toStyles = ( ); const rules = declarations.join( ';' ); - ruleset += `${ cssSelector }{${ rules };}`; + ruleset += `:root :where(${ cssSelector }){${ rules };}`; } } ); @@ -907,7 +946,7 @@ export const toStyles = ( tree ); if ( styleVariationDeclarations.length ) { - ruleset += `${ styleVariationSelector }{${ styleVariationDeclarations.join( + ruleset += `:root :where(${ styleVariationSelector }){${ styleVariationDeclarations.join( ';' ) };}`; } @@ -916,50 +955,6 @@ export const toStyles = ( ); } - // Process duotone styles. - if ( duotoneSelector ) { - const duotoneStyles = {}; - if ( styles?.filter ) { - duotoneStyles.filter = styles.filter; - delete styles.filter; - } - const duotoneDeclarations = - getStylesDeclarations( duotoneStyles ); - if ( duotoneDeclarations.length ) { - ruleset += `${ duotoneSelector }{${ duotoneDeclarations.join( - ';' - ) };}`; - } - } - - // Process blockGap and layout styles. - if ( - ! disableLayoutStyles && - ( ROOT_BLOCK_SELECTOR === selector || hasLayoutSupport ) - ) { - ruleset += getLayoutStyles( { - style: styles, - selector, - hasBlockGapSupport, - hasFallbackGapSupport, - fallbackGapValue, - } ); - } - - // Process the remaining block styles (they use either normal block class or __experimentalSelector). - const declarations = getStylesDeclarations( - styles, - selector, - useRootPaddingAlign, - tree, - disableRootPadding - ); - if ( declarations?.length ) { - ruleset += `:where(${ selector }){${ declarations.join( - ';' - ) };}`; - } - // Check for pseudo selector in `styles` and handle separately. const pseudoSelectorStyles = Object.entries( styles ).filter( ( [ key ] ) => key.startsWith( ':' ) @@ -1018,13 +1013,13 @@ export const toStyles = ( getGapCSSValue( tree?.styles?.spacing?.blockGap ) || '0.5em'; ruleset = ruleset + - `:where(.wp-site-blocks) > * { margin-block-start: ${ gapValue }; margin-block-end: 0; }`; + `:root :where(.wp-site-blocks) > * { margin-block-start: ${ gapValue }; margin-block-end: 0; }`; ruleset = ruleset + - ':where(.wp-site-blocks) > :first-child { margin-block-start: 0; }'; + ':root :where(.wp-site-blocks) > :first-child { margin-block-start: 0; }'; ruleset = ruleset + - ':where(.wp-site-blocks) > :last-child { margin-block-end: 0; }'; + ':root :where(.wp-site-blocks) > :last-child { margin-block-end: 0; }'; } if ( options.presets ) { @@ -1185,7 +1180,7 @@ export function processCSSNesting( css, blockSelector ) { const isRootCss = ! part.includes( '{' ); if ( isRootCss ) { // If the part doesn't contain braces, it applies to the root level. - processedCSS += `${ blockSelector }{${ part.trim() }}`; + processedCSS += `:root :where(${ blockSelector }){${ part.trim() }}`; } else { // If the part contains braces, it's a nested CSS rule. const splittedPart = part.replace( '}', '' ).split( '{' ); @@ -1198,7 +1193,7 @@ export function processCSSNesting( css, blockSelector ) { ? scopeSelector( blockSelector, nestedSelector ) : appendToSelector( blockSelector, nestedSelector ); - processedCSS += `${ combinedSelector }{${ cssValue.trim() }}`; + processedCSS += `:root :where(${ combinedSelector }){${ cssValue.trim() }}`; } } ); return processedCSS; diff --git a/packages/block-library/src/audio/theme.scss b/packages/block-library/src/audio/theme.scss index eda394fd6a3d54..2744d36e74ca62 100644 --- a/packages/block-library/src/audio/theme.scss +++ b/packages/block-library/src/audio/theme.scss @@ -2,6 +2,6 @@ @include caption-style-theme(); } -:where(.wp-block-audio) { +.wp-block-audio { margin: 0 0 1em 0; } diff --git a/packages/block-library/src/block/editor.scss b/packages/block-library/src/block/editor.scss deleted file mode 100644 index 318101f7f52dac..00000000000000 --- a/packages/block-library/src/block/editor.scss +++ /dev/null @@ -1,35 +0,0 @@ -.edit-post-visual-editor .block-library-block__reusable-block-container { - // Unset the padding that root containers get when they're actually root containers. - .is-root-container { - padding-left: 0; - padding-right: 0; - } - - // Allow vertical paddings to collapse to better fit the flow. - .block-editor-writing-flow { - display: block; - } - - .components-disabled .block-list-appender { - display: none; - } -} - -.edit-post-visual-editor .block-editor-block-list__block:not(.remove-outline).is-reusable { - - &.is-highlighted::after, - &.is-selected::after { - outline-color: var(--wp-block-synced-color); - } - - &.block-editor-block-list__block:not([contenteditable]):focus { - &::after { - outline-color: var(--wp-block-synced-color); - - // Show a light color for dark themes. - .is-dark-theme & { - outline-color: $dark-theme-focus; - } - } - } -} diff --git a/packages/block-library/src/button/editor.scss b/packages/block-library/src/button/editor.scss index c24021d17e38ec..8c879c7e3b7c9e 100644 --- a/packages/block-library/src/button/editor.scss +++ b/packages/block-library/src/button/editor.scss @@ -37,38 +37,3 @@ div[data-type="core/button"] { text-decoration: inherit; } -.editor-styles-wrapper .wp-block-button .wp-block-button__link { - // The following styles ensure a default border is applied when the user selects only a border color or style in the editor, - // but no width. They override the `border-width: 0;` applied by core's theme.json via the Elements API button. - &:where(.has-border-color) { - border-width: initial; - } - &:where([style*="border-top-color"]) { - border-top-width: initial; - } - &:where([style*="border-right-color"]) { - border-right-width: initial; - } - &:where([style*="border-bottom-color"]) { - border-bottom-width: initial; - } - &:where([style*="border-left-color"]) { - border-left-width: initial; - } - - &:where([style*="border-style"]) { - border-width: initial; - } - &:where([style*="border-top-style"]) { - border-top-width: initial; - } - &:where([style*="border-right-style"]) { - border-right-width: initial; - } - &:where([style*="border-bottom-style"]) { - border-bottom-width: initial; - } - &:where([style*="border-left-style"]) { - border-left-width: initial; - } -} diff --git a/packages/block-library/src/button/style.scss b/packages/block-library/src/button/style.scss index f441152107973f..42306cba0c984d 100644 --- a/packages/block-library/src/button/style.scss +++ b/packages/block-library/src/button/style.scss @@ -86,69 +86,37 @@ $blocks-block__margin: 0.5em; } } -// the first selector is required for old buttons markup +// The follow block style selectors are required for old buttons markup +// and do not use the `:root :where()` format to match specificity at +// the time they were deprecated. .wp-block-button.is-style-squared, .wp-block-button__link.wp-block-button.is-style-squared { border-radius: 0; } - -// the first selector is required for old buttons markup .wp-block-button.no-border-radius, .wp-block-button__link.no-border-radius { border-radius: 0 !important; } -.wp-block-button:where(.is-style-outline) > .wp-block-button__link, -.wp-block-button .wp-block-button__link:where(.is-style-outline) { - border: 2px solid currentColor; - padding: 0.667em 1.333em; -} - -.wp-block-button:where(.is-style-outline) > .wp-block-button__link:not(.has-text-color), -.wp-block-button .wp-block-button__link:where(.is-style-outline):not(.has-text-color) { - color: currentColor; -} - -.wp-block-button:where(.is-style-outline) > .wp-block-button__link:not(.has-background), -.wp-block-button .wp-block-button__link:where(.is-style-outline):not(.has-background) { - background-color: transparent; - // background-image is required to overwrite a gradient background - background-image: none; -} - -.wp-block-button .wp-block-button__link { - // The following styles ensure a default border is applied when the user - // selects only a border color or style. This overcomes the zero border - // width applied by core's theme.json via the elements API. - &:where(.has-border-color) { - border-width: initial; - } - &:where([style*="border-top-color"]) { - border-top-width: initial; - } - &:where([style*="border-right-color"]) { - border-right-width: initial; - } - &:where([style*="border-bottom-color"]) { - border-bottom-width: initial; - } - &:where([style*="border-left-color"]) { - border-left-width: initial; +// Selectors here use the `:root :where()` format for maintaining compatibility +// with global styles and nested block style variations. +:root { + // Outline Block Style Variation. + :where(.wp-block-button.is-style-outline > .wp-block-button__link), + :where(.wp-block-button .wp-block-button__link.is-style-outline) { + border: 2px solid currentColor; + padding: 0.667em 1.333em; } - &:where([style*="border-style"]) { - border-width: initial; - } - &:where([style*="border-top-style"]) { - border-top-width: initial; + :where(.wp-block-button.is-style-outline > .wp-block-button__link:not(.has-text-color)), + :where(.wp-block-button .wp-block-button__link.is-style-outline:not(.has-text-color)) { + color: currentColor; } - &:where([style*="border-right-style"]) { - border-right-width: initial; - } - &:where([style*="border-bottom-style"]) { - border-bottom-width: initial; - } - &:where([style*="border-left-style"]) { - border-left-width: initial; + + :where(.wp-block-button.is-style-outline > .wp-block-button__link:not(.has-background)), + :where(.wp-block-button .wp-block-button__link.is-style-outline:not(.has-background)) { + background-color: transparent; + // background-image is required to overwrite a gradient background + background-image: none; } } diff --git a/packages/block-library/src/cover/style.scss b/packages/block-library/src/cover/style.scss index d14f606fc0226a..58f1147f12d279 100644 --- a/packages/block-library/src/cover/style.scss +++ b/packages/block-library/src/cover/style.scss @@ -1,11 +1,7 @@ -// Lowest specificity styles are used to ensure that the default styles for the cover block can be overridden by global styles. -:where(.wp-block-cover-image, .wp-block-cover) { - min-height: 430px; - padding: 1em; -} - .wp-block-cover-image, .wp-block-cover { + min-height: 430px; + padding: 1em; position: relative; background-position: center center; display: flex; @@ -120,18 +116,6 @@ /*rtl:raw: direction: rtl; */ } - p, - h1, - h2, - h3, - h4, - h5, - h6 { - &:where(:not(.has-text-color)) { - color: inherit; - } - } - // Position: Top &.is-position-top-left { align-items: flex-start; @@ -314,3 +298,15 @@ section.wp-block-cover-image > h2, :where(.wp-block-cover-image.is-light:not(.has-text-color)) { color: $black; } + +:root { + :where(.wp-block-cover p:not(.has-text-color)), + :where(.wp-block-cover h1:not(.has-text-color)), + :where(.wp-block-cover h2:not(.has-text-color)), + :where(.wp-block-cover h3:not(.has-text-color)), + :where(.wp-block-cover h4:not(.has-text-color)), + :where(.wp-block-cover h5:not(.has-text-color)), + :where(.wp-block-cover h6:not(.has-text-color)) { + color: inherit; + } +} diff --git a/packages/block-library/src/editor.scss b/packages/block-library/src/editor.scss index 0bca3e23028c50..c43137c632b73f 100644 --- a/packages/block-library/src/editor.scss +++ b/packages/block-library/src/editor.scss @@ -1,7 +1,6 @@ @import "./archives/editor.scss"; @import "./audio/editor.scss"; @import "./avatar/editor.scss"; -@import "./block/editor.scss"; @import "./button/editor.scss"; @import "./buttons/editor.scss"; @import "./categories/editor.scss"; diff --git a/packages/block-library/src/embed/theme.scss b/packages/block-library/src/embed/theme.scss index 57ece1dcd43cac..e809a783b9c810 100644 --- a/packages/block-library/src/embed/theme.scss +++ b/packages/block-library/src/embed/theme.scss @@ -2,6 +2,6 @@ @include caption-style-theme(); } -:where(.wp-block-embed) { +.wp-block-embed { margin: 0 0 1em 0; } diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index ea6fa8836a3a4b..9efaf88e5acc71 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -1,4 +1,7 @@ -:where(figure.wp-block-gallery) { +// Adding `figure` to the selector increases the specificity above the global +// styles specificity, which is levelled at 0-1-0. We should figure out why +// `figure` is needed. +:root :where(figure.wp-block-gallery) { // Override the default list style type _only in the editor_ // to avoid :not() selector specificity issues. // See https://github.com/WordPress/gutenberg/pull/10358 diff --git a/packages/block-library/src/image/style.scss b/packages/block-library/src/image/style.scss index 75c8b839dca37c..40ffe0cd0e61c7 100644 --- a/packages/block-library/src/image/style.scss +++ b/packages/block-library/src/image/style.scss @@ -82,16 +82,10 @@ @include caption-style(); } - // Variations - &.is-style-rounded img, - .is-style-rounded img { - // We use an absolute pixel to prevent the oval shape that a value of 50% would give - // to rectangular images. A pill-shape is better than otherwise. - border-radius: 9999px; - } - // The following variation is deprecated. // The CSS is kept here for the time being, to support blocks using the old variation. + // The selector is not scoped with `:root :where()` like global styles are to keep its + // specificity the same as it was when it was deprecated. &.is-style-circle-mask img { // We use an absolute pixel to prevent the oval shape that a value of 50% would give // to rectangular images. A pill-shape is better than otherwise. @@ -108,42 +102,13 @@ border-radius: 0; } } +} - // The following is required to overcome WP Core applying styles that clear - // img borders with a higher specificity than those added by the border - // block support to provide a default border-style of solid when a border - // color or width has been set. - :where(.has-border-color) { - border-style: solid; - } - :where([style*="border-top-color"]) { - border-top-style: solid; - } - :where([style*="border-right-color"]) { - border-right-style: solid; - } - :where([style*="border-bottom-color"]) { - border-bottom-style: solid; - } - :where([style*="border-left-color"]) { - border-left-style: solid; - } - - :where([style*="border-width"]) { - border-style: solid; - } - :where([style*="border-top-width"]) { - border-top-style: solid; - } - :where([style*="border-right-width"]) { - border-right-style: solid; - } - :where([style*="border-bottom-width"]) { - border-bottom-style: solid; - } - :where([style*="border-left-width"]) { - border-left-style: solid; - } +// Variations +:root :where(.wp-block-image.is-style-rounded img, .wp-block-image .is-style-rounded img) { + // We use an absolute pixel to prevent the oval shape that a value of 50% would give + // to rectangular images. A pill-shape is better than otherwise. + border-radius: 9999px; } .wp-block-image figure { diff --git a/packages/block-library/src/image/theme.scss b/packages/block-library/src/image/theme.scss index 459036511335a6..c89dd3334dd09a 100644 --- a/packages/block-library/src/image/theme.scss +++ b/packages/block-library/src/image/theme.scss @@ -1,7 +1,7 @@ -.wp-block-image figcaption { +:root :where(.wp-block-image figcaption) { @include caption-style-theme(); } -:where(.wp-block-image) { +.wp-block-image { margin: 0 0 1em 0; } diff --git a/packages/block-library/src/latest-posts/editor.scss b/packages/block-library/src/latest-posts/editor.scss index 3c2d6a30f1c077..d3f0b5275653e3 100644 --- a/packages/block-library/src/latest-posts/editor.scss +++ b/packages/block-library/src/latest-posts/editor.scss @@ -1,9 +1,4 @@ .wp-block-latest-posts { - padding-left: 2.5em; - &.is-grid { - padding-left: 0; - } - // Apply overflow for post items, so any floated featured images won't crop the focus style. > li { overflow: hidden; @@ -14,10 +9,6 @@ display: inline; } -.edit-post-visual-editor .wp-block-latest-posts.is-grid li { - margin-bottom: 20px; -} - .editor-latest-posts-image-alignment-control { .components-base-control__label { display: block; @@ -27,3 +18,13 @@ border-radius: $radius-block-ui; } } + +:root :where(.wp-block-latest-posts) { + padding-left: 2.5em; +} +:root { + :where(.wp-block-latest-posts.is-grid), + :where(.wp-block-latest-posts__list) { + padding-left: 0; + } +} diff --git a/packages/block-library/src/latest-posts/style.scss b/packages/block-library/src/latest-posts/style.scss index 5d3e360d0804a8..2a01d177ef47c4 100644 --- a/packages/block-library/src/latest-posts/style.scss +++ b/packages/block-library/src/latest-posts/style.scss @@ -12,7 +12,6 @@ } &.wp-block-latest-posts__list { list-style: none; - padding-left: 0; li { clear: both; @@ -23,7 +22,6 @@ &.is-grid { display: flex; flex-wrap: wrap; - padding: 0; li { margin: 0 1.25em 1.25em 0; @@ -34,9 +32,9 @@ @include break-small { @for $i from 2 through 6 { &.columns-#{ $i } li { - width: calc((100% / #{ $i }) - 1.25em + (1.25em / #{ $i })); + width: calc((100% / #{$i}) - 1.25em + (1.25em / #{$i})); - &:nth-child( #{ $i }n ) { + &:nth-child(#{ $i }n) { margin-right: 0; } } @@ -44,6 +42,15 @@ } } +:root { + :where(.wp-block-latest-posts.is-grid) { + padding: 0; + } + :where(.wp-block-latest-posts.wp-block-latest-posts__list) { + padding-left: 0; + } +} + .wp-block-latest-posts__post-date, .wp-block-latest-posts__post-author { display: block; diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index c5ef8e9204b32d..ba36acf139a626 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -1617,10 +1617,16 @@ function block_core_navigation_update_ignore_hooked_blocks_meta( $post ) { $rest_insert_wp_navigation_core_callback = 'block_core_navigation_' . 'update_ignore_hooked_blocks_meta'; // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found /* - * Injection of hooked blocks into the Navigation block relies on some functions present in WP >= 6.5 - * that are not present in Gutenberg's WP 6.5 compatibility layer. + * Do not add the `block_core_navigation_update_ignore_hooked_blocks_meta` filter in the following cases: + * - If Core has added the `update_ignored_hooked_blocks_postmeta` filter already (WP >= 6.6); + * - or if the `set_ignored_hooked_blocks_metadata` function is unavailable (which is required for the filter to work. It was introduced by WP 6.5 but is not present in Gutenberg's WP 6.5 compatibility layer); + * - or if the `$rest_insert_wp_navigation_core_callback` filter has already been added. */ -if ( function_exists( 'set_ignored_hooked_blocks_metadata' ) && ! has_filter( 'rest_pre_insert_wp_navigation', $rest_insert_wp_navigation_core_callback ) ) { +if ( + ! has_filter( 'rest_pre_insert_wp_navigation', 'update_ignored_hooked_blocks_postmeta' ) && + function_exists( 'set_ignored_hooked_blocks_metadata' ) && + ! has_filter( 'rest_pre_insert_wp_navigation', $rest_insert_wp_navigation_core_callback ) +) { add_filter( 'rest_pre_insert_wp_navigation', 'block_core_navigation_update_ignore_hooked_blocks_meta' ); } diff --git a/packages/block-library/src/pullquote/editor.scss b/packages/block-library/src/pullquote/editor.scss index 7b985d8020c9fe..deb325849ebebf 100644 --- a/packages/block-library/src/pullquote/editor.scss +++ b/packages/block-library/src/pullquote/editor.scss @@ -1,4 +1,6 @@ // .is-style-solid-color is deprecated. +// This selector has not been scoped with `:root :where`, as global styles +// does, to keep its specificity as it was at the time of deprecation. .wp-block-pullquote.is-style-solid-color { & blockquote p { font-size: 32px; diff --git a/packages/block-library/src/pullquote/style.scss b/packages/block-library/src/pullquote/style.scss index 07f6366d47617f..b9e28b7cdcfaa6 100644 --- a/packages/block-library/src/pullquote/style.scss +++ b/packages/block-library/src/pullquote/style.scss @@ -2,6 +2,8 @@ text-align: center; // Default text-alignment where the `textAlign` attribute value isn't specified. overflow-wrap: break-word; // Break long strings of text without spaces so they don't overflow the block. box-sizing: border-box; + margin: 0 0 1em 0; + padding: 4em 0; p, blockquote, @@ -35,12 +37,6 @@ } } -// Lowest specificity to avoid overriding layout and global styles. -:where(.wp-block-pullquote) { - margin: 0 0 1em 0; - padding: 4em 0; -} - // Ensure that we are reasonably specific to override theme defaults. .wp-block-pullquote.has-text-align-left blockquote { text-align: left; @@ -52,6 +48,8 @@ } // .is-style-solid-color is deprecated. +// This selector has not been scoped with `:root :where`, as global styles +// does, to keep its specificity as it was at the time of deprecation. .wp-block-pullquote.is-style-solid-color { border: none; blockquote { diff --git a/packages/block-library/src/pullquote/theme.scss b/packages/block-library/src/pullquote/theme.scss index 0dc7943a770512..6b5e8401227f5b 100644 --- a/packages/block-library/src/pullquote/theme.scss +++ b/packages/block-library/src/pullquote/theme.scss @@ -1,11 +1,9 @@ -:where(.wp-block-pullquote) { +.wp-block-pullquote { border-top: 4px solid currentColor; border-bottom: 4px solid currentColor; margin-bottom: 1.75em; color: currentColor; -} -.wp-block-pullquote { cite, footer, &__citation { diff --git a/packages/block-library/src/quote/theme.scss b/packages/block-library/src/quote/theme.scss index aaf63b899771b0..5bcccbd60eefc4 100644 --- a/packages/block-library/src/quote/theme.scss +++ b/packages/block-library/src/quote/theme.scss @@ -1,4 +1,4 @@ -:where(.wp-block-quote) { +.wp-block-quote { border-left: 0.25em solid currentColor; margin: 0 0 1.75em 0; padding-left: 1em; diff --git a/packages/block-library/src/separator/editor.scss b/packages/block-library/src/separator/editor.scss index 220c6bd9d80e38..24e940684279e8 100644 --- a/packages/block-library/src/separator/editor.scss +++ b/packages/block-library/src/separator/editor.scss @@ -2,11 +2,4 @@ // Prevent margin collapsing so the area to select the separator is bigger. padding-top: 0.1px; padding-bottom: 0.1px; - - // This is also set in style.scss, but needs a higher specificity in editor - // due to the way that color block supports adds additional background color styles. - &.wp-block-separator.is-style-dots { - background: none !important; - border: none; - } } diff --git a/packages/block-library/src/separator/style.scss b/packages/block-library/src/separator/style.scss index d40dd2f05844ed..65e463bc513f48 100644 --- a/packages/block-library/src/separator/style.scss +++ b/packages/block-library/src/separator/style.scss @@ -1,28 +1,4 @@ .wp-block-separator { - // Dots style - &.is-style-dots { - // Override any background themes often set on the hr tag for this style. - // also override the color set in the editor since it's intented for normal HR - background: none !important; - border: none; - text-align: center; - line-height: 1; - height: auto; - - &::before { - content: "\00b7 \00b7 \00b7"; - color: currentColor; - font-size: 1.5em; - letter-spacing: 2em; - /*rtl:ignore*/ - padding-left: 2em; - font-family: serif; - } - } -} - -// Lowest specificity to avoid overriding global styles. -:where(.wp-block-separator) { border-top: 2px solid currentColor; // Default, thin style, is stored in theme.scss so it can be opted out of @@ -31,3 +7,31 @@ border-right: none; border-bottom: none; } + +// Dots block style variation +:root :where(.wp-block-separator.is-style-dots) { + text-align: center; + line-height: 1; + height: auto; + + &::before { + content: "\00b7 \00b7 \00b7"; + color: currentColor; + font-size: 1.5em; + letter-spacing: 2em; + /*rtl:ignore*/ + padding-left: 2em; + font-family: serif; + } +} + +// The following overrides should be enforced regardless of global styles. +// The dots block style uses a pseudo element to render the dots. Background +// color and borders would break this aesthetic. +.wp-block-separator.is-style-dots { + // Override any background themes often set on the hr tag for this style. + // also override the color set in the editor since it's intended for normal HR + background: none !important; + // Important required to ensure dots does not get a border. + border: none !important; +} diff --git a/packages/block-library/src/site-logo/edit.js b/packages/block-library/src/site-logo/edit.js index 3192f2b000346e..046b5feeb20c99 100644 --- a/packages/block-library/src/site-logo/edit.js +++ b/packages/block-library/src/site-logo/edit.js @@ -73,7 +73,6 @@ const SiteLogo = ( { const [ { naturalWidth, naturalHeight }, setNaturalSize ] = useState( {} ); const [ isEditingImage, setIsEditingImage ] = useState( false ); const { toggleSelection } = useDispatch( blockEditorStore ); - const classes = clsx( 'custom-logo-link' ); const { imageEditing, maxWidth, title } = useSelect( ( select ) => { const settings = select( blockEditorStore ).getSettings(); const siteEntities = select( coreStore ).getEntityRecord( @@ -136,7 +135,7 @@ const SiteLogo = ( { /* eslint-disable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */ event.preventDefault() } diff --git a/packages/block-library/src/site-logo/style.scss b/packages/block-library/src/site-logo/style.scss index ca9c92539b6760..020b7aab5370b3 100644 --- a/packages/block-library/src/site-logo/style.scss +++ b/packages/block-library/src/site-logo/style.scss @@ -31,11 +31,11 @@ margin-right: auto; text-align: center; } +} - // Style variations - &.is-style-rounded { - // We use an absolute pixel to prevent the oval shape that a value of 50% would give - // to rectangular images. A pill-shape is better than otherwise. - border-radius: 9999px; - } +// Style variations +:root :where(.wp-block-site-logo.is-style-rounded) { + // We use an absolute pixel to prevent the oval shape that a value of 50% would give + // to rectangular images. A pill-shape is better than otherwise. + border-radius: 9999px; } diff --git a/packages/block-library/src/site-title/editor.scss b/packages/block-library/src/site-title/editor.scss index 173e4570929a51..ce83659170ff6f 100644 --- a/packages/block-library/src/site-title/editor.scss +++ b/packages/block-library/src/site-title/editor.scss @@ -3,8 +3,6 @@ border: 1px dashed; } -.editor-styles-wrapper .wp-block-site-title { - a { - color: inherit; - } +.editor-styles-wrapper :where(.wp-block-site-title a) { + color: inherit; } diff --git a/packages/block-library/src/site-title/style.scss b/packages/block-library/src/site-title/style.scss index afc6f449f4025b..337c82f79ad354 100644 --- a/packages/block-library/src/site-title/style.scss +++ b/packages/block-library/src/site-title/style.scss @@ -1,5 +1,3 @@ -.wp-block-site-title { - a { - color: inherit; - } +:root :where(.wp-block-site-title a) { + color: inherit; } diff --git a/packages/block-library/src/social-link/editor.scss b/packages/block-library/src/social-link/editor.scss index 73211958b48c15..bd93ad9f055fcd 100644 --- a/packages/block-library/src/social-link/editor.scss +++ b/packages/block-library/src/social-link/editor.scss @@ -31,11 +31,11 @@ } } -.wp-block-social-links.is-style-pill-shape .wp-social-link button { +:root :where(.wp-block-social-links.is-style-pill-shape .wp-social-link button) { padding-left: calc((2/3) * 1em); padding-right: calc((2/3) * 1em); } -.wp-block-social-links.is-style-logos-only .wp-social-link button { +:root :where(.wp-block-social-links.is-style-logos-only .wp-social-link button) { padding: 0; } diff --git a/packages/block-library/src/social-links/editor.scss b/packages/block-library/src/social-links/editor.scss index b729949c837d80..6f07ea209ecbea 100644 --- a/packages/block-library/src/social-links/editor.scss +++ b/packages/block-library/src/social-links/editor.scss @@ -11,9 +11,19 @@ transform: none; } -.editor-styles-wrapper .wp-block-social-links { +// Specificity for the following styles are fixed at 0-1-0 to match and be +// overridable by global styles. +:root :where(.wp-block-social-links), +:root :where(.wp-block-social-links.is-style-logos-only .wp-block-social-links__social-placeholder .wp-social-link) { padding: 0; } +:root :where(.wp-block-social-links__social-placeholder .wp-social-link) { + padding: 0.25em; +} +:root :where(.wp-block-social-links.is-style-pill-shape .wp-block-social-links__social-placeholder .wp-social-link) { + padding-left: calc((2/3) * 1em); + padding-right: calc((2/3) * 1em); +} // Placeholder/setup state. .wp-block-social-links__social-placeholder { @@ -37,19 +47,6 @@ display: flex; } - .wp-social-link { - padding: 0.25em; - - .is-style-pill-shape & { - padding-left: calc((2/3) * 1em); - padding-right: calc((2/3) * 1em); - } - - .is-style-logos-only & { - padding: 0; - } - } - .wp-social-link::before { content: ""; display: block; diff --git a/packages/block-library/src/social-links/style.scss b/packages/block-library/src/social-links/style.scss index 1ad883bbb88840..f04c11ea07acd3 100644 --- a/packages/block-library/src/social-links/style.scss +++ b/packages/block-library/src/social-links/style.scss @@ -21,12 +21,6 @@ } .wp-social-link { - // By setting the font size, we can scale icons and paddings consistently based on that. - // This also allows themes to override this, if need be. - a { - padding: 0.25em; - } - svg { width: 1em; height: 1em; @@ -119,14 +113,13 @@ } // Treatment for logos only style. +// The specificity for this selector has not been reduced to 0-1-0 as per +// global styles variation selectors as the lack of background should be +// enforced for this block style. .wp-block-social-links.is-style-logos-only { .wp-social-link { background: none; - a { - padding: 0; - } - // Make these bigger. svg { width: 1.25em; @@ -142,11 +135,19 @@ .wp-social-link { width: auto; } +} - .wp-social-link a { - padding-left: calc((2/3) * 1em); - padding-right: calc((2/3) * 1em); - } +// The following rules have their selector specificity set to 0-1-0 to +// facilitate theme.json styling of the inner social-link block padding. +:root :where(.wp-block-social-links .wp-social-link a) { + padding: 0.25em; +} +:root :where(.wp-block-social-links.is-style-logos-only .wp-social-link a) { + padding: 0; +} +:root :where(.wp-block-social-links.is-style-pill-shape .wp-social-link a) { + padding-left: calc((2/3) * 1em); + padding-right: calc((2/3) * 1em); } // Ensure the Snapchat label is visible when no custom diff --git a/packages/block-library/src/table/style.scss b/packages/block-library/src/table/style.scss index 4f4271650f50e1..69cd2666e13e20 100644 --- a/packages/block-library/src/table/style.scss +++ b/packages/block-library/src/table/style.scss @@ -71,6 +71,9 @@ } // "Stripes" style variation. + // This block style selector does not have 0-1-0 specificity, as per those + // generated via global styles, to maintain current styling. Global styles + // support for table borders also only applies to the outer `table` element. &.is-style-stripes { border-spacing: 0; border-collapse: inherit; diff --git a/packages/block-library/src/table/theme.scss b/packages/block-library/src/table/theme.scss index 19dc71c8857bd7..d42e79b02b4965 100644 --- a/packages/block-library/src/table/theme.scss +++ b/packages/block-library/src/table/theme.scss @@ -1,4 +1,6 @@ .wp-block-table { + margin: 0 0 1em 0; + td, th { word-break: normal; @@ -8,7 +10,3 @@ @include caption-style-theme(); } } - -:where(.wp-block-table) { - margin: 0 0 1em 0; -} diff --git a/packages/block-library/src/tag-cloud/style.scss b/packages/block-library/src/tag-cloud/style.scss index 5fb04840de1517..dedb5e73ab1a1f 100644 --- a/packages/block-library/src/tag-cloud/style.scss +++ b/packages/block-library/src/tag-cloud/style.scss @@ -22,18 +22,20 @@ margin-left: 5px; text-decoration: none; } +} - &.is-style-outline { - display: flex; - flex-wrap: wrap; - gap: 1ch; - - a { - border: 1px solid currentColor; - font-size: unset !important; // !important Needed to override the inline styles. - margin-right: 0; - padding: 1ch 2ch; - text-decoration: none !important; // !important needed to override generic post content link decoration. - } - } +// Specificity is set to 0-1-0 to match global styles selectors. +:root :where(.wp-block-tag-cloud.is-style-outline) { + display: flex; + flex-wrap: wrap; + gap: 1ch; +} +// The block support related styles below haven't been replicated in the base theme.json +// as the block doesn't yet adopt them for its inner links. +:root :where(.wp-block-tag-cloud.is-style-outline a) { + border: 1px solid currentColor; + font-size: unset !important; // !important Needed to override the inline styles. + margin-right: 0; + padding: 1ch 2ch; + text-decoration: none !important; // !important needed to override generic post content link decoration. } diff --git a/packages/block-library/src/template-part/theme.scss b/packages/block-library/src/template-part/theme.scss index 2f1d3a0a513cb7..179873b9448b82 100644 --- a/packages/block-library/src/template-part/theme.scss +++ b/packages/block-library/src/template-part/theme.scss @@ -1,9 +1,7 @@ // Same as the group block styles. -:where(.wp-block-template-part) { - &.has-background { - // Matches paragraph Block padding - padding: $block-bg-padding--v $block-bg-padding--h; - margin-top: 0; - margin-bottom: 0; - } +:root :where(.wp-block-template-part.has-background) { + // Matches paragraph Block padding + padding: $block-bg-padding--v $block-bg-padding--h; + margin-top: 0; + margin-bottom: 0; } diff --git a/packages/block-library/src/video/theme.scss b/packages/block-library/src/video/theme.scss index c5399582bbb281..cdc95af0b02c29 100644 --- a/packages/block-library/src/video/theme.scss +++ b/packages/block-library/src/video/theme.scss @@ -2,6 +2,6 @@ @include caption-style-theme(); } -:where(.wp-block-video) { +.wp-block-video { margin: 0 0 1em 0; } diff --git a/packages/components/src/animate/index.tsx b/packages/components/src/animate/index.tsx index e7aaf72d243801..e819020447bc9e 100644 --- a/packages/components/src/animate/index.tsx +++ b/packages/components/src/animate/index.tsx @@ -23,7 +23,7 @@ function getDefaultOrigin( type?: GetAnimateOptions[ 'type' ] ) { */ export function getAnimateClassName( options: GetAnimateOptions ) { if ( options.type === 'loading' ) { - return clsx( 'components-animate__loading' ); + return 'components-animate__loading'; } const { type, origin = getDefaultOrigin( type ) } = options; diff --git a/packages/components/src/focal-point-picker/focal-point.tsx b/packages/components/src/focal-point-picker/focal-point.tsx index 7a401eb4c6870b..a03e41d4809cce 100644 --- a/packages/components/src/focal-point-picker/focal-point.tsx +++ b/packages/components/src/focal-point-picker/focal-point.tsx @@ -6,7 +6,6 @@ import { PointerCircle } from './styles/focal-point-style'; /** * External dependencies */ -import clsx from 'clsx'; import type { FocalPointProps } from './types'; import type { WordPressComponentProps } from '../context'; @@ -15,9 +14,13 @@ export default function FocalPoint( { top = '50%', ...props }: WordPressComponentProps< FocalPointProps, 'div' > ) { - const classes = clsx( 'components-focal-point-picker__icon_container' ); - const style = { left, top }; - return ; + return ( + + ); } diff --git a/packages/compose/README.md b/packages/compose/README.md index 83bde196033a01..c60d202f59aacf 100644 --- a/packages/compose/README.md +++ b/packages/compose/README.md @@ -265,11 +265,11 @@ Helper hook for input fields that need to debounce the value before using it. _Parameters_ -- _defaultValue_ `any`: The default value to use. +- _defaultValue_ The default value to use. _Returns_ -- `[string, Function, string]`: The input value, the setter and the debounced input value. +- `[ string, ( value: string ) => void, string ]`: The input value, the setter and the debounced input value. ### useDisabled diff --git a/packages/compose/src/hooks/use-debounced-input/index.js b/packages/compose/src/hooks/use-debounced-input/index.ts similarity index 60% rename from packages/compose/src/hooks/use-debounced-input/index.js rename to packages/compose/src/hooks/use-debounced-input/index.ts index 91a01073fcfee8..643b0ba68026c3 100644 --- a/packages/compose/src/hooks/use-debounced-input/index.js +++ b/packages/compose/src/hooks/use-debounced-input/index.ts @@ -11,18 +11,20 @@ import useDebounce from '../use-debounce'; /** * Helper hook for input fields that need to debounce the value before using it. * - * @param {any} defaultValue The default value to use. - * @return {[string, Function, string]} The input value, the setter and the debounced input value. + * @param defaultValue The default value to use. + * @return The input value, the setter and the debounced input value. */ -export default function useDebouncedInput( defaultValue = '' ) { - const [ input, setInput ] = useState( defaultValue ); +export default function useDebouncedInput( + defaultValue = '' +): [ string, ( value: string ) => void, string ] { + const [ input, setInput ] = useState< string >( defaultValue ); const [ debouncedInput, setDebouncedState ] = useState( defaultValue ); const setDebouncedInput = useDebounce( setDebouncedState, 250 ); useEffect( () => { setDebouncedInput( input ); - }, [ input ] ); + }, [ input, setDebouncedInput ] ); return [ input, setInput, debouncedInput ]; } diff --git a/packages/dataviews/src/bulk-actions-toolbar.tsx b/packages/dataviews/src/bulk-actions-toolbar.tsx index e7c4a23ff758c9..c2b3644b88bceb 100644 --- a/packages/dataviews/src/bulk-actions-toolbar.tsx +++ b/packages/dataviews/src/bulk-actions-toolbar.tsx @@ -31,14 +31,14 @@ interface ToolbarContentProps< Item extends AnyItem > { selection: string[]; actionsToShow: Action< Item >[]; selectedItems: Item[]; - setSelection: ( selection: Item[] ) => void; + onSelectionChange: ( selection: Item[] ) => void; } interface BulkActionsToolbarProps< Item extends AnyItem > { data: Item[]; selection: string[]; actions: Action< Item >[]; - setSelection: ( selection: Item[] ) => void; + onSelectionChange: ( selection: Item[] ) => void; getItemId: ( item: Item ) => string; } @@ -123,7 +123,7 @@ function renderToolbarContent< Item extends AnyItem >( selectedItems: Item[], actionInProgress: string | null, setActionInProgress: ( actionId: string | null ) => void, - setSelection: ( selection: Item[] ) => void + onSelectionChange: ( selection: Item[] ) => void ) { return ( <> @@ -163,7 +163,7 @@ function renderToolbarContent< Item extends AnyItem >( label={ __( 'Cancel' ) } disabled={ !! actionInProgress } onClick={ () => { - setSelection( EMPTY_ARRAY ); + onSelectionChange( EMPTY_ARRAY ); } } /> @@ -175,7 +175,7 @@ function ToolbarContent< Item extends AnyItem >( { selection, actionsToShow, selectedItems, - setSelection, + onSelectionChange, }: ToolbarContentProps< Item > ) { const [ actionInProgress, setActionInProgress ] = useState< string | null >( null @@ -191,7 +191,7 @@ function ToolbarContent< Item extends AnyItem >( { selectedItems, actionInProgress, setActionInProgress, - setSelection + onSelectionChange ); } else if ( ! buttons.current ) { buttons.current = renderToolbarContent( @@ -200,7 +200,7 @@ function ToolbarContent< Item extends AnyItem >( { selectedItems, actionInProgress, setActionInProgress, - setSelection + onSelectionChange ); } return buttons.current; @@ -210,7 +210,7 @@ export default function BulkActionsToolbar< Item extends AnyItem >( { data, selection, actions = EMPTY_ARRAY, - setSelection, + onSelectionChange, getItemId, }: BulkActionsToolbarProps< Item > ) { const isReducedMotion = useReducedMotion(); @@ -258,7 +258,7 @@ export default function BulkActionsToolbar< Item extends AnyItem >( { selection={ selection } actionsToShow={ actionsToShow } selectedItems={ selectedItems } - setSelection={ setSelection } + onSelectionChange={ onSelectionChange } /> diff --git a/packages/dataviews/src/dataviews.js b/packages/dataviews/src/dataviews.tsx similarity index 73% rename from packages/dataviews/src/dataviews.js rename to packages/dataviews/src/dataviews.tsx index 75b672721f0419..875746ceb52c38 100644 --- a/packages/dataviews/src/dataviews.js +++ b/packages/dataviews/src/dataviews.tsx @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import type { ComponentType } from 'react'; + /** * WordPress dependencies */ @@ -16,21 +21,46 @@ import { VIEW_LAYOUTS } from './layouts'; import BulkActions from './bulk-actions'; import { normalizeFields } from './normalize-fields'; import BulkActionsToolbar from './bulk-actions-toolbar'; +import type { Action, AnyItem, Field, View, ViewBaseProps } from './types'; + +interface DataViewsProps< Item extends AnyItem > { + view: View; + onChangeView: ( view: View ) => void; + fields: Field< Item >[]; + search?: boolean; + searchLabel?: string; + actions?: Action< Item >[]; + data: Item[]; + getItemId?: ( item: Item ) => string; + isLoading?: boolean; + paginationInfo: { + totalItems: number; + totalPages: number; + }; + supportedLayouts: string[]; + onSelectionChange?: ( items: Item[] ) => void; +} -const defaultGetItemId = ( item ) => item.id; +const defaultGetItemId = ( item: AnyItem ) => item.id; const defaultOnSelectionChange = () => {}; -function useSomeItemHasAPossibleBulkAction( actions, data ) { +function useSomeItemHasAPossibleBulkAction< Item extends AnyItem >( + actions: Action< Item >[], + data: Item[] +) { return useMemo( () => { return data.some( ( item ) => { return actions.some( ( action ) => { - return action.supportsBulk && action.isEligible( item ); + return ( + action.supportsBulk && + ( ! action.isEligible || action.isEligible( item ) ) + ); } ); } ); }, [ actions, data ] ); } -export default function DataViews( { +export default function DataViews< Item extends AnyItem >( { view, onChangeView, fields, @@ -43,9 +73,9 @@ export default function DataViews( { paginationInfo, supportedLayouts, onSelectionChange = defaultOnSelectionChange, -} ) { - const [ selection, setSelection ] = useState( [] ); - const [ openedFilter, setOpenedFilter ] = useState( null ); +}: DataViewsProps< Item > ) { + const [ selection, setSelection ] = useState< string[] >( [] ); + const [ openedFilter, setOpenedFilter ] = useState< string | null >( null ); useEffect( () => { if ( @@ -67,16 +97,15 @@ export default function DataViews( { }, [ selection, data, getItemId, onSelectionChange ] ); const onSetSelection = useCallback( - ( items ) => { + ( items: Item[] ) => { setSelection( items.map( ( item ) => getItemId( item ) ) ); onSelectionChange( items ); }, [ setSelection, getItemId, onSelectionChange ] ); - const ViewComponent = VIEW_LAYOUTS.find( - ( v ) => v.type === view.type - ).component; + const ViewComponent = VIEW_LAYOUTS.find( ( v ) => v.type === view.type ) + ?.component as ComponentType< ViewBaseProps< Item > >; const _fields = useMemo( () => normalizeFields( fields ), [ fields ] ); const hasPossibleBulkAction = useSomeItemHasAPossibleBulkAction( @@ -150,7 +179,7 @@ export default function DataViews( { data={ data } actions={ actions } selection={ selection } - setSelection={ setSelection } + onSelectionChange={ onSetSelection } getItemId={ getItemId } /> ) } diff --git a/packages/dataviews/src/filters.tsx b/packages/dataviews/src/filters.tsx index df7a13b2953f16..0cf017fce191b1 100644 --- a/packages/dataviews/src/filters.tsx +++ b/packages/dataviews/src/filters.tsx @@ -22,7 +22,7 @@ interface FiltersProps< Item extends AnyItem > { setOpenedFilter: ( openedFilter: string | null ) => void; } -const Filters = memo( function Filters< Item extends AnyItem >( { +function _Filters< Item extends AnyItem >( { fields, view, onChangeView, @@ -117,6 +117,9 @@ const Filters = memo( function Filters< Item extends AnyItem >( { { filterComponents } ); -} ); +} + +// A type assertion is used here to keep the type argument. +const Filters = memo( _Filters ) as typeof _Filters; export default Filters; diff --git a/packages/dataviews/src/index.js b/packages/dataviews/src/index.ts similarity index 100% rename from packages/dataviews/src/index.js rename to packages/dataviews/src/index.ts diff --git a/packages/dataviews/src/search.js b/packages/dataviews/src/search.tsx similarity index 65% rename from packages/dataviews/src/search.js rename to packages/dataviews/src/search.tsx index 13a828c330575a..7929a9bd0eb3cb 100644 --- a/packages/dataviews/src/search.js +++ b/packages/dataviews/src/search.tsx @@ -6,20 +6,37 @@ import { useEffect, useRef, memo } from '@wordpress/element'; import { SearchControl } from '@wordpress/components'; import { useDebouncedInput } from '@wordpress/compose'; -const Search = memo( function Search( { label, view, onChangeView } ) { +/** + * Internal dependencies + */ +import type { View } from './types'; + +interface SearchProps { + label?: string; + view: View; + onChangeView: ( view: View ) => void; +} + +const Search = memo( function Search( { + label, + view, + onChangeView, +}: SearchProps ) { const [ search, setSearch, debouncedSearch ] = useDebouncedInput( view.search ); useEffect( () => { - setSearch( view.search ); - }, [ view ] ); + setSearch( view.search ?? '' ); + }, [ view.search, setSearch ] ); const onChangeViewRef = useRef( onChangeView ); + const viewRef = useRef( view ); useEffect( () => { onChangeViewRef.current = onChangeView; - }, [ onChangeView ] ); + viewRef.current = view; + }, [ onChangeView, view ] ); useEffect( () => { onChangeViewRef.current( { - ...view, + ...viewRef.current, page: 1, search: debouncedSearch, } ); diff --git a/packages/dataviews/src/types.ts b/packages/dataviews/src/types.ts index 58b0bffc922966..f7e6274d83928e 100644 --- a/packages/dataviews/src/types.ts +++ b/packages/dataviews/src/types.ts @@ -373,15 +373,35 @@ export type Action< Item extends AnyItem > = | ActionModal< Item > | ActionButton< Item >; -export interface ViewProps< Item extends AnyItem, ViewType extends ViewBase > { +export interface ViewBaseProps< Item extends AnyItem > { actions: Action< Item >[]; data: Item[]; fields: NormalizedField< Item >[]; getItemId: ( item: Item ) => string; isLoading?: boolean; - onChangeView( view: ViewType ): void; + onChangeView( view: View ): void; onSelectionChange: ( items: Item[] ) => void; selection: string[]; setOpenedFilter: ( fieldId: string ) => void; - view: ViewType; + view: View; } + +export interface ViewTableProps< Item extends AnyItem > + extends ViewBaseProps< Item > { + view: ViewTable; +} + +export interface ViewListProps< Item extends AnyItem > + extends ViewBaseProps< Item > { + view: ViewList; +} + +export interface ViewGridProps< Item extends AnyItem > + extends ViewBaseProps< Item > { + view: ViewGrid; +} + +export type ViewProps< Item extends AnyItem > = + | ViewTableProps< Item > + | ViewGridProps< Item > + | ViewListProps< Item >; diff --git a/packages/dataviews/src/view-actions.tsx b/packages/dataviews/src/view-actions.tsx index 0e041cc070c525..90098417575315 100644 --- a/packages/dataviews/src/view-actions.tsx +++ b/packages/dataviews/src/view-actions.tsx @@ -303,7 +303,7 @@ function SortMenu< Item extends AnyItem >( { ); } -const ViewActions = memo( function ViewActions< Item extends AnyItem >( { +function _ViewActions< Item extends AnyItem >( { fields, view, onChangeView, @@ -339,6 +339,9 @@ const ViewActions = memo( function ViewActions< Item extends AnyItem >( { ); -} ); +} + +// A type assertion is used here to keep the type argument. +const ViewActions = memo( _ViewActions ) as typeof _ViewActions; export default ViewActions; diff --git a/packages/dataviews/src/view-grid.tsx b/packages/dataviews/src/view-grid.tsx index f42ec215be9d23..5c6b8ba5bc3b50 100644 --- a/packages/dataviews/src/view-grid.tsx +++ b/packages/dataviews/src/view-grid.tsx @@ -22,16 +22,7 @@ import { __ } from '@wordpress/i18n'; import ItemActions from './item-actions'; import SingleSelectionCheckbox from './single-selection-checkbox'; import { useHasAPossibleBulkAction } from './bulk-actions'; -import type { - Action, - AnyItem, - NormalizedField, - ViewGrid as ViewGridType, - ViewProps, -} from './types'; - -interface ViewGridProps< Item extends AnyItem > - extends ViewProps< Item, ViewGridType > {} +import type { Action, AnyItem, NormalizedField, ViewGridProps } from './types'; interface GridItemProps< Item extends AnyItem > { selection: string[]; diff --git a/packages/dataviews/src/view-list.tsx b/packages/dataviews/src/view-list.tsx index f829b505454b30..1e7a558bbad5eb 100644 --- a/packages/dataviews/src/view-list.tsx +++ b/packages/dataviews/src/view-list.tsx @@ -32,19 +32,10 @@ import { moreVertical } from '@wordpress/icons'; * Internal dependencies */ import { unlock } from './lock-unlock'; -import type { - Action, - AnyItem, - NormalizedField, - ViewList as ViewListType, - ViewProps, -} from './types'; +import type { Action, AnyItem, NormalizedField, ViewListProps } from './types'; import { ActionsDropdownMenuGroup, ActionModal } from './item-actions'; -interface ViewListProps< Item extends AnyItem > - extends ViewProps< Item, ViewListType > {} - interface ListViewItemProps< Item extends AnyItem > { actions: Action< Item >[]; id?: string; diff --git a/packages/dataviews/src/view-table.tsx b/packages/dataviews/src/view-table.tsx index 9ecfa9c9c0770d..dcfb8a67bf3636 100644 --- a/packages/dataviews/src/view-table.tsx +++ b/packages/dataviews/src/view-table.tsx @@ -50,8 +50,8 @@ import type { AnyItem, NormalizedField, SortDirection, - ViewProps, ViewTable as ViewTableType, + ViewTableProps, } from './types'; const { @@ -91,9 +91,6 @@ interface TableRowProps< Item extends AnyItem > { data: Item[]; } -interface ViewTableProps< Item extends AnyItem > - extends ViewProps< Item, ViewTableType > {} - function WithDropDownMenuSeparators( { children }: { children: ReactNode } ) { return Children.toArray( children ) .filter( Boolean ) diff --git a/packages/e2e-tests/plugins/interactive-blocks/namespace/render.php b/packages/e2e-tests/plugins/interactive-blocks/namespace/render.php index 6fdc2d07e350c8..0b7e40b6c1653b 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/namespace/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/namespace/render.php @@ -18,6 +18,28 @@ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+
+ +
diff --git a/packages/e2e-tests/plugins/interactive-blocks/namespace/view.js b/packages/e2e-tests/plugins/interactive-blocks/namespace/view.js index 9225f88ce9d279..5717387395ff24 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/namespace/view.js +++ b/packages/e2e-tests/plugins/interactive-blocks/namespace/view.js @@ -3,9 +3,16 @@ */ import { store } from '@wordpress/interactivity'; + +store( '', { + state: { + url: '/empty-string-url', + }, +} ); + store( 'namespace', { state: { - url: '/some-url', + url: '/namespace-url', }, } ); @@ -14,3 +21,50 @@ store( 'other', { url: '/other-store-url', }, } ); + +store( 'null', { + state: { + url: '/null-url', + }, +} ); + +store( '2', { + state: { + url: '/number-url', + }, +} ); + +store( '{}', { + state: { + url: '/object-url', + }, +} ); + +store( 'true', { + state: { + url: '/true-url', + }, +} ); + +store( 'false', { + state: { + url: '/false-url', + }, +} ); + +store( '[]', { + state: { + url: '/array-url', + }, +} ); + +store( '"quoted string"', { + state: { + url: '/quoted-url', + }, +} ); + + + + + diff --git a/packages/edit-site/src/components/dataviews-actions/index.js b/packages/edit-site/src/components/dataviews-actions/index.js index ed6522995d3b7b..09b7597c6cb341 100644 --- a/packages/edit-site/src/components/dataviews-actions/index.js +++ b/packages/edit-site/src/components/dataviews-actions/index.js @@ -9,6 +9,7 @@ import { privateApis as routerPrivateApis } from '@wordpress/router'; /** * Internal dependencies */ +import { PATTERN_TYPES } from '../../utils/constants'; import { unlock } from '../../lock-unlock'; const { useHistory } = unlock( routerPrivateApis ); @@ -21,8 +22,12 @@ export const useEditPostAction = () => { label: __( 'Edit' ), isPrimary: true, icon: edit, - isEligible( { status } ) { - return status !== 'trash'; + isEligible( post ) { + if ( post.status === 'trash' ) { + return false; + } + // It's eligible for all post types except theme patterns. + return post.type !== PATTERN_TYPES.theme; }, callback( items ) { const post = items[ 0 ]; diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index ba4d751de5ae08..b7fc350c3eabb9 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -213,6 +213,7 @@ export default function Editor( { isLoading } ) { ( actionId, items ) => { switch ( actionId ) { case 'move-to-trash': + case 'delete-post': { history.push( { postType: items[ 0 ].type, diff --git a/packages/edit-site/src/components/global-styles/background-panel.js b/packages/edit-site/src/components/global-styles/background-panel.js index 0ad74e0cd0bdd5..8a372587bc66e5 100644 --- a/packages/edit-site/src/components/global-styles/background-panel.js +++ b/packages/edit-site/src/components/global-styles/background-panel.js @@ -2,7 +2,6 @@ * WordPress dependencies */ import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; -import { __ } from '@wordpress/i18n'; /** * Internal dependencies @@ -59,7 +58,6 @@ export default function BackgroundPanel() { value={ style } onChange={ setStyle } settings={ settings } - headerLabel={ __( 'Background' ) } defaultValues={ BACKGROUND_DEFAULT_VALUES } defaultControls={ defaultControls } themeFileURIs={ _links?.[ 'wp:theme-file' ] } diff --git a/packages/edit-site/src/components/save-panel/index.js b/packages/edit-site/src/components/save-panel/index.js index 87621638b233fe..1f784edc52234f 100644 --- a/packages/edit-site/src/components/save-panel/index.js +++ b/packages/edit-site/src/components/save-panel/index.js @@ -151,9 +151,7 @@ export default function SavePanel() { > + + + + ); + }, +}; + const trashPostAction = { id: 'move-to-trash', label: __( 'Move to Trash' ), @@ -55,7 +164,7 @@ const trashPostAction = { supportsBulk: true, hideModalHeader: true, RenderModal: ( { - items: posts, + items, closeModal, onActionStart, onActionPerformed, @@ -67,20 +176,22 @@ const trashPostAction = { return ( - { posts.length === 1 + { items.length === 1 ? sprintf( - // translators: %s: The page's title. - __( 'Are you sure you want to delete "%s"?' ), - getItemTitle( posts[ 0 ] ) + // translators: %s: The item's title. + __( + 'Are you sure you want to move to trash "%s"?' + ), + getItemTitle( items[ 0 ] ) ) : sprintf( - // translators: %d: The number of pages (2 or more). + // translators: %d: The number of items (2 or more). _n( - 'Are you sure you want to delete %d page?', - 'Are you sure you want to delete %d pages?', - posts.length + 'Are you sure you want to move to trash %d item?', + 'Are you sure you want to move to trash %d items?', + items.length ), - posts.length + items.length ) } @@ -97,18 +208,18 @@ const trashPostAction = { onClick={ async () => { setIsBusy( true ); if ( onActionStart ) { - onActionStart( posts ); + onActionStart( items ); } const promiseResult = await Promise.allSettled( - posts.map( ( post ) => { - return deleteEntityRecord( + items.map( ( item ) => + deleteEntityRecord( 'postType', - post.type, - post.id, + item.type, + item.id, {}, { throwOnError: true } - ); - } ) + ) + ) ); // If all the promises were fulfilled with success. if ( @@ -119,41 +230,41 @@ const trashPostAction = { let successMessage; if ( promiseResult.length === 1 ) { successMessage = sprintf( - /* translators: The posts's title. */ - __( '"%s" moved to the Trash.' ), - getItemTitle( posts[ 0 ] ) + /* translators: The item's title. */ + __( '"%s" moved to trash.' ), + getItemTitle( items[ 0 ] ) ); - } else if ( posts[ 0 ].type === 'page' ) { + } else if ( items[ 0 ].type === 'page' ) { successMessage = sprintf( - /* translators: The number of pages. */ - __( '%s pages moved to the Trash.' ), - posts.length + /* translators: The number of items. */ + __( '%s items moved to trash.' ), + items.length ); } else { successMessage = sprintf( /* translators: The number of posts. */ - __( '%s posts moved to the Trash.' ), - posts.length + __( '%s items move to trash.' ), + items.length ); } createSuccessNotice( successMessage, { type: 'snackbar', - id: 'trash-post-action', + id: 'move-to-trash-action', } ); } else { - // If there was at lease one failure. + // If there was at least one failure. let errorMessage; - // If we were trying to move a single post to the trash. + // If we were trying to delete a single item. if ( promiseResult.length === 1 ) { if ( promiseResult[ 0 ].reason?.message ) { errorMessage = promiseResult[ 0 ].reason.message; } else { errorMessage = __( - 'An error occurred while moving the post to the trash.' + 'An error occurred while moving to trash the item.' ); } - // If we were trying to move multiple posts to the trash + // If we were trying to delete multiple items. } else { const errorMessages = new Set(); const failedPromises = promiseResult.filter( @@ -168,13 +279,13 @@ const trashPostAction = { } if ( errorMessages.size === 0 ) { errorMessage = __( - 'An error occurred while moving the posts to the trash.' + 'An error occurred while moving to trash the items.' ); } else if ( errorMessages.size === 1 ) { errorMessage = sprintf( /* translators: %s: an error message */ __( - 'An error occurred while moving the posts to the trash: %s' + 'An error occurred while moving to trash the item: %s' ), [ ...errorMessages ][ 0 ] ); @@ -182,7 +293,7 @@ const trashPostAction = { errorMessage = sprintf( /* translators: %s: a list of comma separated error messages */ __( - 'Some errors occurred while moving the pages to the trash: %s' + 'Some errors occurred while moving to trash the items: %s' ), [ ...errorMessages ].join( ',' ) ); @@ -193,7 +304,7 @@ const trashPostAction = { } ); } if ( onActionPerformed ) { - onActionPerformed( posts ); + onActionPerformed( items ); } setIsBusy( false ); closeModal(); @@ -202,7 +313,7 @@ const trashPostAction = { disabled={ isBusy } __experimentalIsFocusable > - { __( 'Delete' ) } + { __( 'Trash' ) } @@ -511,7 +622,7 @@ const renamePostAction = { ) { return true; } - // In the case of templates, we can only remove custom templates. + // In the case of templates, we can only rename custom templates. if ( post.type === TEMPLATE_POST_TYPE ) { return isTemplateRemovable( post ) && post.is_custom; } @@ -850,245 +961,6 @@ const resetTemplateAction = { }, }; -/** - * Check if a template is removable. - * Copy from packages/edit-site/src/utils/is-template-removable.js. - * - * @param {Object} template The template entity to check. - * @return {boolean} Whether the template is revertable. - */ -function isTemplateRemovable( template ) { - if ( ! template ) { - return false; - } - - return ( - template.source === TEMPLATE_ORIGINS.custom && ! template.has_theme_file - ); -} - -const deleteTemplateAction = { - id: 'delete-template', - label: __( 'Delete' ), - isEligible: isTemplateRemovable, - icon: trash, - supportsBulk: true, - hideModalHeader: true, - RenderModal: ( { - items: templates, - closeModal, - onActionStart, - onActionPerformed, - } ) => { - const [ isBusy, setIsBusy ] = useState( false ); - const { removeTemplates } = unlock( useDispatch( editorStore ) ); - return ( - - - { templates.length > 1 - ? sprintf( - // translators: %d: number of items to delete. - _n( - 'Delete %d item?', - 'Delete %d items?', - templates.length - ), - templates.length - ) - : sprintf( - // translators: %s: The template or template part's titles - __( 'Delete "%s"?' ), - decodeEntities( - templates?.[ 0 ]?.title?.rendered - ) - ) } - - - - - - - ); - }, -}; - -const canDeleteOrReset = ( item ) => { - const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE; - const isUserPattern = item.type === PATTERN_TYPES.user; - return isUserPattern || ( isTemplatePart && item.isCustom ); -}; - -export const deletePatternAction = { - id: 'delete-pattern', - label: __( 'Delete' ), - isEligible: ( item ) => { - if ( ! item ) { - return false; - } - const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE; - const hasThemeFile = - isTemplatePart && item.templatePart?.has_theme_file; - return canDeleteOrReset( item ) && ! hasThemeFile; - }, - hideModalHeader: true, - supportsBulk: true, - RenderModal: ( { items, closeModal, onActionPerformed } ) => { - const { __experimentalDeleteReusableBlock } = - useDispatch( reusableBlocksStore ); - const { createErrorNotice, createSuccessNotice } = - useDispatch( noticesStore ); - const { removeTemplates } = unlock( useDispatch( editorStore ) ); - - const deletePattern = async () => { - const promiseResult = await Promise.allSettled( - items.map( ( item ) => { - return __experimentalDeleteReusableBlock( item.id ); - } ) - ); - // If all the promises were fulfilled with success. - if ( - promiseResult.every( ( { status } ) => status === 'fulfilled' ) - ) { - let successMessage; - if ( promiseResult.length === 1 ) { - successMessage = sprintf( - /* translators: The posts's title. */ - __( '"%s" deleted.' ), - items[ 0 ].title - ); - } else { - successMessage = __( 'The patterns were deleted.' ); - } - createSuccessNotice( successMessage, { - type: 'snackbar', - id: 'edit-site-page-trashed', - } ); - } else { - // If there was at lease one failure. - let errorMessage; - // If we were trying to delete a single pattern. - if ( promiseResult.length === 1 ) { - if ( promiseResult[ 0 ].reason?.message ) { - errorMessage = promiseResult[ 0 ].reason.message; - } else { - errorMessage = __( - 'An error occurred while deleting the pattern.' - ); - } - // If we were trying to delete multiple patterns. - } else { - const errorMessages = new Set(); - const failedPromises = promiseResult.filter( - ( { status } ) => status === 'rejected' - ); - for ( const failedPromise of failedPromises ) { - if ( failedPromise.reason?.message ) { - errorMessages.add( failedPromise.reason.message ); - } - } - if ( errorMessages.size === 0 ) { - errorMessage = __( - 'An error occurred while deleting the patterns.' - ); - } else if ( errorMessages.size === 1 ) { - errorMessage = sprintf( - /* translators: %s: an error message */ - __( - 'An error occurred while deleting the patterns: %s' - ), - [ ...errorMessages ][ 0 ] - ); - } else { - errorMessage = sprintf( - /* translators: %s: a list of comma separated error messages */ - __( - 'Some errors occurred while deleting the patterns: %s' - ), - [ ...errorMessages ].join( ',' ) - ); - } - createErrorNotice( errorMessage, { - type: 'snackbar', - } ); - } - } - }; - const deleteItem = () => { - if ( items[ 0 ].type === TEMPLATE_PART_POST_TYPE ) { - removeTemplates( items ); - } else { - deletePattern(); - } - if ( onActionPerformed ) { - onActionPerformed(); - } - closeModal(); - }; - let questionMessage; - if ( items.length === 1 ) { - questionMessage = sprintf( - // translators: %s: The page's title. - __( 'Are you sure you want to delete "%s"?' ), - decodeEntities( items[ 0 ].title || items[ 0 ].name ) - ); - } else if ( - items.length > 1 && - items[ 0 ].type === TEMPLATE_PART_POST_TYPE - ) { - questionMessage = sprintf( - // translators: %d: The number of template parts (2 or more). - __( 'Are you sure you want to delete %d template parts?' ), - items.length - ); - } else { - questionMessage = sprintf( - // translators: %d: The number of patterns (2 or more). - __( 'Are you sure you want to delete %d patterns?' ), - items.length - ); - } - return ( - - { questionMessage } - - - - - - ); - }, -}; - export function usePostActions( postType, onActionPerformed ) { const { postTypeObject } = useSelect( ( select ) => { @@ -1108,6 +980,7 @@ export function usePostActions( postType, onActionPerformed ) { ].includes( postType ); const isPattern = postType === PATTERN_POST_TYPE; const isLoaded = !! postTypeObject; + const supportsRevisions = !! postTypeObject?.supports?.revisions; return useMemo( () => { if ( ! isLoaded ) { return []; @@ -1115,7 +988,7 @@ export function usePostActions( postType, onActionPerformed ) { const actions = [ postTypeObject?.viewable && viewPostAction, - postRevisionsAction, + supportsRevisions && postRevisionsAction, globalThis.IS_GUTENBERG_PLUGIN ? ! isTemplateOrTemplatePart && ! isPattern && @@ -1124,11 +997,10 @@ export function usePostActions( postType, onActionPerformed ) { renamePostAction, isPattern && exportPatternAsJSONAction, isTemplateOrTemplatePart ? resetTemplateAction : restorePostAction, - isTemplateOrTemplatePart - ? deleteTemplateAction - : permanentlyDeletePostAction, - isPattern && deletePatternAction, - ! isTemplateOrTemplatePart && trashPostAction, + isTemplateOrTemplatePart || isPattern + ? deletePostAction + : trashPostAction, + ! isTemplateOrTemplatePart && permanentlyDeletePostAction, ].filter( Boolean ); if ( onActionPerformed ) { @@ -1181,5 +1053,6 @@ export function usePostActions( postType, onActionPerformed ) { restorePostAction, onActionPerformed, isLoaded, + supportsRevisions, ] ); } diff --git a/packages/editor/src/components/sidebar/index.js b/packages/editor/src/components/sidebar/index.js index 30d27a8c5db306..7a6a1d10282731 100644 --- a/packages/editor/src/components/sidebar/index.js +++ b/packages/editor/src/components/sidebar/index.js @@ -26,7 +26,6 @@ import PageAttributesPanel from '../page-attributes/panel'; import PatternOverridesPanel from '../pattern-overrides-panel'; import PluginDocumentSettingPanel from '../plugin-document-setting-panel'; import PluginSidebar from '../plugin-sidebar'; -import PostLastRevisionPanel from '../post-last-revision/panel'; import PostSummary from './post-summary'; import PostTaxonomiesPanel from '../post-taxonomies/panel'; import PostTransformPanel from '../post-transform-panel'; @@ -117,7 +116,6 @@ const SidebarContent = ( { ) } - diff --git a/packages/editor/src/store/private-actions.js b/packages/editor/src/store/private-actions.js index c3fca0798e8b70..9304a2fe2c0579 100644 --- a/packages/editor/src/store/private-actions.js +++ b/packages/editor/src/store/private-actions.js @@ -15,7 +15,6 @@ import { decodeEntities } from '@wordpress/html-entities'; * Internal dependencies */ import isTemplateRevertable from './utils/is-template-revertable'; -import { TEMPLATE_POST_TYPE } from './constants'; /** * Returns an action object used to set which template is currently being used/edited. @@ -363,14 +362,13 @@ export const revertTemplate = }; /** - * Action that removes an array of templates. + * Action that removes an array of templates, template parts or patterns. * - * @param {Array} items An array of template or template part objects to remove. + * @param {Array} items An array of template,template part or pattern objects to remove. */ export const removeTemplates = ( items ) => async ( { registry } ) => { - const isTemplate = items[ 0 ].type === TEMPLATE_POST_TYPE; const promiseResult = await Promise.allSettled( items.map( ( item ) => { return registry @@ -402,16 +400,14 @@ export const removeTemplates = decodeEntities( title ) ); } else { - successMessage = isTemplate - ? __( 'Templates deleted.' ) - : __( 'Template parts deleted.' ); + successMessage = __( 'Items deleted.' ); } registry .dispatch( noticesStore ) .createSuccessNotice( successMessage, { type: 'snackbar', - id: 'site-editor-template-deleted-success', + id: 'editor-template-deleted-success', } ); } else { // If there was at lease one failure. @@ -421,11 +417,9 @@ export const removeTemplates = if ( promiseResult[ 0 ].reason?.message ) { errorMessage = promiseResult[ 0 ].reason.message; } else { - errorMessage = isTemplate - ? __( 'An error occurred while deleting the template.' ) - : __( - 'An error occurred while deleting the template part.' - ); + errorMessage = __( + 'An error occurred while deleting the item.' + ); } // If we were trying to delete a multiple templates } else { @@ -439,45 +433,23 @@ export const removeTemplates = } } if ( errorMessages.size === 0 ) { - errorMessage = isTemplate - ? __( - 'An error occurred while deleting the templates.' - ) - : __( - 'An error occurred while deleting the template parts.' - ); + errorMessage = __( + 'An error occurred while deleting the items.' + ); } else if ( errorMessages.size === 1 ) { - errorMessage = isTemplate - ? sprintf( - /* translators: %s: an error message */ - __( - 'An error occurred while deleting the templates: %s' - ), - [ ...errorMessages ][ 0 ] - ) - : sprintf( - /* translators: %s: an error message */ - __( - 'An error occurred while deleting the template parts: %s' - ), - [ ...errorMessages ][ 0 ] - ); + errorMessage = sprintf( + /* translators: %s: an error message */ + __( 'An error occurred while deleting the items: %s' ), + [ ...errorMessages ][ 0 ] + ); } else { - errorMessage = isTemplate - ? sprintf( - /* translators: %s: a list of comma separated error messages */ - __( - 'Some errors occurred while deleting the templates: %s' - ), - [ ...errorMessages ].join( ',' ) - ) - : sprintf( - /* translators: %s: a list of comma separated error messages */ - __( - 'Some errors occurred while deleting the template parts: %s' - ), - [ ...errorMessages ].join( ',' ) - ); + sprintf( + /* translators: %s: a list of comma separated error messages */ + __( + 'Some errors occurred while deleting the items: %s' + ), + [ ...errorMessages ].join( ',' ) + ); } } registry diff --git a/packages/interactivity/CHANGELOG.md b/packages/interactivity/CHANGELOG.md index e40c68a50180a2..c3542b914de159 100644 --- a/packages/interactivity/CHANGELOG.md +++ b/packages/interactivity/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Bug fixes + +- Fix null and number strings as namespaces runtime error. ([#61960](https://github.com/WordPress/gutenberg/pull/61960/)) + ### Breaking Changes - Variables like `process.env.IS_GUTENBERG_PLUGIN` have been replaced by `globalThis.IS_GUTENBERG_PLUGIN`. Build systems using `process.env` should be updated ([#61486](https://github.com/WordPress/gutenberg/pull/61486)). diff --git a/packages/interactivity/src/store.ts b/packages/interactivity/src/store.ts index d173f2cd842dc1..9b35192fe8b132 100644 --- a/packages/interactivity/src/store.ts +++ b/packages/interactivity/src/store.ts @@ -15,7 +15,6 @@ import { setNamespace, resetNamespace, } from './hooks'; - const isObject = ( item: unknown ): item is Record< string, unknown > => Boolean( item && typeof item === 'object' && item.constructor === Object ); diff --git a/packages/interactivity/src/vdom.ts b/packages/interactivity/src/vdom.ts index cc481f89ff772a..98deca656cfa6c 100644 --- a/packages/interactivity/src/vdom.ts +++ b/packages/interactivity/src/vdom.ts @@ -13,6 +13,8 @@ const islandAttr = `data-${ p }-interactive`; const fullPrefix = `data-${ p }-`; const namespaces: Array< string | null > = []; const currentNamespace = () => namespaces[ namespaces.length - 1 ] ?? null; +const isObject = ( item: unknown ): item is Record< string, unknown > => + Boolean( item && typeof item === 'object' && item.constructor === Object ); // Regular expression for directive parsing. const directiveParser = new RegExp( @@ -100,8 +102,9 @@ export function toVdom( root: Node ): Array< ComponentChild > { const namespace = regexResult?.[ 1 ] ?? null; let value: any = regexResult?.[ 2 ] ?? attributeValue; try { - value = value && JSON.parse( value ); - } catch ( e ) {} + const parsedValue = JSON.parse( value ); + value = isObject( parsedValue ) ? parsedValue : value; + } catch {} if ( attributeName === islandAttr ) { island = true; const islandNamespace = diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 00799b7ba0b478..28401bb20d484d 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -547,7 +547,7 @@ public function test_get_stylesheet() { ); $variables = ':root{--wp--preset--color--grey: grey;--wp--preset--gradient--custom-gradient: linear-gradient(135deg,rgba(0,0,0) 0%,rgb(0,0,0) 100%);--wp--preset--font-size--small: 14px;--wp--preset--font-size--big: 41px;--wp--preset--font-family--arial: Arial, serif;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}'; - $styles = static::$base_styles . ':where(body){color: var(--wp--preset--color--grey);}:where(a:where(:not(.wp-element-button))){background-color: #333;color: #111;}:where(.wp-element-button, .wp-block-button__link){box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.66);}:where(.wp-block-cover){min-height: unset;aspect-ratio: 16/9;}:where(.wp-block-group){background: var(--wp--preset--gradient--custom-gradient);border-radius: 10px;min-height: 50vh;padding: 24px;}:where(.wp-block-group a:where(:not(.wp-element-button))){color: #111;}:where(.wp-block-heading){color: #123456;}:where(.wp-block-heading a:where(:not(.wp-element-button))){background-color: #333;color: #111;font-size: 60px;}:where(.wp-block-post-date){color: #123456;}:where(.wp-block-post-date a:where(:not(.wp-element-button))){background-color: #777;color: #555;}:where(.wp-block-post-excerpt){column-count: 2;}:where(.wp-block-image){margin-bottom: 30px;}:where(.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder){border-top-left-radius: 10px;border-bottom-right-radius: 1em;}:where(.wp-block-image img, .wp-block-image .components-placeholder){filter: var(--wp--preset--duotone--custom-duotone);}'; + $styles = static::$base_styles . ':root :where(body){color: var(--wp--preset--color--grey);}:root :where(a:where(:not(.wp-element-button))){background-color: #333;color: #111;}:root :where(.wp-element-button, .wp-block-button__link){box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.66);}:root :where(.wp-block-cover){min-height: unset;aspect-ratio: 16/9;}:root :where(.wp-block-group){background: var(--wp--preset--gradient--custom-gradient);border-radius: 10px;min-height: 50vh;padding: 24px;}:root :where(.wp-block-group a:where(:not(.wp-element-button))){color: #111;}:root :where(.wp-block-heading){color: #123456;}:root :where(.wp-block-heading a:where(:not(.wp-element-button))){background-color: #333;color: #111;font-size: 60px;}:root :where(.wp-block-post-date){color: #123456;}:root :where(.wp-block-post-date a:where(:not(.wp-element-button))){background-color: #777;color: #555;}:root :where(.wp-block-post-excerpt){column-count: 2;}:root :where(.wp-block-image){margin-bottom: 30px;}:root :where(.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder){border-top-left-radius: 10px;border-bottom-right-radius: 1em;}:root :where(.wp-block-image img, .wp-block-image .components-placeholder){filter: var(--wp--preset--duotone--custom-duotone);}'; $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-custom-gradient-gradient-background{background: var(--wp--preset--gradient--custom-gradient) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-big-font-size{font-size: var(--wp--preset--font-size--big) !important;}.has-arial-font-family{font-family: var(--wp--preset--font-family--arial) !important;}'; $all = $variables . $styles . $presets; @@ -593,7 +593,7 @@ public function test_get_stylesheet_support_for_shorthand_and_longhand_values() ) ); - $styles = static::$base_styles . ':where(.wp-block-group){border-radius: 10px;margin: 1em;padding: 24px;}:where(.wp-block-image){margin-bottom: 30px;padding-top: 15px;}:where(.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder){border-top-left-radius: 10px;border-bottom-right-radius: 1em;}'; + $styles = static::$base_styles . ':root :where(.wp-block-group){border-radius: 10px;margin: 1em;padding: 24px;}:root :where(.wp-block-image){margin-bottom: 30px;padding-top: 15px;}:root :where(.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder){border-top-left-radius: 10px;border-bottom-right-radius: 1em;}'; $this->assertSame( $styles, $theme_json->get_stylesheet() ); $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) ); } @@ -644,7 +644,7 @@ public function test_get_stylesheet_renders_enabled_protected_properties() { ) ); - $expected = ':where(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(.wp-site-blocks) > * { margin-block-start: 1em; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: 1em; }:where(.is-layout-flow) > :first-child{margin-block-start: 0;}:where(.is-layout-flow) > :last-child{margin-block-end: 0;}:where(.is-layout-flow) > *{margin-block-start: 1em;margin-block-end: 0;}:where(.is-layout-constrained) > :first-child{margin-block-start: 0;}:where(.is-layout-constrained) > :last-child{margin-block-end: 0;}:where(.is-layout-constrained) > *{margin-block-start: 1em;margin-block-end: 0;}:where(.is-layout-flex) {gap: 1em;}:where(.is-layout-grid) {gap: 1em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}'; + $expected = ':where(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(.wp-site-blocks) > * { margin-block-start: 1em; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: 1em; }.is-layout-flow > :first-child{margin-block-start: 0;}.is-layout-flow > :last-child{margin-block-end: 0;}.is-layout-flow > *{margin-block-start: 1em;margin-block-end: 0;}.is-layout-constrained > :first-child{margin-block-start: 0;}.is-layout-constrained > :last-child{margin-block-end: 0;}.is-layout-constrained > *{margin-block-start: 1em;margin-block-end: 0;}.is-layout-flex {gap: 1em;}.is-layout-grid {gap: 1em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}'; $this->assertSame( $expected, $theme_json->get_stylesheet() ); $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } @@ -706,7 +706,7 @@ public function test_get_stylesheet_preset_rules_come_after_block_rules() { ) ); - $styles = static::$base_styles . ':where(.wp-block-group){color: red;}'; + $styles = static::$base_styles . ':root :where(.wp-block-group){color: red;}'; $presets = '.wp-block-group.has-grey-color{color: var(--wp--preset--color--grey) !important;}.wp-block-group.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.wp-block-group.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}'; $variables = '.wp-block-group{--wp--preset--color--grey: grey;}'; @@ -793,7 +793,7 @@ public function test_get_stylesheet_preset_values_are_marked_as_important() { ); $this->assertSame( - ':root{--wp--preset--color--grey: grey;}' . static::$base_styles . ':where(p){background-color: blue;color: red;font-size: 12px;line-height: 1.3;}.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}', + ':root{--wp--preset--color--grey: grey;}' . static::$base_styles . ':root :where(p){background-color: blue;color: red;font-size: 12px;line-height: 1.3;}.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}', $theme_json->get_stylesheet() ); } @@ -831,7 +831,7 @@ public function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors ) ); - $element_styles = ':where(a:where(:not(.wp-element-button))){background-color: red;color: green;}:where(a:where(:not(.wp-element-button)):hover){background-color: green;color: red;font-size: 10em;text-transform: uppercase;}:where(a:where(:not(.wp-element-button)):focus){background-color: black;color: yellow;}'; + $element_styles = ':root :where(a:where(:not(.wp-element-button))){background-color: red;color: green;}:root :where(a:where(:not(.wp-element-button)):hover){background-color: green;color: red;font-size: 10em;text-transform: uppercase;}:root :where(a:where(:not(.wp-element-button)):focus){background-color: black;color: yellow;}'; $expected = static::$base_styles . $element_styles; @@ -868,7 +868,7 @@ public function test_get_stylesheet_handles_only_pseudo_selector_rules_for_given ) ); - $element_styles = ':where(a:where(:not(.wp-element-button)):hover){background-color: green;color: red;font-size: 10em;text-transform: uppercase;}:where(a:where(:not(.wp-element-button)):focus){background-color: black;color: yellow;}'; + $element_styles = ':root :where(a:where(:not(.wp-element-button)):hover){background-color: green;color: red;font-size: 10em;text-transform: uppercase;}:root :where(a:where(:not(.wp-element-button)):focus){background-color: black;color: yellow;}'; $expected = static::$base_styles . $element_styles; @@ -905,7 +905,7 @@ public function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_ ) ); - $element_styles = ':where(h4){background-color: red;color: green;}'; + $element_styles = ':root :where(h4){background-color: red;color: green;}'; $expected = static::$base_styles . $element_styles; @@ -942,7 +942,7 @@ public function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() { ) ); - $element_styles = ':where(a:where(:not(.wp-element-button))){background-color: red;color: green;}:where(a:where(:not(.wp-element-button)):hover){background-color: green;color: red;}'; + $element_styles = ':root :where(a:where(:not(.wp-element-button))){background-color: red;color: green;}:root :where(a:where(:not(.wp-element-button)):hover){background-color: green;color: red;}'; $expected = static::$base_styles . $element_styles; @@ -988,7 +988,7 @@ public function test_get_stylesheet_handles_priority_of_elements_vs_block_elemen ) ); - $element_styles = ':where(.wp-block-group a:where(:not(.wp-element-button))){background-color: red;color: green;}:where(.wp-block-group a:where(:not(.wp-element-button)):hover){background-color: green;color: red;font-size: 10em;text-transform: uppercase;}:where(.wp-block-group a:where(:not(.wp-element-button)):focus){background-color: black;color: yellow;}'; + $element_styles = ':root :where(.wp-block-group a:where(:not(.wp-element-button))){background-color: red;color: green;}:root :where(.wp-block-group a:where(:not(.wp-element-button)):hover){background-color: green;color: red;font-size: 10em;text-transform: uppercase;}:root :where(.wp-block-group a:where(:not(.wp-element-button)):focus){background-color: black;color: yellow;}'; $expected = static::$base_styles . $element_styles; @@ -1033,7 +1033,7 @@ public function test_get_stylesheet_handles_whitelisted_block_level_element_pseu ) ); - $element_styles = ':where(a:where(:not(.wp-element-button))){background-color: red;color: green;}:where(a:where(:not(.wp-element-button)):hover){background-color: green;color: red;}:where(.wp-block-group a:where(:not(.wp-element-button)):hover){background-color: black;color: yellow;}'; + $element_styles = ':root :where(a:where(:not(.wp-element-button))){background-color: red;color: green;}:root :where(a:where(:not(.wp-element-button)):hover){background-color: green;color: red;}:root :where(.wp-block-group a:where(:not(.wp-element-button)):hover){background-color: black;color: yellow;}'; $expected = static::$base_styles . $element_styles; @@ -1095,7 +1095,7 @@ public function test_get_stylesheet_with_deprecated_feature_level_selectors() { ); $base_styles = ':root{--wp--preset--color--green: green;}' . static::$base_styles; - $block_styles = ':where(.wp-block-test, .wp-block-test__wrapper){color: green;}:where(.wp-block-test .inner, .wp-block-test__wrapper .inner){border-radius: 9999px;padding: 20px;}:where(.wp-block-test .sub-heading, .wp-block-test__wrapper .sub-heading){font-size: 3em;}'; + $block_styles = ':root :where(.wp-block-test, .wp-block-test__wrapper){color: green;}:root :where(.wp-block-test .inner, .wp-block-test__wrapper .inner){border-radius: 9999px;padding: 20px;}:root :where(.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; @@ -1157,7 +1157,7 @@ public function test_get_stylesheet_with_block_json_selectors() { ); $base_styles = ':root{--wp--preset--color--green: green;}' . static::$base_styles; - $block_styles = ':where(.custom-root-selector){background-color: grey;padding: 20px;}:where(.custom-root-selector img){border-radius: 9999px;}:where(.custom-root-selector > figcaption){color: navy;font-size: 3em;}'; + $block_styles = ':root :where(.custom-root-selector){background-color: grey;padding: 20px;}:root :where(.custom-root-selector img){border-radius: 9999px;}:root :where(.custom-root-selector > figcaption){color: navy;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; @@ -1188,7 +1188,7 @@ public function test_get_stylesheet_generates_layout_styles() { // Results also include root site blocks styles. $this->assertSame( - ':root { --wp--style--global--content-size: 640px;--wp--style--global--wide-size: 1200px; }:where(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(.wp-site-blocks) > * { margin-block-start: 1em; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: 1em; }:where(.is-layout-flow) > :first-child{margin-block-start: 0;}:where(.is-layout-flow) > :last-child{margin-block-end: 0;}:where(.is-layout-flow) > *{margin-block-start: 1em;margin-block-end: 0;}:where(.is-layout-constrained) > :first-child{margin-block-start: 0;}:where(.is-layout-constrained) > :last-child{margin-block-end: 0;}:where(.is-layout-constrained) > *{margin-block-start: 1em;margin-block-end: 0;}:where(.is-layout-flex) {gap: 1em;}:where(.is-layout-grid) {gap: 1em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}', + ':root { --wp--style--global--content-size: 640px;--wp--style--global--wide-size: 1200px; }:where(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(.wp-site-blocks) > * { margin-block-start: 1em; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: 1em; }.is-layout-flow > :first-child{margin-block-start: 0;}.is-layout-flow > :last-child{margin-block-end: 0;}.is-layout-flow > *{margin-block-start: 1em;margin-block-end: 0;}.is-layout-constrained > :first-child{margin-block-start: 0;}.is-layout-constrained > :last-child{margin-block-end: 0;}.is-layout-constrained > *{margin-block-start: 1em;margin-block-end: 0;}.is-layout-flex {gap: 1em;}.is-layout-grid {gap: 1em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}', $theme_json->get_stylesheet( array( 'styles' ) ) ); } @@ -1217,7 +1217,7 @@ public function test_get_stylesheet_generates_layout_styles_with_spacing_presets // Results also include root site blocks styles. $this->assertSame( - ':root { --wp--style--global--content-size: 640px;--wp--style--global--wide-size: 1200px; }:where(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(.wp-site-blocks) > * { margin-block-start: var(--wp--preset--spacing--60); margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: var(--wp--preset--spacing--60); }:where(.is-layout-flow) > :first-child{margin-block-start: 0;}:where(.is-layout-flow) > :last-child{margin-block-end: 0;}:where(.is-layout-flow) > *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}:where(.is-layout-constrained) > :first-child{margin-block-start: 0;}:where(.is-layout-constrained) > :last-child{margin-block-end: 0;}:where(.is-layout-constrained) > *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}:where(.is-layout-flex) {gap: var(--wp--preset--spacing--60);}:where(.is-layout-grid) {gap: var(--wp--preset--spacing--60);}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}', + ':root { --wp--style--global--content-size: 640px;--wp--style--global--wide-size: 1200px; }:where(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(.wp-site-blocks) > * { margin-block-start: var(--wp--preset--spacing--60); margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: var(--wp--preset--spacing--60); }.is-layout-flow > :first-child{margin-block-start: 0;}.is-layout-flow > :last-child{margin-block-end: 0;}.is-layout-flow > *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}.is-layout-constrained > :first-child{margin-block-start: 0;}.is-layout-constrained > :last-child{margin-block-end: 0;}.is-layout-constrained > *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}.is-layout-flex {gap: var(--wp--preset--spacing--60);}.is-layout-grid {gap: var(--wp--preset--spacing--60);}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}', $theme_json->get_stylesheet( array( 'styles' ) ) ); } @@ -1345,8 +1345,8 @@ public function test_get_stylesheet_generates_valid_block_gap_values_and_skips_n ); $this->assertSame( - ':root { --wp--style--global--content-size: 640px;--wp--style--global--wide-size: 1200px; }:where(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(.wp-site-blocks) > * { margin-block-start: 1rem; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: 1rem; }:where(.is-layout-flow) > :first-child{margin-block-start: 0;}:where(.is-layout-flow) > :last-child{margin-block-end: 0;}:where(.is-layout-flow) > *{margin-block-start: 1rem;margin-block-end: 0;}:where(.is-layout-constrained) > :first-child{margin-block-start: 0;}:where(.is-layout-constrained) > :last-child{margin-block-end: 0;}:where(.is-layout-constrained) > *{margin-block-start: 1rem;margin-block-end: 0;}:where(.is-layout-flex) {gap: 1rem;}:where(.is-layout-grid) {gap: 1rem;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}' . - ':where(.wp-block-post-content){color: gray;}:where(.wp-block-social-links-is-layout-flow) > :first-child{margin-block-start: 0;}:where(.wp-block-social-links-is-layout-flow) > :last-child{margin-block-end: 0;}:where(.wp-block-social-links-is-layout-flow) > *{margin-block-start: 0;margin-block-end: 0;}:where(.wp-block-social-links-is-layout-constrained) > :first-child{margin-block-start: 0;}:where(.wp-block-social-links-is-layout-constrained) > :last-child{margin-block-end: 0;}:where(.wp-block-social-links-is-layout-constrained) > *{margin-block-start: 0;margin-block-end: 0;}:where(.wp-block-social-links-is-layout-flex) {gap: 0;}:where(.wp-block-social-links-is-layout-grid) {gap: 0;}:where(.wp-block-buttons-is-layout-flow) > :first-child{margin-block-start: 0;}:where(.wp-block-buttons-is-layout-flow) > :last-child{margin-block-end: 0;}:where(.wp-block-buttons-is-layout-flow) > *{margin-block-start: 0;margin-block-end: 0;}:where(.wp-block-buttons-is-layout-constrained) > :first-child{margin-block-start: 0;}:where(.wp-block-buttons-is-layout-constrained) > :last-child{margin-block-end: 0;}:where(.wp-block-buttons-is-layout-constrained) > *{margin-block-start: 0;margin-block-end: 0;}:where(.wp-block-buttons-is-layout-flex) {gap: 0;}:where(.wp-block-buttons-is-layout-grid) {gap: 0;}', + ':root { --wp--style--global--content-size: 640px;--wp--style--global--wide-size: 1200px; }:where(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(.wp-site-blocks) > * { margin-block-start: 1rem; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: 1rem; }.is-layout-flow > :first-child{margin-block-start: 0;}.is-layout-flow > :last-child{margin-block-end: 0;}.is-layout-flow > *{margin-block-start: 1rem;margin-block-end: 0;}.is-layout-constrained > :first-child{margin-block-start: 0;}.is-layout-constrained > :last-child{margin-block-end: 0;}.is-layout-constrained > *{margin-block-start: 1rem;margin-block-end: 0;}.is-layout-flex {gap: 1rem;}.is-layout-grid {gap: 1rem;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}' . + ':root :where(.wp-block-post-content){color: gray;}.wp-block-social-links-is-layout-flow > :first-child{margin-block-start: 0;}.wp-block-social-links-is-layout-flow > :last-child{margin-block-end: 0;}.wp-block-social-links-is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links-is-layout-constrained > :first-child{margin-block-start: 0;}.wp-block-social-links-is-layout-constrained > :last-child{margin-block-end: 0;}.wp-block-social-links-is-layout-constrained > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links-is-layout-flex {gap: 0;}.wp-block-social-links-is-layout-grid {gap: 0;}.wp-block-buttons-is-layout-flow > :first-child{margin-block-start: 0;}.wp-block-buttons-is-layout-flow > :last-child{margin-block-end: 0;}.wp-block-buttons-is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons-is-layout-constrained > :first-child{margin-block-start: 0;}.wp-block-buttons-is-layout-constrained > :last-child{margin-block-end: 0;}.wp-block-buttons-is-layout-constrained > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons-is-layout-flex {gap: 0;}.wp-block-buttons-is-layout-grid {gap: 0;}', $theme_json->get_stylesheet() ); } @@ -1378,7 +1378,7 @@ public function test_get_stylesheet_returns_outline_styles() { ) ); - $element_styles = ':where(.wp-element-button, .wp-block-button__link){outline-color: red;outline-offset: 3px;outline-style: dashed;outline-width: 3px;}:where(.wp-element-button:hover, .wp-block-button__link:hover){outline-color: blue;outline-offset: 3px;outline-style: solid;outline-width: 3px;}'; + $element_styles = ':root :where(.wp-element-button, .wp-block-button__link){outline-color: red;outline-offset: 3px;outline-style: dashed;outline-width: 3px;}:root :where(.wp-element-button:hover, .wp-block-button__link:hover){outline-color: blue;outline-offset: 3px;outline-style: solid;outline-width: 3px;}'; $expected = static::$base_styles . $element_styles; $this->assertSame( $expected, $theme_json->get_stylesheet() ); @@ -1403,7 +1403,7 @@ public function test_get_stylesheet_custom_root_selector() { // Results also include root site blocks styles which hard code // `:where(body) { margin: 0; }`. $this->assertSame( - ':where(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(.custom){color: teal;}', + ':where(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; }:root :where(.custom){color: teal;}', $actual ); } @@ -1462,7 +1462,7 @@ public function test_get_stylesheet_generates_fluid_typography_values() { // Results also include root site blocks styles. $this->assertSame( - ':root{--wp--preset--font-size--pickles: clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.156), 16px);--wp--preset--font-size--toast: clamp(14.642px, 0.915rem + ((1vw - 3.2px) * 0.575), 22px);}:where(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;}:where(.is-layout-grid){gap: 0.5em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}:where(body){font-size: clamp(0.875em, 0.875rem + ((1vw - 0.2em) * 0.156), 1em);}:where(h1){font-size: clamp(50.171px, 3.136rem + ((1vw - 3.2px) * 3.893), 100px);}:where(.wp-block-test-clamp-me){font-size: clamp(27.894px, 1.743rem + ((1vw - 3.2px) * 1.571), 48px);}.has-pickles-font-size{font-size: var(--wp--preset--font-size--pickles) !important;}.has-toast-font-size{font-size: var(--wp--preset--font-size--toast) !important;}', + ':root{--wp--preset--font-size--pickles: clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.156), 16px);--wp--preset--font-size--toast: clamp(14.642px, 0.915rem + ((1vw - 3.2px) * 0.575), 22px);}:where(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;}:where(.is-layout-grid){gap: 0.5em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}:root :where(body){font-size: clamp(0.875em, 0.875rem + ((1vw - 0.2em) * 0.156), 1em);}:root :where(h1){font-size: clamp(50.171px, 3.136rem + ((1vw - 3.2px) * 3.893), 100px);}:root :where(.wp-block-test-clamp-me){font-size: clamp(27.894px, 1.743rem + ((1vw - 3.2px) * 1.571), 48px);}.has-pickles-font-size{font-size: var(--wp--preset--font-size--pickles) !important;}.has-toast-font-size{font-size: var(--wp--preset--font-size--toast) !important;}', $theme_json->get_stylesheet() ); } @@ -3519,7 +3519,7 @@ public function test_get_property_value_valid() { ) ); - $color_styles = ':where(body){background-color: #ffffff;color: #000000;}:where(.wp-element-button, .wp-block-button__link){background-color: #000000;color: #ffffff;}'; + $color_styles = ':root :where(body){background-color: #ffffff;color: #000000;}:root :where(.wp-element-button, .wp-block-button__link){background-color: #000000;color: #ffffff;}'; $expected = static::$base_styles . $color_styles; $this->assertSame( $expected, $theme_json->get_stylesheet() ); } @@ -3597,7 +3597,7 @@ public function test_get_property_value_loop() { ) ); - $color_styles = ':where(body){background-color: #ffffff;}:where(.wp-element-button, .wp-block-button__link){color: #ffffff;}'; + $color_styles = ':root :where(body){background-color: #ffffff;}:root :where(.wp-element-button, .wp-block-button__link){color: #ffffff;}'; $expected = static::$base_styles . $color_styles; $this->assertSame( $expected, $theme_json->get_stylesheet() ); } @@ -3630,7 +3630,7 @@ public function test_get_property_value_recursion() { ) ); - $color_styles = ':where(body){background-color: #ffffff;color: #ffffff;}:where(.wp-element-button, .wp-block-button__link){color: #ffffff;}'; + $color_styles = ':root :where(body){background-color: #ffffff;color: #ffffff;}:root :where(.wp-element-button, .wp-block-button__link){color: #ffffff;}'; $expected = static::$base_styles . $color_styles; $this->assertSame( $expected, $theme_json->get_stylesheet() ); } @@ -3654,7 +3654,7 @@ public function test_get_property_value_self() { ) ); - $color_styles = ':where(body){background-color: #ffffff;}'; + $color_styles = ':root :where(body){background-color: #ffffff;}'; $expected = static::$base_styles . $color_styles; $this->assertSame( $expected, $theme_json->get_stylesheet() ); } @@ -3684,7 +3684,7 @@ public function test_get_styles_for_block_with_padding_aware_alignments() { 'selector' => 'body', ); - $expected = ':where(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 :where(.has-global-padding:not(.wp-block-block)) { padding-right: 0; padding-left: 0; }.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 :where(.has-global-padding:not(.wp-block-block)) > .alignfull { margin-right: 0; margin-left: 0; }.has-global-padding > .alignfull:where(:not(.has-global-padding):not(.is-layout-flex):not(.is-layout-grid)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),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); }.has-global-padding :where(.has-global-padding) > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: 0; padding-left: 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;}:where(.is-layout-grid){gap: 0.5em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}:where(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;}'; + $expected = ':where(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 :where(.has-global-padding:not(.wp-block-block, .alignfull, .alignwide)) { padding-right: 0; padding-left: 0; }.has-global-padding :where(.has-global-padding:not(.wp-block-block, .alignfull, .alignwide)) > .alignfull { margin-left: 0; margin-right: 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;}:where(.is-layout-grid){gap: 0.5em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}:root :where(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;}'; $root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON_Gutenberg::ROOT_BLOCK_SELECTOR, $metadata ); $style_rules = $theme_json->get_styles_for_block( $metadata ); $this->assertSame( $expected, $root_rules . $style_rules ); @@ -3712,7 +3712,7 @@ public function test_get_styles_for_block_without_padding_aware_alignments() { 'selector' => 'body', ); - $expected = static::$base_styles . ':where(body){padding-top: 10px;padding-right: 12px;padding-bottom: 10px;padding-left: 12px;}'; + $expected = static::$base_styles . ':root :where(body){padding-top: 10px;padding-right: 12px;padding-bottom: 10px;padding-left: 12px;}'; $root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON_Gutenberg::ROOT_BLOCK_SELECTOR, $metadata ); $style_rules = $theme_json->get_styles_for_block( $metadata ); $this->assertSame( $expected, $root_rules . $style_rules ); @@ -3757,7 +3757,7 @@ public function test_get_styles_with_appearance_tools() { 'selector' => 'body', ); - $expected = ':where(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(.wp-site-blocks) > * { margin-block-start: ; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: ; }:where(.is-layout-flow) > :first-child{margin-block-start: 0;}:where(.is-layout-flow) > :last-child{margin-block-end: 0;}:where(.is-layout-flow) > *{margin-block-start: 1;margin-block-end: 0;}:where(.is-layout-constrained) > :first-child{margin-block-start: 0;}:where(.is-layout-constrained) > :last-child{margin-block-end: 0;}:where(.is-layout-constrained) > *{margin-block-start: 1;margin-block-end: 0;}:where(.is-layout-flex) {gap: 1;}:where(.is-layout-grid) {gap: 1;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}'; + $expected = ':where(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(.wp-site-blocks) > * { margin-block-start: ; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: ; }.is-layout-flow > :first-child{margin-block-start: 0;}.is-layout-flow > :last-child{margin-block-end: 0;}.is-layout-flow > *{margin-block-start: 1;margin-block-end: 0;}.is-layout-constrained > :first-child{margin-block-start: 0;}.is-layout-constrained > :last-child{margin-block-end: 0;}.is-layout-constrained > *{margin-block-start: 1;margin-block-end: 0;}.is-layout-flex {gap: 1;}.is-layout-grid {gap: 1;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}'; $root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON_Gutenberg::ROOT_BLOCK_SELECTOR, $metadata ); $this->assertSame( $expected, $root_rules ); } @@ -4146,9 +4146,9 @@ public function data_get_styles_for_block_with_style_variations() { $plain = array( 'metadata' => array( 'path' => array( 'styles', 'blocks', 'core/quote', 'variations', 'plain' ), - 'selector' => '.is-style-plain.is-style-plain.wp-block-quote', + 'selector' => '.is-style-plain.wp-block-quote', ), - 'styles' => '.is-style-plain.is-style-plain.wp-block-quote{background-color: hotpink;}', + 'styles' => ':root :where(.is-style-plain.wp-block-quote){background-color: hotpink;}', ); return array( @@ -4682,7 +4682,7 @@ public function data_update_separator_declarations() { 'background' => 'blue', ), ), - 'expected_output' => static::$base_styles . ':where(.wp-block-separator){background-color: blue;color: blue;}', + 'expected_output' => static::$base_styles . ':root :where(.wp-block-separator){background-color: blue;color: blue;}', ), // If background and text are defined, do not include border-color, as text color is enough. 'background and text, no border-color' => array( @@ -4692,7 +4692,7 @@ public function data_update_separator_declarations() { 'text' => 'red', ), ), - 'expected_output' => static::$base_styles . ':where(.wp-block-separator){background-color: blue;color: red;}', + 'expected_output' => static::$base_styles . ':root :where(.wp-block-separator){background-color: blue;color: red;}', ), // If only text is defined, do not include border-color, as by itself is enough. 'only text' => array( @@ -4701,7 +4701,7 @@ public function data_update_separator_declarations() { 'text' => 'red', ), ), - 'expected_output' => static::$base_styles . ':where(.wp-block-separator){color: red;}', + 'expected_output' => static::$base_styles . ':root :where(.wp-block-separator){color: red;}', ), // If background, text, and border-color are defined, include everything, CSS specificity will decide which to apply. 'background, text, and border-color' => array( @@ -4714,7 +4714,7 @@ public function data_update_separator_declarations() { 'color' => 'pink', ), ), - 'expected_output' => static::$base_styles . ':where(.wp-block-separator){background-color: blue;border-color: pink;color: red;}', + 'expected_output' => static::$base_styles . ':root :where(.wp-block-separator){background-color: blue;border-color: pink;color: red;}', ), // If background and border color are defined, include everything, CSS specificity will decide which to apply. 'background, and border-color' => array( @@ -4726,7 +4726,7 @@ public function data_update_separator_declarations() { 'color' => 'pink', ), ), - 'expected_output' => static::$base_styles . ':where(.wp-block-separator){background-color: blue;border-color: pink;}', + 'expected_output' => static::$base_styles . ':root :where(.wp-block-separator){background-color: blue;border-color: pink;}', ), ); } @@ -4790,7 +4790,7 @@ public function test_get_shadow_styles_for_blocks() { ); $global_styles = ':root{--wp--preset--shadow--natural: 5px 5px 0 0 black;}' . static::$base_styles; - $element_styles = ':where(a:where(:not(.wp-element-button))){box-shadow: var(--wp--preset--shadow--natural);}:where(.wp-element-button, .wp-block-button__link){box-shadow: var(--wp--preset--shadow--natural);}:where(p){box-shadow: var(--wp--preset--shadow--natural);}'; + $element_styles = ':root :where(a:where(:not(.wp-element-button))){box-shadow: var(--wp--preset--shadow--natural);}:root :where(.wp-element-button, .wp-block-button__link){box-shadow: var(--wp--preset--shadow--natural);}:root :where(p){box-shadow: var(--wp--preset--shadow--natural);}'; $expected_styles = $global_styles . $element_styles; $this->assertSame( $expected_styles, $theme_json->get_stylesheet() ); } @@ -4836,7 +4836,7 @@ public function test_get_top_level_background_image_styles() { ) ); - $expected_styles = ":where(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;}:where(.is-layout-grid){gap: 0.5em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}html{min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px));}:where(body){background-image: url('http://example.org/image.png');background-position: center center;background-repeat: no-repeat;background-size: contain;}"; + $expected_styles = ":where(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;}:where(.is-layout-grid){gap: 0.5em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}html{min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px));}:root :where(body){background-image: url('http://example.org/image.png');background-position: center center;background-repeat: no-repeat;background-size: contain;}"; $this->assertSame( $expected_styles, $theme_json->get_stylesheet(), 'Styles returned from "::get_stylesheet()" with top-level background styles type does not match expectations' ); $theme_json = new WP_Theme_JSON_Gutenberg( @@ -4853,7 +4853,7 @@ public function test_get_top_level_background_image_styles() { ) ); - $expected_styles = ":where(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;}:where(.is-layout-grid){gap: 0.5em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}html{min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px));}:where(body){background-image: url('http://example.org/image.png');background-position: center center;background-repeat: no-repeat;background-size: contain;}"; + $expected_styles = ":where(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;}:where(.is-layout-grid){gap: 0.5em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}html{min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px));}:root :where(body){background-image: url('http://example.org/image.png');background-position: center center;background-repeat: no-repeat;background-size: contain;}"; $this->assertSame( $expected_styles, $theme_json->get_stylesheet(), 'Styles returned from "::get_stylesheet()" with top-level background image as string type does not match expectations' ); } @@ -4872,7 +4872,7 @@ public function test_get_custom_css_handles_global_custom_css() { ) ); - $custom_css = 'body {color:purple;}p{color:red;}'; + $custom_css = 'body {color:purple;}:root :where(p){color:red;}'; $this->assertSame( $custom_css, $theme_json->get_custom_css() ); } @@ -4979,7 +4979,7 @@ public function data_process_blocks_custom_css() { 'selector' => '.foo', 'css' => 'color: red; margin: auto;', ), - 'expected' => '.foo{color: red; margin: auto;}', + 'expected' => ':root :where(.foo){color: red; margin: auto;}', ), // CSS with nested selectors. 'with nested selector' => array( @@ -4987,7 +4987,7 @@ public function data_process_blocks_custom_css() { 'selector' => '.foo', 'css' => 'color: red; margin: auto; &.one{color: blue;} & .two{color: green;}', ), - 'expected' => '.foo{color: red; margin: auto;}.foo.one{color: blue;}.foo .two{color: green;}', + 'expected' => ':root :where(.foo){color: red; margin: auto;}:root :where(.foo.one){color: blue;}:root :where(.foo .two){color: green;}', ), // CSS with pseudo elements. 'with pseudo elements' => array( @@ -4995,7 +4995,7 @@ public function data_process_blocks_custom_css() { 'selector' => '.foo', 'css' => 'color: red; margin: auto; &::before{color: blue;} & ::before{color: green;} &.one::before{color: yellow;} & .two::before{color: purple;}', ), - 'expected' => '.foo{color: red; margin: auto;}.foo::before{color: blue;}.foo ::before{color: green;}.foo.one::before{color: yellow;}.foo .two::before{color: purple;}', + 'expected' => ':root :where(.foo){color: red; margin: auto;}:root :where(.foo::before){color: blue;}:root :where(.foo ::before){color: green;}:root :where(.foo.one::before){color: yellow;}:root :where(.foo .two::before){color: purple;}', ), // CSS with multiple root selectors. 'with multiple root selectors' => array( @@ -5003,7 +5003,7 @@ public function data_process_blocks_custom_css() { 'selector' => '.foo, .bar', 'css' => 'color: red; margin: auto; &.one{color: blue;} & .two{color: green;} &::before{color: yellow;} & ::before{color: purple;} &.three::before{color: orange;} & .four::before{color: skyblue;}', ), - 'expected' => '.foo, .bar{color: red; margin: auto;}.foo.one, .bar.one{color: blue;}.foo .two, .bar .two{color: green;}.foo::before, .bar::before{color: yellow;}.foo ::before, .bar ::before{color: purple;}.foo.three::before, .bar.three::before{color: orange;}.foo .four::before, .bar .four::before{color: skyblue;}', + 'expected' => ':root :where(.foo, .bar){color: red; margin: auto;}:root :where(.foo.one, .bar.one){color: blue;}:root :where(.foo .two, .bar .two){color: green;}:root :where(.foo::before, .bar::before){color: yellow;}:root :where(.foo ::before, .bar ::before){color: purple;}:root :where(.foo.three::before, .bar.three::before){color: orange;}:root :where(.foo .four::before, .bar .four::before){color: skyblue;}', ), ); } diff --git a/storybook/decorators/with-global-css.js b/storybook/decorators/with-global-css.js index 298d841d1c2a5b..d3d283234be1e5 100644 --- a/storybook/decorators/with-global-css.js +++ b/storybook/decorators/with-global-css.js @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import clsx from 'clsx'; - /** * WordPress dependencies */ @@ -14,6 +9,11 @@ import { useEffect } from '@wordpress/element'; import basicStyles from '../global-basic.lazy.scss'; import wordPressStyles from '../global-wordpress.lazy.scss'; +/** + * External dependencies + */ +import clsx from 'clsx'; + /** * A Storybook decorator to inject global CSS. * diff --git a/test/e2e/specs/editor/various/change-detection.spec.js b/test/e2e/specs/editor/various/change-detection.spec.js index a737e4eb94a5fc..4ac262f4c1348d 100644 --- a/test/e2e/specs/editor/various/change-detection.spec.js +++ b/test/e2e/specs/editor/various/change-detection.spec.js @@ -420,7 +420,7 @@ test.describe( 'Change detection', () => { .click(); await page .getByRole( 'dialog' ) - .getByRole( 'button', { name: 'Delete' } ) + .getByRole( 'button', { name: 'Trash' } ) .click(); await expect( page ).toHaveURL( '/wp-admin/edit.php?post_type=post' ); diff --git a/test/e2e/specs/editor/various/footnotes.spec.js b/test/e2e/specs/editor/various/footnotes.spec.js index 01017b2d2ea2e6..e7fd3804706471 100644 --- a/test/e2e/specs/editor/various/footnotes.spec.js +++ b/test/e2e/specs/editor/various/footnotes.spec.js @@ -363,11 +363,15 @@ test.describe( 'Footnotes', () => { // Open revisions. await editor.openDocumentSettingsSidebar(); + const editorSettings = page.getByRole( 'region', { + name: 'Editor settings', + } ); + await editorSettings.getByRole( 'tab', { name: 'Post' } ).click(); + await editorSettings.getByRole( 'button', { name: 'Actions' } ).click(); await page - .getByRole( 'region', { name: 'Editor settings' } ) - .getByRole( 'tab', { name: 'Post' } ) + .getByRole( 'menu' ) + .getByRole( 'menuitem', { name: 'View revisions' } ) .click(); - await page.locator( 'a:text("Revisions (2)")' ).click(); await page.locator( '.revisions-controls .ui-slider-handle' ).focus(); await page.keyboard.press( 'ArrowLeft' ); await page.locator( 'input:text("Restore This Revision")' ).click(); diff --git a/test/e2e/specs/editor/various/styles.spec.js b/test/e2e/specs/editor/various/styles.spec.js new file mode 100644 index 00000000000000..0aa1f3007d2419 --- /dev/null +++ b/test/e2e/specs/editor/various/styles.spec.js @@ -0,0 +1,17 @@ +/** + * WordPress dependencies + */ +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.describe( 'Styles', () => { + test( 'should override reset styles', async ( { admin, editor } ) => { + await admin.createNewPost( { postType: 'page' } ); + await editor.insertBlock( { name: 'core/social-links' } ); + + const block = editor.canvas.getByRole( 'document', { + name: 'Block: Social Icons', + } ); + + await expect( block ).toHaveCSS( 'padding-left', '0px' ); + } ); +} ); diff --git a/test/e2e/specs/interactivity/namespace.spec.ts b/test/e2e/specs/interactivity/namespace.spec.ts index fd38a7ecf6ed64..9d0edc997886cb 100644 --- a/test/e2e/specs/interactivity/namespace.spec.ts +++ b/test/e2e/specs/interactivity/namespace.spec.ts @@ -20,30 +20,68 @@ test.describe( 'Namespaces', () => { test( 'Empty string as namespace should not work', async ( { page } ) => { const el = page.getByTestId( 'empty namespace' ); - await expect( el ).not.toHaveAttribute( 'href', '/some-url' ); + await expect( el ).not.toHaveAttribute( 'href', '/empty-string-url' ); } ); test( 'A string as namespace should work', async ( { page } ) => { const el = page.getByTestId( 'correct namespace' ); - await expect( el ).toHaveAttribute( 'href', '/some-url' ); + await expect( el ).toHaveAttribute( 'href', '/namespace-url' ); } ); - test( 'An empty object as namespace should work', async ( { page } ) => { + test( 'An empty object as namespace should not work', async ( { + page, + } ) => { const el = page.getByTestId( 'object namespace' ); - await expect( el ).not.toHaveAttribute( 'href', '/some-url' ); + await expect( el ).not.toHaveAttribute( 'href', '/object-url' ); } ); test( 'A wrong namespace should not break the runtime', async ( { page, } ) => { const el = page.getByTestId( 'object namespace' ); - await expect( el ).not.toHaveAttribute( 'href', '/some-url' ); + await expect( el ).not.toHaveAttribute( 'href', '/namespace-url' ); const correct = page.getByTestId( 'correct namespace' ); - await expect( correct ).toHaveAttribute( 'href', '/some-url' ); + await expect( correct ).toHaveAttribute( 'href', '/namespace-url' ); } ); test( 'A different store namespace should work', async ( { page } ) => { const el = page.getByTestId( 'other namespace' ); await expect( el ).toHaveAttribute( 'href', '/other-store-url' ); } ); + + test( 'A number as a string as namespace should work', async ( { + page, + } ) => { + const el = page.getByTestId( 'number namespace' ); + await expect( el ).toHaveAttribute( 'href', '/number-url' ); + } ); + + test( 'A null as a string as namespace should work', async ( { page } ) => { + const el = page.getByTestId( 'null namespace' ); + await expect( el ).toHaveAttribute( 'href', '/null-url' ); + } ); + + test( 'A true as a string as namespace should work', async ( { page } ) => { + const el = page.getByTestId( 'true namespace' ); + await expect( el ).toHaveAttribute( 'href', '/true-url' ); + } ); + + test( 'A false as a string as namespace should work', async ( { + page, + } ) => { + const el = page.getByTestId( 'false namespace' ); + await expect( el ).toHaveAttribute( 'href', '/false-url' ); + } ); + + test( 'A [] as a string as namespace should work', async ( { page } ) => { + const el = page.getByTestId( '[] namespace' ); + await expect( el ).toHaveAttribute( 'href', '/array-url' ); + } ); + + test( 'A "quoted string" as a string as namespace should work', async ( { + page, + } ) => { + const el = page.getByTestId( 'quoted namespace' ); + await expect( el ).toHaveAttribute( 'href', '/quoted-url' ); + } ); } ); diff --git a/test/e2e/specs/site-editor/styles.spec.js b/test/e2e/specs/site-editor/styles.spec.js new file mode 100644 index 00000000000000..66ddf0b7faa1b5 --- /dev/null +++ b/test/e2e/specs/site-editor/styles.spec.js @@ -0,0 +1,59 @@ +/** + * WordPress dependencies + */ +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.describe( 'Styles', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activateTheme( 'twentytwentythree' ); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.activateTheme( 'twentytwentyone' ); + } ); + + test( 'should override reset styles and library styles', async ( { + admin, + editor, + requestUtils, + page, + } ) => { + const { id } = await requestUtils.createPage( { + title: 'Social Icons', + content: ` + +`, + status: 'publish', + } ); + await admin.visitSiteEditor( { + postId: id, + postType: 'page', + canvas: 'edit', + } ); + + const block = editor.canvas.getByRole( 'document', { + name: 'Block: Social Icons', + } ); + + await expect( block ).toHaveCSS( 'padding-left', '0px' ); + + const topBar = page.getByRole( 'region', { name: 'Editor top bar' } ); + // Navigate to Styles -> Blocks -> Heading -> Typography + await topBar.getByRole( 'button', { name: 'Styles' } ).click(); + await page.getByRole( 'button', { name: 'Blocks styles' } ).click(); + await page + .getByRole( 'button', { name: 'Social Icons block styles' } ) + .click(); + + // find the second padding control + const paddingControl = page + .locator( '[aria-label="padding"]' ) + .nth( 1 ); + + // Change the padding value + await paddingControl.fill( '2' ); + + // Check the padding value + await expect( block ).toHaveCSS( 'padding-left', '35.4644px' ); + } ); +} );