diff --git a/packages/block-editor/src/components/border-radius-control/all-input-control.js b/packages/block-editor/src/components/border-radius-control/all-input-control.js new file mode 100644 index 00000000000000..00073ba297c666 --- /dev/null +++ b/packages/block-editor/src/components/border-radius-control/all-input-control.js @@ -0,0 +1,29 @@ +/** + * WordPress dependencies + */ +import { __experimentalUnitControl as UnitControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import { getAllValue, hasMixedValues, hasDefinedValues } from './utils'; + +export default function AllInputControl( { onChange, values, ...props } ) { + const allValue = getAllValue( values ); + const hasValues = hasDefinedValues( values ); + const isMixed = hasValues && hasMixedValues( values ); + const allPlaceholder = isMixed ? __( 'Mixed' ) : null; + + return ( + + ); +} diff --git a/packages/block-editor/src/components/border-radius-control/index.js b/packages/block-editor/src/components/border-radius-control/index.js new file mode 100644 index 00000000000000..7d5233d5cabe6e --- /dev/null +++ b/packages/block-editor/src/components/border-radius-control/index.js @@ -0,0 +1,102 @@ +/** + * WordPress dependencies + */ +import { + RangeControl, + __experimentalParseUnit as parseUnit, + __experimentalUseCustomUnits as useCustomUnits, +} from '@wordpress/components'; +import { useState } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import AllInputControl from './all-input-control'; +import InputControls from './input-controls'; +import LinkedButton from './linked-button'; +import { + getAllValue, + getAllUnit, + hasDefinedValues, + hasMixedValues, +} from './utils'; + +const DEFAULT_VALUES = { + topLeft: null, + topRight: null, + bottomLeft: null, + bottomRight: null, +}; +const MIN_BORDER_RADIUS_VALUE = 0; +const MAX_BORDER_RADIUS_VALUES = { + px: 100, + em: 20, + rem: 20, +}; + +/** + * Control to display border radius options. + * + * @param {Object} props Component props. + * @param {Function} props.onChange Callback to handle onChange. + * @param {Object} props.values Border radius values. + * + * @return {WPElement} Custom border radius control. + */ +export default function BorderRadiusControl( { onChange, values } ) { + const [ isLinked, setIsLinked ] = useState( + ! hasDefinedValues( values ) || ! hasMixedValues( values ) + ); + + const units = useCustomUnits( { availableUnits: [ 'px', 'em', 'rem' ] } ); + const unit = getAllUnit( values ); + const unitConfig = units.find( ( item ) => item.value === unit ); + const step = unitConfig?.step || 1; + + const [ allValue ] = parseUnit( getAllValue( values ) ); + + const toggleLinked = () => setIsLinked( ! isLinked ); + + const handleSliderChange = ( next ) => { + onChange( next !== undefined ? `${ next }${ unit }` : undefined ); + }; + + return ( +
+ { __( 'Radius' ) } +
+ { isLinked ? ( + <> + + + + ) : ( + + ) } + +
+
+ ); +} diff --git a/packages/block-editor/src/components/border-radius-control/input-controls.js b/packages/block-editor/src/components/border-radius-control/input-controls.js new file mode 100644 index 00000000000000..db294c7f8bd1b6 --- /dev/null +++ b/packages/block-editor/src/components/border-radius-control/input-controls.js @@ -0,0 +1,55 @@ +/** + * WordPress dependencies + */ +import { __experimentalUnitControl as UnitControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +const CORNERS = { + topLeft: __( 'Top left' ), + topRight: __( 'Top right' ), + bottomLeft: __( 'Bottom left' ), + bottomRight: __( 'Bottom right' ), +}; + +export default function BoxInputControls( { + onChange, + values: valuesProp, + ...props +} ) { + const createHandleOnChange = ( corner ) => ( next ) => { + if ( ! onChange ) { + return; + } + + onChange( { + ...values, + [ corner ]: next ? next : undefined, + } ); + }; + + // For shorthand style & backwards compatibility, handle flat string value. + const values = + typeof valuesProp !== 'string' + ? valuesProp + : { + topLeft: valuesProp, + topRight: valuesProp, + bottomLeft: valuesProp, + bottomRight: valuesProp, + }; + + // Controls are wrapped in tooltips as visible labels aren't desired here. + return ( +
+ { Object.entries( CORNERS ).map( ( [ key, label ] ) => ( + + ) ) } +
+ ); +} diff --git a/packages/block-editor/src/components/border-radius-control/linked-button.js b/packages/block-editor/src/components/border-radius-control/linked-button.js new file mode 100644 index 00000000000000..58fec1012b0651 --- /dev/null +++ b/packages/block-editor/src/components/border-radius-control/linked-button.js @@ -0,0 +1,25 @@ +/** + * WordPress dependencies + */ +import { Button, Tooltip } from '@wordpress/components'; +import { link, linkOff } from '@wordpress/icons'; +import { __ } from '@wordpress/i18n'; + +export default function LinkedButton( { isLinked, ...props } ) { + const label = isLinked ? __( 'Unlink Radii' ) : __( 'Link Radii' ); + + return ( + +