diff --git a/packages/block-library/src/separator/block.json b/packages/block-library/src/separator/block.json index 2983a93a86190a..0fbb45a2930127 100644 --- a/packages/block-library/src/separator/block.json +++ b/packages/block-library/src/separator/block.json @@ -8,6 +8,13 @@ }, "customColor": { "type": "string" + }, + "height": { + "type": "number" + }, + "heightUnit": { + "type": "string", + "default": "px" } }, "supports": { diff --git a/packages/block-library/src/separator/edit.js b/packages/block-library/src/separator/edit.js index f611abde42a62b..e5c881b949a959 100644 --- a/packages/block-library/src/separator/edit.js +++ b/packages/block-library/src/separator/edit.js @@ -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
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 ( <> - + + setIsResizing( true ) } + onResize={ onResize } + onResizeStop={ ( ...args ) => { + onResize( ...args ); + setIsResizing( false ); + } } + showHandle={ isSelected } + __experimentalShowTooltip={ true } + __experimentalTooltipProps={ { + axis: 'y', + position: 'bottom', + isVisible: isResizing, + } } + /> + + - ); } diff --git a/packages/block-library/src/separator/edit.native.js b/packages/block-library/src/separator/edit.native.js new file mode 100644 index 00000000000000..b6a1bf95fa120f --- /dev/null +++ b/packages/block-library/src/separator/edit.native.js @@ -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
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 ( + <> + + + + + + ); +} + +export default withColors( 'color', { textColor: 'color' } )( SeparatorEdit ); diff --git a/packages/block-library/src/separator/editor.scss b/packages/block-library/src/separator/editor.scss index 24e940684279e8..18a056860465fe 100644 --- a/packages/block-library/src/separator/editor.scss +++ b/packages/block-library/src/separator/editor.scss @@ -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); +} diff --git a/packages/block-library/src/separator/save.js b/packages/block-library/src/separator/save.js index 67d489bd611c3c..6ce2c7a342af98 100644 --- a/packages/block-library/src/separator/save.js +++ b/packages/block-library/src/separator/save.js @@ -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 @@ -27,6 +28,8 @@ export default function separatorSave( { attributes } ) { const style = { backgroundColor: backgroundClass ? undefined : customColor, color: colorClass ? undefined : customColor, + marginBottom: margin, + marginTop: margin, }; return
; diff --git a/packages/block-library/src/separator/separator-settings.js b/packages/block-library/src/separator/separator-settings.js index 320cfc862b93bd..561b12adaebb64 100644 --- a/packages/block-library/src/separator/separator-settings.js +++ b/packages/block-library/src/separator/separator-settings.js @@ -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 } ) => ( - - - -); + return ( + + + + + + + ); +}; export default SeparatorSettings; diff --git a/packages/block-library/src/separator/separator-settings.native.js b/packages/block-library/src/separator/separator-settings.native.js index d2bdd8ef6443a3..77c6526bd900df 100644 --- a/packages/block-library/src/separator/separator-settings.native.js +++ b/packages/block-library/src/separator/separator-settings.native.js @@ -1,3 +1,68 @@ -// Mobile has no separator settings at this time, so render nothing -const SeparatorSettings = () => null; +/** + * External dependencies + */ +import { clamp } from 'lodash'; + +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { InspectorControls, PanelColorSettings } from '@wordpress/block-editor'; +import { PanelBody, 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, + } ); + }; + + return ( + + + + + + + ); +}; + export default SeparatorSettings; diff --git a/packages/block-library/src/separator/shared.js b/packages/block-library/src/separator/shared.js new file mode 100644 index 00000000000000..46755a90d4a219 --- /dev/null +++ b/packages/block-library/src/separator/shared.js @@ -0,0 +1,53 @@ +/** + * WordPress dependencies + */ +import { Platform } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; + +//Separator height related constants. +export const MIN_PX_HEIGHT = 30; +export const MIN_EM_HEIGHT = 1.5; +export const MIN_REM_HEIGHT = 1.5; +export const MAX_PX_HEIGHT = 500; +export const MAX_EM_HEIGHT = 30; +export const MAX_REM_HEIGHT = 30; + +const isWeb = Platform.OS === 'web'; + +/** + * Available CSS units for specifying Separator height. + */ +export const HEIGHT_CSS_UNITS = [ + { value: 'px', label: isWeb ? 'px' : __( 'Pixels (px)' ), default: 0 }, + { + value: 'em', + label: isWeb ? 'em' : __( 'Relative to parent font size (em)' ), + default: 0, + }, + { + value: 'rem', + label: isWeb ? 'rem' : __( 'Relative to root font size (rem)' ), + default: 0, + }, +]; + +/** + * Separator height constraints for available CSS units. + */ +export const HEIGHT_CONSTRAINTS = { + px: { + min: MIN_PX_HEIGHT, + max: MAX_PX_HEIGHT, + default: MIN_PX_HEIGHT, + }, + em: { + min: MIN_EM_HEIGHT, + max: MAX_EM_HEIGHT, + default: 1.5, + }, + rem: { + min: MIN_REM_HEIGHT, + max: MAX_REM_HEIGHT, + default: 1.5, + }, +}; diff --git a/packages/primitives/src/horizontal-rule/index.native.js b/packages/primitives/src/horizontal-rule/index.native.js index 853b57e76d0c1a..6046411cbbe82f 100644 --- a/packages/primitives/src/horizontal-rule/index.native.js +++ b/packages/primitives/src/horizontal-rule/index.native.js @@ -2,6 +2,7 @@ * External dependencies */ import Hr from 'react-native-hr'; +import { View } from 'react-native'; /** * WordPress dependencies @@ -13,16 +14,25 @@ import { withPreferredColorScheme } from '@wordpress/compose'; */ import styles from './styles.scss'; -const HR = ( { getStylesFromColorScheme, ...props } ) => { +const HR = ( { getStylesFromColorScheme, style, ...props } ) => { const lineStyle = getStylesFromColorScheme( styles.line, styles.lineDark ); + const customBackground = style?.backgroundColor + ? { backgroundColor: style.backgroundColor } + : {}; return ( -
+ +
+
); }; diff --git a/packages/primitives/src/horizontal-rule/styles.native.scss b/packages/primitives/src/horizontal-rule/styles.native.scss index dabb62a8336542..7ec1e49e85d2c2 100644 --- a/packages/primitives/src/horizontal-rule/styles.native.scss +++ b/packages/primitives/src/horizontal-rule/styles.native.scss @@ -1,3 +1,13 @@ +.container { + align-items: center; + bottom: 0; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; +} + .line { background-color: $gray-lighten-20; height: 2;