Skip to content

Commit

Permalink
Block Support: Update border support to allow non-pixel units (#31483)
Browse files Browse the repository at this point in the history
* Update border support to allow non-pixel units
* Fix search block to work with non-pixel border radius units
  • Loading branch information
aaronrobertshaw committed Jun 7, 2021
1 parent e9f0983 commit d4e9c65
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 37 deletions.
20 changes: 16 additions & 4 deletions lib/block-supports/border.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,14 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) {
gutenberg_has_border_feature_support( $block_type, 'radius' ) &&
isset( $block_attributes['style']['border']['radius'] )
) {
$border_radius = (int) $block_attributes['style']['border']['radius'];
$styles[] = sprintf( 'border-radius: %dpx;', $border_radius );
$border_radius = $block_attributes['style']['border']['radius'];

// This check handles original unitless implementation.
if ( is_numeric( $border_radius ) ) {
$border_radius .= 'px';
}

$styles[] = sprintf( 'border-radius: %s;', $border_radius );
}

// Border style.
Expand All @@ -74,8 +80,14 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) {
gutenberg_has_border_feature_support( $block_type, 'width' ) &&
isset( $block_attributes['style']['border']['width'] )
) {
$border_width = intval( $block_attributes['style']['border']['width'] );
$styles[] = sprintf( 'border-width: %dpx;', $border_width );
$border_width = $block_attributes['style']['border']['width'];

// This check handles original unitless implementation.
if ( is_numeric( $border_width ) ) {
$border_width .= 'px';
}

$styles[] = sprintf( 'border-width: %s;', $border_width );
}

// Border color.
Expand Down
24 changes: 17 additions & 7 deletions packages/block-editor/src/hooks/border-radius.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
/**
* WordPress dependencies
*/
import { RangeControl } from '@wordpress/components';
import { __experimentalUnitControl as UnitControl } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { CSS_UNITS, parseUnit } from './border';
import { cleanEmptyObject } from './utils';

const MIN_BORDER_RADIUS_VALUE = 0;
const MAX_BORDER_RADIUS_VALUE = 50;

/**
* Inspector control panel containing the border radius related configuration.
Expand All @@ -24,6 +25,15 @@ export function BorderRadiusEdit( props ) {
setAttributes,
} = props;

// Step value is maintained in state so step is appropriate for current unit
// even when current radius value is undefined.
const initialStep = parseUnit( style?.border?.radius ) === 'px' ? 1 : 0.25;
const [ step, setStep ] = useState( initialStep );

const onUnitChange = ( newUnit ) => {
setStep( newUnit === 'px' ? 1 : 0.25 );
};

const onChange = ( newRadius ) => {
let newStyle = {
...style,
Expand All @@ -33,22 +43,22 @@ export function BorderRadiusEdit( props ) {
},
};

if ( newRadius === undefined ) {
if ( newRadius === undefined || newRadius === '' ) {
newStyle = cleanEmptyObject( newStyle );
}

setAttributes( { style: newStyle } );
};

return (
<RangeControl
<UnitControl
value={ style?.border?.radius }
label={ __( 'Border radius' ) }
min={ MIN_BORDER_RADIUS_VALUE }
max={ MAX_BORDER_RADIUS_VALUE }
initialPosition={ 0 }
allowReset
onChange={ onChange }
onUnitChange={ onUnitChange }
step={ step }
units={ CSS_UNITS }
/>
);
}
30 changes: 22 additions & 8 deletions packages/block-editor/src/hooks/border-width.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
/**
* WordPress dependencies
*/
import { RangeControl } from '@wordpress/components';
import { __experimentalUnitControl as UnitControl } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { CSS_UNITS, parseUnit } from './border';
import { cleanEmptyObject } from './utils';

const MIN_BORDER_WIDTH = 0;
const MAX_BORDER_WIDTH = 50;

/**
* Inspector control for configuring border width property.
Expand All @@ -24,27 +25,40 @@ export const BorderWidthEdit = ( props ) => {
setAttributes,
} = props;

// Step value is maintained in state so step is appropriate for current unit
// even when current radius value is undefined.
const initialStep = parseUnit( style?.border?.width ) === 'px' ? 1 : 0.25;
const [ step, setStep ] = useState( initialStep );

const onUnitChange = ( newUnit ) => {
setStep( newUnit === 'px' ? 1 : 0.25 );
};

const onChange = ( newWidth ) => {
const newStyle = {
let newStyle = {
...style,
border: {
...style?.border,
width: newWidth,
},
};

setAttributes( { style: cleanEmptyObject( newStyle ) } );
if ( newWidth === undefined || newWidth === '' ) {
newStyle = cleanEmptyObject( newStyle );
}

setAttributes( { style: newStyle } );
};

return (
<RangeControl
<UnitControl
value={ style?.border?.width }
label={ __( 'Border width' ) }
min={ MIN_BORDER_WIDTH }
max={ MAX_BORDER_WIDTH }
initialPosition={ 0 }
allowReset
onChange={ onChange }
onUnitChange={ onUnitChange }
step={ step }
units={ CSS_UNITS }
/>
);
};
43 changes: 42 additions & 1 deletion packages/block-editor/src/hooks/border.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,44 @@ import { BorderRadiusEdit } from './border-radius';
import { BorderStyleEdit } from './border-style';
import { BorderWidthEdit } from './border-width';

const isWeb = Platform.OS === 'web';

export const BORDER_SUPPORT_KEY = '__experimentalBorder';
export const CSS_UNITS = [
{
value: 'px',
label: isWeb ? 'px' : __( 'Pixels (px)' ),
default: '',
a11yLabel: __( 'Pixels (px)' ),
},
{
value: 'em',
label: isWeb ? 'em' : __( 'Relative to parent font size (em)' ),
default: '',
a11yLabel: __( 'Relative to parent font size (em)' ),
},
{
value: 'rem',
label: isWeb ? 'rem' : __( 'Relative to root font size (rem)' ),
default: '',
a11yLabel: __( 'Relative to root font size (rem)' ),
},
];

/**
* Parses a CSS unit from a border CSS value.
*
* @param {string} cssValue CSS value to parse e.g. `10px` or `1.5em`.
* @return {string} CSS unit from provided value or default 'px'.
*/
export function parseUnit( cssValue ) {
const value = String( cssValue ).trim();
const unitMatch = value.match( /[\d.\-\+]*\s*(.*)/ )[ 1 ];
const unit = unitMatch !== undefined ? unitMatch.toLowerCase() : '';
const currentUnit = CSS_UNITS.find( ( item ) => item.value === unit );

return currentUnit?.value || 'px';
}

export function BorderPanel( props ) {
const isDisabled = useIsBorderDisabled( props );
Expand Down Expand Up @@ -44,7 +81,11 @@ export function BorderPanel( props ) {

return (
<InspectorControls>
<PanelBody title={ __( 'Border settings' ) } initialOpen={ false }>
<PanelBody
className="block-editor-hooks__border-controls"
title={ __( 'Border settings' ) }
initialOpen={ false }
>
{ isStyleSupported && <BorderStyleEdit { ...props } /> }
{ isWidthSupported && <BorderWidthEdit { ...props } /> }
{ isRadiusSupported && <BorderRadiusEdit { ...props } /> }
Expand Down
10 changes: 10 additions & 0 deletions packages/block-editor/src/hooks/border.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.block-editor-hooks__border-controls {
.components-unit-control-wrapper {
margin-bottom: $grid-unit-30;

&:last-child {
margin-bottom: $grid-unit-10;
}
}
}

8 changes: 4 additions & 4 deletions packages/block-editor/src/hooks/test/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ describe( 'getInlineStyles', () => {
color: { text: 'red', background: 'black' },
typography: { lineHeight: 1.5, fontSize: 10 },
border: {
radius: 10,
width: 3,
radius: '10px',
width: '1em',
style: 'dotted',
color: '#21759b',
},
Expand All @@ -31,9 +31,9 @@ describe( 'getInlineStyles', () => {
).toEqual( {
backgroundColor: 'black',
borderColor: '#21759b',
borderRadius: 10,
borderRadius: '10px',
borderStyle: 'dotted',
borderWidth: 3,
borderWidth: '1em',
color: 'red',
lineHeight: 1.5,
fontSize: 10,
Expand Down
1 change: 1 addition & 0 deletions packages/block-editor/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
@import "./components/warning/style.scss";
@import "./hooks/anchor.scss";
@import "./hooks/layout.scss";
@import "./hooks/border.scss";

// This tag marks the end of the styles that apply to editing canvas contents and need to be manipulated when we resize the editor.
#end-resizable-editor-section {
Expand Down
4 changes: 1 addition & 3 deletions packages/block-library/src/button/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,7 @@ function ButtonEdit( props ) {
}
) }
style={ {
borderRadius: borderRadius
? borderRadius + 'px'
: undefined,
borderRadius: borderRadius ? borderRadius : undefined,
...colorProps.style,
} }
onSplit={ ( value ) =>
Expand Down
2 changes: 1 addition & 1 deletion packages/block-library/src/button/save.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default function save( { attributes, className } ) {
}
);
const buttonStyle = {
borderRadius: borderRadius ? borderRadius + 'px' : undefined,
borderRadius: borderRadius ? borderRadius : undefined,
...colorProps.style,
};

Expand Down
14 changes: 10 additions & 4 deletions packages/block-library/src/search/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import {

// Used to calculate border radius adjustment to avoid "fat" corners when
// button is placed inside wrapper.
const DEFAULT_INNER_PADDING = 4;
const DEFAULT_INNER_PADDING = '4px';

export default function SearchEdit( {
className,
Expand Down Expand Up @@ -323,10 +323,16 @@ export default function SearchEdit( {
if ( 'button-inside' === buttonPosition && style?.border?.radius ) {
// We have button inside wrapper and a border radius value to apply.
// Add default padding so we don't get "fat" corners.
const outerRadius =
parseInt( style?.border?.radius, 10 ) + DEFAULT_INNER_PADDING;
//
// CSS calc() is used here to support non-pixel units. The inline
// style using calc() will only apply if both values have units.
const radius = Number.isInteger( borderRadius )
? `${ borderRadius }px`
: borderRadius;

return { borderRadius: `${ outerRadius }px` };
return {
borderRadius: `calc(${ radius } + ${ DEFAULT_INNER_PADDING })`,
};
}

return undefined;
Expand Down
14 changes: 9 additions & 5 deletions packages/block-library/src/search/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,8 @@ function styles_for_block_core_search( $attributes ) {
if ( $has_border_radius ) {
// Shared style for button and input radius values.
$border_radius = $attributes['style']['border']['radius'];
$shared_styles[] = sprintf( 'border-radius: %spx;', esc_attr( $border_radius ) );
$border_radius = is_numeric( $border_radius ) ? $border_radius . 'px' : $border_radius;
$shared_styles[] = sprintf( 'border-radius: %s;', esc_attr( $border_radius ) );

// Apply wrapper border radius if button placed inside.
$button_inside = ! empty( $attributes['buttonPosition'] ) &&
Expand All @@ -199,10 +200,13 @@ function styles_for_block_core_search( $attributes ) {
if ( $button_inside ) {
// We adjust the border radius value for the outer wrapper element
// to make it visually consistent with the radius applied to inner
// elements.
$default_padding = 4;
$adjusted_radius = $border_radius + $default_padding;
$wrapper_styles[] = sprintf( 'border-radius: %dpx;', esc_attr( $adjusted_radius ) );
// elements. calc() is used to support non-pixel CSS units.
$default_padding = '4px';
$wrapper_styles[] = sprintf(
'border-radius: calc(%s + %s);',
esc_attr( $border_radius ),
esc_attr( $default_padding )
);
}
}

Expand Down

0 comments on commit d4e9c65

Please sign in to comment.