Skip to content
Prev Previous commit
Next Next commit
Add support for em and rem height values
  • Loading branch information
aaronrobertshaw committed Jan 27, 2021
commit b743c6c6068d5f7d119e7d9f25615e7c10467bb9
4 changes: 4 additions & 0 deletions packages/block-library/src/separator/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
},
"height": {
"type": "number"
},
"heightUnit": {
"type": "string",
"default": "px"
}
},
"supports": {
Expand Down
72 changes: 55 additions & 17 deletions packages/block-library/src/separator/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,76 @@ import { clamp } from 'lodash';
* WordPress dependencies
*/
import { HorizontalRule, ResizableBox } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { useEffect, useState } from '@wordpress/element';
import { withColors, useBlockProps } from '@wordpress/block-editor';
import { View } from '@wordpress/primitives';

/**
* Internal dependencies
*/
import SeparatorSettings from './separator-settings';

const MIN_HEIGHT = 20;
const MIN_DOTS_HEIGHT = 30;
const MAX_HEIGHT = 500;
import { getHeightConstraints } from './height-constraints';

function SeparatorEdit( props ) {
const { attributes, setAttributes, color, setColor, isSelected } = props;
const { height } = attributes;
const hasDotsStyle = attributes.className?.indexOf( 'is-style-dots' ) >= 0;
const { height, heightUnit } = attributes;
const [ isResizing, setIsResizing ] = useState( false );

const hasDotsStyle = attributes.className?.indexOf( 'is-style-dots' ) >= 0;
const minimumHeightScale = hasDotsStyle ? 1.5 : 1;
const heightConstraints = getHeightConstraints( minimumHeightScale );
const currentMinHeight = heightConstraints[ heightUnit ].min;
const currentMaxHeight = heightConstraints[ heightUnit ].max;

useEffect( () => {
if ( height < currentMinHeight ) {
setAttributes( { height: currentMinHeight } );
}
}, [ hasDotsStyle, heightConstraints ] );

const onResizeStart = () => {
setIsResizing( true );
};

// Change handler for sidebar height control only.
const updateHeight = ( value ) => {
setAttributes( {
height: clamp( Math.round( value ), MIN_HEIGHT, MAX_HEIGHT ),
height: clamp(
parseFloat( value ), // Rounding or parsing as integer here isn't ideal for em and rem units.
currentMinHeight,
currentMaxHeight
),
heightUnit,
} );
};

const updateHeightUnit = ( value ) => {
setAttributes( {
height: heightConstraints[ value ].default,
heightUnit: value,
} );
};

// ResizableBox callback to set height and force pixel units.
const onResizeStop = ( _event, _direction, elt ) => {
updateHeight( elt.clientHeight );
setAttributes( {
height: clamp(
parseInt( elt.clientHeight, 10 ),
heightConstraints.px.min,
heightConstraints.px.max
),
heightUnit: 'px',
} );
setIsResizing( false );
};

// const minHeight = `${ currentMinHeight }${ heightUnit }`;
const cssHeight = `${ height }${ heightUnit }`;
const blockProps = useBlockProps();
const wrapperClasses = blockProps.className?.replace(
'wp-block-separator',
'wp-block-separator__wrapper'
);

// The block's className and styles are moved to the inner <hr> to retain
// the different styling approaches between themes. The use of bottom
Expand All @@ -53,10 +88,8 @@ function SeparatorEdit( props ) {
<>
<View
{ ...blockProps }
className={ blockProps.className?.replace(
'wp-block-separator',
''
) }
className={ wrapperClasses }
style={ { height: height ? cssHeight : undefined } }
>
<HorizontalRule
className={ classnames( blockProps.className, {
Expand All @@ -75,7 +108,10 @@ function SeparatorEdit( props ) {
'is-selected': isSelected,
}
) }
size={ { height } }
size={ {
height:
heightUnit === 'px' && height ? cssHeight : '100%',
} }
enable={ {
top: false,
right: false,
Expand All @@ -86,7 +122,7 @@ function SeparatorEdit( props ) {
bottomLeft: false,
topLeft: false,
} }
minHeight={ hasDotsStyle ? MIN_DOTS_HEIGHT : MIN_HEIGHT }
minHeight={ heightConstraints.px.min }
onResizeStart={ onResizeStart }
onResizeStop={ onResizeStop }
showHandle={ isSelected }
Expand All @@ -101,10 +137,12 @@ function SeparatorEdit( props ) {
<SeparatorSettings
color={ color }
setColor={ setColor }
minHeight={ hasDotsStyle ? MIN_DOTS_HEIGHT : MIN_HEIGHT }
maxHeight={ MAX_HEIGHT }
minHeight={ currentMinHeight }
maxHeight={ currentMaxHeight }
height={ height }
heightUnit={ heightUnit }
updateHeight={ updateHeight }
updateHeightUnit={ updateHeightUnit }
/>
</>
);
Expand Down
6 changes: 6 additions & 0 deletions packages/block-library/src/separator/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
position: relative;
}

.editor-styles-wrapper {
.wp-block.wp-block-separator__wrapper {
margin: 0 auto;
}
}

// Duplicate selector to overcome theme specificity.
.editor-styles-wrapper .wp-block .wp-block-separator.wp-block-separator {
// Remove default margins and center within ResizableBox control.
Expand Down
26 changes: 26 additions & 0 deletions packages/block-library/src/separator/height-constraints.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const MIN_PX_HEIGHT = 20;
const MIN_EM_HEIGHT = 1;
const MIN_REM_HEIGHT = 1;
const MAX_PX_HEIGHT = 500;
const MAX_EM_HEIGHT = 30;
const MAX_REM_HEIGHT = 30;

export const getHeightConstraints = ( minimumScale = 1 ) => {
return {
px: {
min: minimumScale * MIN_PX_HEIGHT,
max: MAX_PX_HEIGHT,
default: minimumScale * MIN_PX_HEIGHT,
},
em: {
min: minimumScale * MIN_EM_HEIGHT,
max: MAX_EM_HEIGHT,
default: 1,
},
rem: {
min: minimumScale * MIN_REM_HEIGHT,
max: MAX_REM_HEIGHT,
default: 1,
},
};
};
4 changes: 2 additions & 2 deletions packages/block-library/src/separator/save.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import classnames from 'classnames';
import { getColorClassName, useBlockProps } from '@wordpress/block-editor';

export default function separatorSave( { attributes } ) {
const { color, customColor, height } = attributes;
const margin = height ? `${ height / 2 }px` : undefined;
const { color, customColor, height, heightUnit } = attributes;
const margin = height ? `${ height / 2 }${ heightUnit }` : undefined;

// the hr support changing color using border-color, since border-color
// is not yet supported in the color palette, we use background-color
Expand Down
89 changes: 57 additions & 32 deletions packages/block-library/src/separator/separator-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,63 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { InspectorControls, PanelColorSettings } from '@wordpress/block-editor';
import { PanelBody, RangeControl } from '@wordpress/components';
import {
InspectorControls,
PanelColorSettings,
__experimentalUnitControl as UnitControl,
} from '@wordpress/block-editor';
import { BaseControl, PanelBody } from '@wordpress/components';
import { useInstanceId } from '@wordpress/compose';

const SeparatorSettings = ( {
color,
setColor,
height,
minHeight,
maxHeight,
updateHeight,
} ) => (
<InspectorControls>
<PanelBody title={ __( 'Separator settings' ) }>
<RangeControl
label={ __( 'Height in pixels' ) }
min={ minHeight }
max={ maxHeight }
value={ height }
onChange={ updateHeight }
/>
</PanelBody>
<PanelColorSettings
title={ __( 'Color settings' ) }
colorSettings={ [
{
value: color.color,
onChange: setColor,
label: __( 'Color' ),
},
] }
></PanelColorSettings>
</InspectorControls>
);
const HEIGHT_CSS_UNITS = [
{ value: 'px', label: 'px', default: 0 },
{ value: 'em', label: 'em', default: 0 },
{ value: 'rem', label: 'rem', default: 0 },
];

const SeparatorSettings = ( props ) => {
const {
color,
setColor,
height,
heightUnit,
minHeight,
maxHeight,
updateHeight,
updateHeightUnit,
} = props;
const unitControlInstanceId = useInstanceId( UnitControl );
const unitControlInputId = `wp-block-separator__height-${ unitControlInstanceId }`;

return (
<InspectorControls>
<PanelBody title={ __( 'Separator settings' ) }>
<BaseControl label={ __( 'Height' ) } id={ unitControlInputId }>
<UnitControl
id={ unitControlInputId }
min={ minHeight }
max={ maxHeight }
onChange={ updateHeight }
onUnitChange={ updateHeightUnit }
value={ `${ height }${ heightUnit }` }
unit={ heightUnit }
units={ HEIGHT_CSS_UNITS }
step={ heightUnit === 'px' ? '1' : '0.25' }
/>
</BaseControl>
</PanelBody>
<PanelColorSettings
title={ __( 'Color settings' ) }
colorSettings={ [
{
value: color.color,
onChange: setColor,
label: __( 'Color' ),
},
] }
></PanelColorSettings>
</InspectorControls>
);
};

export default SeparatorSettings;