Skip to content
7 changes: 7 additions & 0 deletions packages/block-library/src/separator/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
},
"customColor": {
"type": "string"
},
"height": {
"type": "number"
},
"heightUnit": {
"type": "string",
"default": "px"
}
},
"supports": {
Expand Down
108 changes: 98 additions & 10 deletions packages/block-library/src/separator/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,121 @@
* External dependencies
*/
import classnames from 'classnames';
import { clamp } from 'lodash';

/**
* WordPress dependencies
*/
import { HorizontalRule } from '@wordpress/components';
import { HorizontalRule, ResizableBox } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { withColors, useBlockProps } from '@wordpress/block-editor';
import { View } from '@wordpress/primitives';

/**
* Internal dependencies
*/
import SeparatorSettings from './separator-settings';
import { HEIGHT_CONSTRAINTS } from './shared';

function SeparatorEdit( props ) {
const { attributes, setAttributes, color, setColor, isSelected } = props;
const { height, heightUnit } = attributes;
const [ isResizing, setIsResizing ] = useState( false );

const currentMinHeight = HEIGHT_CONSTRAINTS[ heightUnit ].min;
const currentMaxHeight = HEIGHT_CONSTRAINTS[ heightUnit ].max;

// Resize handler for when user is drag resizing block via ResizableBlock.
const onResize = ( _event, _direction, elt ) => {
setAttributes( {
height: clamp(
parseInt( elt.clientHeight, 10 ),
HEIGHT_CONSTRAINTS.px.min,
HEIGHT_CONSTRAINTS.px.max
),
heightUnit: 'px',
} );
};

const cssHeight = `${ height }${ heightUnit }`;
const blockProps = useBlockProps();
const margin = height
? `${ height / 2 }${ heightUnit }`
: `${ currentMinHeight / 2 }${ heightUnit }`;

function SeparatorEdit( { color, setColor, className } ) {
// The block's className and styles are moved to the inner <hr> to retain
// the different styling approaches between themes. The use of bottom
// borders and background colors prevents using padding internally on the
// edit component. Adjusting margins leads to losing visual indicators for
// block selection.
return (
<>
<HorizontalRule
{ ...useBlockProps( {
className: classnames( className, {
<View
{ ...blockProps }
className={ blockProps.className?.replace(
'wp-block-separator',
'wp-block-separator__wrapper'
) }
style={ { height: height ? cssHeight : currentMinHeight } }
>
<HorizontalRule
className={ classnames( blockProps.className, {
'has-background': color.color,
[ color.class ]: color.class,
} ),
style: {
} ) }
style={ {
backgroundColor: color.color,
color: color.color,
},
} ) }
marginTop: margin,
marginBottom: margin,
} }
/>
<ResizableBox
className={ classnames(
'block-library-separator__resize-container',
{
'is-selected': isSelected,
}
) }
size={ {
height:
heightUnit === 'px' && height ? cssHeight : '100%',
} }
enable={ {
top: false,
right: false,
bottom: true, // Only enable bottom handle.
left: false,
topRight: false,
bottomRight: false,
bottomLeft: false,
topLeft: false,
} }
minHeight={ HEIGHT_CONSTRAINTS.px.min }
onResizeStart={ () => setIsResizing( true ) }
onResize={ onResize }
onResizeStop={ ( ...args ) => {
onResize( ...args );
setIsResizing( false );
} }
showHandle={ isSelected }
__experimentalShowTooltip={ true }
__experimentalTooltipProps={ {
axis: 'y',
position: 'bottom',
isVisible: isResizing,
} }
/>
</View>
<SeparatorSettings
color={ color }
setColor={ setColor }
minHeight={ currentMinHeight }
maxHeight={ currentMaxHeight }
height={ height }
heightUnit={ heightUnit }
setAttributes={ setAttributes }
/>
<SeparatorSettings color={ color } setColor={ setColor } />
</>
);
}
Expand Down
79 changes: 79 additions & 0 deletions packages/block-library/src/separator/edit.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { HorizontalRule, useConvertUnitToMobile } from '@wordpress/components';
import { withColors, useBlockProps } from '@wordpress/block-editor';
import { View } from '@wordpress/primitives';

/**
* Internal dependencies
*/
import SeparatorSettings from './separator-settings';
import { HEIGHT_CONSTRAINTS } from './shared';

function SeparatorEdit( props ) {
const {
attributes: { height, heightUnit },
setAttributes,
color,
setColor,
} = props;

const currentMinHeight = HEIGHT_CONSTRAINTS[ heightUnit ].min;
const currentMaxHeight = HEIGHT_CONSTRAINTS[ heightUnit ].max;

const convertedHeightValue = useConvertUnitToMobile(
height || currentMinHeight,
heightUnit
);

const margin = convertedHeightValue / 2;
const blockProps = useBlockProps();

// The block's className and styles are moved to the inner <hr> to retain
// the different styling approaches between themes. The use of bottom
// borders and background colors prevents using padding internally on the
// edit component. Adjusting margins leads to losing visual indicators for
// block selection.
return (
<>
<View
{ ...blockProps }
className={ blockProps.className?.replace(
'wp-block-separator',
'wp-block-separator__wrapper'
) }
style={ { height: convertedHeightValue } }
>
<HorizontalRule
className={ classnames( blockProps.className, {
'has-background': color.color,
[ color.class ]: color.class,
} ) }
style={ {
backgroundColor: color.color,
color: color.color,
marginTop: margin,
marginBottom: margin,
} }
/>
</View>
<SeparatorSettings
color={ color }
setColor={ setColor }
minHeight={ currentMinHeight }
maxHeight={ currentMaxHeight }
height={ height || currentMinHeight }
heightUnit={ heightUnit }
setAttributes={ setAttributes }
/>
</>
);
}

export default withColors( 'color', { textColor: 'color' } )( SeparatorEdit );
26 changes: 26 additions & 0 deletions packages/block-library/src/separator/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,29 @@
padding-top: 0.1px;
padding-bottom: 0.1px;
}

.block-library-separator__wrapper {
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 {
margin: 0;
position: absolute;
width: 100%;

&.is-style-dots {
border-top: none;
}
}

// Counter the added height of the dots style's pseudo after element
.wp-block-separator__wrapper.is-style-dots .is-style-dots {
transform: translateY(-0.75em);
}
5 changes: 4 additions & 1 deletion packages/block-library/src/separator/save.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import classnames from 'classnames';
import { getColorClassName, useBlockProps } from '@wordpress/block-editor';

export default function separatorSave( { attributes } ) {
const { color, customColor } = attributes;
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 All @@ -27,6 +28,8 @@ export default function separatorSave( { attributes } ) {
const style = {
backgroundColor: backgroundClass ? undefined : customColor,
color: colorClass ? undefined : customColor,
marginBottom: margin,
marginTop: margin,
};

return <hr { ...useBlockProps.save( { className, style } ) } />;
Expand Down
75 changes: 61 additions & 14 deletions packages/block-library/src/separator/separator-settings.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,69 @@
/**
* External dependencies
*/
import { clamp } from 'lodash';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { InspectorControls, PanelColorSettings } from '@wordpress/block-editor';
import {
PanelBody,
__experimentalUnitControl as UnitControl,
} from '@wordpress/components';

/**
* Internal dependencies
*/
import { HEIGHT_CONSTRAINTS, HEIGHT_CSS_UNITS } from './shared';

const SeparatorSettings = ( props ) => {
const { color, setColor, height, heightUnit, setAttributes } = props;
const minHeight = HEIGHT_CONSTRAINTS[ heightUnit ].min;
const maxHeight = HEIGHT_CONSTRAINTS[ heightUnit ].max;

const updateHeight = ( value ) => {
setAttributes( {
height: clamp( parseFloat( value ), minHeight, maxHeight ),
heightUnit,
} );
};

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

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

export default SeparatorSettings;
Loading