diff --git a/lib/block-supports/border.php b/lib/block-supports/border.php index 486f6d99b6489..64b292ce5622a 100644 --- a/lib/block-supports/border.php +++ b/lib/block-supports/border.php @@ -63,15 +63,6 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) { $border_block_styles['radius'] = $border_radius; } - // Border style. - if ( - gutenberg_has_border_feature_support( $block_type, 'style' ) && - isset( $block_attributes['style']['border']['style'] ) && - ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'style' ) - ) { - $border_block_styles['style'] = $block_attributes['style']['border']['style']; - } - // Border width. if ( $has_border_width_support && @@ -98,6 +89,20 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) { $border_block_styles['color'] = $preset_border_color ? $preset_border_color : $custom_border_color; } + // Border style. + if ( + gutenberg_has_border_feature_support( $block_type, 'style' ) && + isset( $block_attributes['style']['border']['style'] ) && + ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'style' ) + ) { + $border_block_styles['style'] = $block_attributes['style']['border']['style']; + } + + // If we set a border color or a border width, make sure we set a border style as well. + if ( isset( $border_block_styles['color'] ) || isset( $border_block_styles['width'] ) ) { + $border_block_styles['style'] = isset( $border_block_styles['style'] ) ? $border_block_styles['style'] : 'solid'; + } + // Generate styles for individual border sides. if ( $has_border_color_support || $has_border_width_support ) { foreach ( array( 'top', 'right', 'bottom', 'left' ) as $side ) { @@ -107,6 +112,12 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) { 'color' => isset( $border['color'] ) && ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'color' ) ? $border['color'] : null, 'style' => isset( $border['style'] ) && ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'style' ) ? $border['style'] : null, ); + + // If we set a border color or a border width, make sure we set a border style as well. + if ( isset( $border_side_values['color'] ) || isset( $border_side_values['width'] ) ) { + $border_side_values['style'] = isset( $border_side_values['style'] ) ? $border_side_values['style'] : 'solid'; + } + $border_block_styles[ $side ] = $border_side_values; } } diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 9a2c9016ae794..895c9c9e85b83 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -1848,6 +1848,21 @@ protected static function compute_style_properties( $styles, $settings = array() $root_variable_duplicates = array(); + // Add a solid style fallback if no style defined. + if ( isset( $styles['border'] ) ) { + if ( + ( isset( $styles['border']['width'] ) || isset( $styles['border']['color'] ) ) && ! isset( $styles['border']['style'] ) ) { + $styles['border']['style'] = 'solid'; + } + foreach ( array( 'top', 'left', 'right', 'bottom' ) as $edge ) { + if ( + isset( $styles['border'][ $edge ]) && + ( isset( $styles['border'][ $edge ]['width'] ) || isset( $styles['border'][ $edge ]['color'] ) ) && ! isset( $styles['border'][ $edge ]['style'] ) ) { + $styles['border'][ $edge ]['style'] = 'solid'; + } + } + } + foreach ( $properties as $css_property => $value_path ) { $value = static::get_property_value( $styles, $value_path, $theme_json ); diff --git a/packages/block-editor/src/components/global-styles/border-panel.js b/packages/block-editor/src/components/global-styles/border-panel.js index b4d47c03efe21..23fadcc1002dd 100644 --- a/packages/block-editor/src/components/global-styles/border-panel.js +++ b/packages/block-editor/src/components/global-styles/border-panel.js @@ -45,35 +45,6 @@ function useHasBorderWidthControl( settings ) { return settings?.border?.width; } -function applyFallbackStyle( border ) { - if ( ! border ) { - return border; - } - - if ( ! border.style && ( border.color || border.width ) ) { - return { ...border, style: 'solid' }; - } - - return border; -} - -function applyAllFallbackStyles( border ) { - if ( ! border ) { - return border; - } - - if ( hasSplitBorders( border ) ) { - return { - top: applyFallbackStyle( border.top ), - right: applyFallbackStyle( border.right ), - bottom: applyFallbackStyle( border.bottom ), - left: applyFallbackStyle( border.left ), - }; - } - - return applyFallbackStyle( border ); -} - function BorderToolsPanel( { resetAllFilter, onChange, @@ -186,7 +157,7 @@ export default function BorderPanel( { const onBorderChange = ( newBorder ) => { // Ensure we have a visible border style when a border width or // color is being selected. - const updatedBorder = applyAllFallbackStyles( newBorder ); + const updatedBorder = newBorder ? { ...newBorder } : undefined; if ( hasSplitBorders( updatedBorder ) ) { [ 'top', 'right', 'bottom', 'left' ].forEach( ( side ) => { diff --git a/packages/block-library/src/common.scss b/packages/block-library/src/common.scss index 2e1c2b8b706bc..5e3d1e5424da6 100644 --- a/packages/block-library/src/common.scss +++ b/packages/block-library/src/common.scss @@ -104,49 +104,6 @@ z-index: 100000; } -/** - * The following provide a simple means of applying a default border style when - * a user first makes a selection in the border block support panel. - * This prevents issues such as where the user could set a border width - * and see no border due there being no border style set. - * - * This is intended to be removed once intelligent defaults can be set while - * making border selections via the block support. - * - * See: https://github.com/WordPress/gutenberg/pull/33743 - */ -html :where(.has-border-color) { - border-style: solid; -} -html :where([style*="border-top-color"]) { - border-top-style: solid; -} -html :where([style*="border-right-color"]) { - border-right-style: solid; -} -html :where([style*="border-bottom-color"]) { - border-bottom-style: solid; -} -html :where([style*="border-left-color"]) { - border-left-style: solid; -} - -html :where([style*="border-width"]) { - border-style: solid; -} -html :where([style*="border-top-width"]) { - border-top-style: solid; -} -html :where([style*="border-right-width"]) { - border-right-style: solid; -} -html :where([style*="border-bottom-width"]) { - border-bottom-style: solid; -} -html :where([style*="border-left-width"]) { - border-left-style: solid; -} - /** * Provide baseline responsiveness for images. */ diff --git a/packages/style-engine/src/styles/border/index.ts b/packages/style-engine/src/styles/border/index.ts index 465e78a09aa5f..f1fdc02e59450 100644 --- a/packages/style-engine/src/styles/border/index.ts +++ b/packages/style-engine/src/styles/border/index.ts @@ -1,7 +1,13 @@ /** * Internal dependencies */ -import type { BoxEdge, GenerateFunction, StyleDefinition } from '../../types'; +import type { + BoxEdge, + GenerateFunction, + StyleDefinition, + Style, + StyleOptions, +} from '../../types'; import { generateRule, generateBoxRules, camelCaseJoin } from '../utils'; /** @@ -26,15 +32,56 @@ function createBorderGenerateFunction( path: string[] ): GenerateFunction { function createBorderEdgeGenerateFunction( edge: BoxEdge ): GenerateFunction { return ( style, options ) => { return [ 'color', 'style', 'width' ].flatMap( ( key ) => { + let styleWithFallback = style; + if ( + ( style?.border?.[ edge ]?.color || + style?.border?.[ edge ]?.width ) && + ! style?.border?.[ edge ]?.style + ) { + styleWithFallback = { + ...style, + border: { + ...style?.border, + [ edge ]: { + ...style?.border?.[ edge ], + style: 'solid', + }, + }, + }; + } const path = [ 'border', edge, key ]; - return createBorderGenerateFunction( path )( style, options ); + return createBorderGenerateFunction( path )( + styleWithFallback, + options + ); } ); }; } const color: StyleDefinition = { name: 'color', - generate: createBorderGenerateFunction( [ 'border', 'color' ] ), + generate: ( style: Style, options: StyleOptions ) => { + const borderColorGenerate = createBorderGenerateFunction( [ + 'border', + 'color', + ] ); + const borderStyleGenerate = createBorderGenerateFunction( [ + 'border', + 'style', + ] ); + const output = borderColorGenerate( style, options ); + if ( style?.border?.color && ! style?.border?.style ) { + return [ + ...output, + ...borderStyleGenerate( + { border: { style: 'solid' } }, + options + ), + ]; + } + + return output; + }, }; const radius: StyleDefinition = { @@ -60,7 +107,32 @@ const borderStyle: StyleDefinition = { const width: StyleDefinition = { name: 'width', - generate: createBorderGenerateFunction( [ 'border', 'width' ] ), + generate: ( style: Style, options: StyleOptions ) => { + const borderWidthGenerate = createBorderGenerateFunction( [ + 'border', + 'width', + ] ); + const borderStyleGenerate = createBorderGenerateFunction( [ + 'border', + 'style', + ] ); + const output = borderWidthGenerate( style, options ); + if ( + style?.border?.width && + ! style?.border.color && // this is only here to avoid duplication + ! style?.border?.style + ) { + return [ + ...output, + ...borderStyleGenerate( + { border: { style: 'solid' } }, + options + ), + ]; + } + + return output; + }, }; const borderTop: StyleDefinition = { diff --git a/packages/style-engine/src/test/index.js b/packages/style-engine/src/test/index.js index fac55b4000e58..bbb9dcef4d5a7 100644 --- a/packages/style-engine/src/test/index.js +++ b/packages/style-engine/src/test/index.js @@ -134,6 +134,40 @@ describe( 'generate', () => { ); } ); + it( 'should geneate a border style fallback if color provided', () => { + expect( + compileCSS( { + border: { + color: 'var:preset|color|perky-peppermint', + }, + } ) + ).toEqual( + 'border-color: var(--wp--preset--color--perky-peppermint); border-style: solid;' + ); + } ); + + it( 'should geneate a border style fallback if width provided', () => { + expect( + compileCSS( { + border: { + width: '5px', + }, + } ) + ).toEqual( 'border-width: 5px; border-style: solid;' ); + } ); + + it( 'should geneate a border style fallback for individual border rules too', () => { + expect( + compileCSS( { + border: { + top: { + width: '5px', + }, + }, + } ) + ).toEqual( 'border-top-style: solid; border-top-width: 5px;' ); + } ); + it( 'should parse individual border rules', () => { expect( compileCSS( { @@ -166,7 +200,7 @@ describe( 'generate', () => { }, } ) ).toEqual( - 'border-top-left-radius: 1px; border-top-right-radius: 2px; border-bottom-left-radius: 3px; border-bottom-right-radius: 4px; border-top-color: var(--wp--preset--color--sandy-beach); border-top-style: dashed; border-top-width: 9px; border-right-color: var(--wp--preset--color--leafy-avenue); border-right-width: 5rem; border-bottom-color: #eee; border-bottom-style: solid; border-bottom-width: 2%; border-left-color: var(--wp--preset--color--avocado-blues); border-left-style: dotted; border-left-width: 100px;' + 'border-top-left-radius: 1px; border-top-right-radius: 2px; border-bottom-left-radius: 3px; border-bottom-right-radius: 4px; border-top-color: var(--wp--preset--color--sandy-beach); border-top-style: dashed; border-top-width: 9px; border-right-color: var(--wp--preset--color--leafy-avenue); border-right-style: solid; border-right-width: 5rem; border-bottom-color: #eee; border-bottom-style: solid; border-bottom-width: 2%; border-left-color: var(--wp--preset--color--avocado-blues); border-left-style: dotted; border-left-width: 100px;' ); } ); } );