diff --git a/packages/block-editor/src/components/border-radius-control/index.js b/packages/block-editor/src/components/border-radius-control/index.js index c995c126422fd1..5db1fde499833c 100644 --- a/packages/block-editor/src/components/border-radius-control/index.js +++ b/packages/block-editor/src/components/border-radius-control/index.js @@ -28,9 +28,9 @@ const DEFAULT_VALUES = { const RANGE_CONTROL_MAX_SIZE = 8; const EMPTY_ARRAY = []; function useBorderRadiusSizes( presets ) { - const defaultSizes = presets?.radiusSizes?.default ?? EMPTY_ARRAY; - const customSizes = presets?.radiusSizes?.custom ?? EMPTY_ARRAY; - const themeSizes = presets?.radiusSizes?.theme ?? EMPTY_ARRAY; + const defaultSizes = presets?.default ?? EMPTY_ARRAY; + const customSizes = presets?.custom ?? EMPTY_ARRAY; + const themeSizes = presets?.theme ?? EMPTY_ARRAY; return useMemo( () => { const sizes = [ @@ -109,6 +109,7 @@ export default function BorderRadiusControl( { onChange, values, presets } ) { values={ values } units={ units } corner="all" + presets={ options } /> ) : ( @@ -127,6 +128,7 @@ export default function BorderRadiusControl( { onChange, values, presets } ) { values={ values || DEFAULT_VALUES } units={ units } corner={ corner } + presets={ options } /> ) ) } diff --git a/packages/block-editor/src/components/border-radius-control/single-input-control.js b/packages/block-editor/src/components/border-radius-control/single-input-control.js index 224bee46feb696..9ae15957f05604 100644 --- a/packages/block-editor/src/components/border-radius-control/single-input-control.js +++ b/packages/block-editor/src/components/border-radius-control/single-input-control.js @@ -4,15 +4,24 @@ import { __experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue, __experimentalUnitControl as UnitControl, + __experimentalHStack as HStack, Tooltip, RangeControl, + Button, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; +import { useState } from '@wordpress/element'; +import { settings } from '@wordpress/icons'; /** * Internal dependencies */ -import { getAllValue } from './utils'; +import { + getAllValue, + getPresetValueFromControlValue, + getSliderValueFromPreset, + isValuePreset, +} from './utils'; const CORNERS = { all: __( 'Border radius' ), @@ -27,6 +36,7 @@ const MAX_BORDER_RADIUS_VALUES = { em: 20, rem: 20, }; +const RANGE_CONTROL_MAX_SIZE = 8; export default function SingleInputControl( { corner, @@ -35,6 +45,7 @@ export default function SingleInputControl( { setSelectedUnits, values: valuesProp, units, + presets, } ) { const onChangeValue = ( next ) => { if ( ! onChange ) { @@ -71,6 +82,23 @@ export default function SingleInputControl( { } setSelectedUnits( newUnits ); }; + const handleSliderChange = ( next ) => { + const val = + next !== undefined ? `${ next }${ computedUnit }` : undefined; + if ( corner === 'all' ) { + onChange( { + topLeft: val, + topRight: val, + bottomLeft: val, + bottomRight: val, + } ); + } else { + onChange( { + ...values, + [ corner ]: val, + } ); + } + }; // For shorthand style & backwards compatibility, handle flat string value. const values = @@ -92,57 +120,114 @@ export default function SingleInputControl( { const unitConfig = units && units.find( ( item ) => item.value === computedUnit ); const step = unitConfig?.step || 1; - const handleSliderChange = ( next ) => { - const val = - next !== undefined ? `${ next }${ computedUnit }` : undefined; - if ( corner === 'all' ) { - onChange( { - topLeft: val, - topRight: val, - bottomLeft: val, - bottomRight: val, - } ); - } else { - onChange( { - ...values, - [ corner ]: val, - } ); - } - }; + const [ showCustomValueControl, setShowCustomValueControl ] = useState( + value !== undefined && ! isValuePreset( value ) + ); + const showRangeControl = presets.length <= RANGE_CONTROL_MAX_SIZE; + const presetValue = getSliderValueFromPreset( value, presets ); + const rangeTooltip = ( newValue ) => + value === undefined ? undefined : presets[ newValue ]?.name; + const marks = presets + .slice( 1, presets.length - 1 ) + .map( ( _newValue, index ) => ( { + value: index + 1, + label: undefined, + } ) ); + const hasPresets = marks.length > 0; // Controls are wrapped in tooltips as visible labels aren't desired here. // Tooltip rendering also requires the UnitControl to be wrapped. See: // https://github.com/WordPress/gutenberg/pull/24966#issuecomment-685875026 return ( -
- -
- -
-
- + { ! hasPresets || + ( showCustomValueControl && ( +
+ +
+ +
+
+ +
+ ) ) } + { hasPresets && showRangeControl && ! showCustomValueControl && ( + + onChangeValue( + getPresetValueFromControlValue( + newSize, + 'range', + presets + ) + ) + } + /**onMouseDown={ ( event ) => { + // If mouse down is near start of range set initial value to 0, which + // prevents the user have to drag right then left to get 0 setting. + if ( event?.nativeEvent?.offsetX < 35 ) { + setInitialValue(); + } + } }**/ + withInputField={ false } + aria-valuenow={ presetValue } + aria-valuetext={ presets[ presetValue ]?.name } + renderTooltipContent={ rangeTooltip } + min={ 0 } + max={ presets.length - 1 } + marks={ marks } + label={ CORNERS[ corner ] } + hideLabelFromVision + __nextHasNoMarginBottom + /*onFocus={ onMouseOver } + onBlur={ onMouseOut }*/ + /> + ) } +
+ ); } diff --git a/packages/block-editor/src/components/border-radius-control/style.scss b/packages/block-editor/src/components/border-radius-control/style.scss index 64da74263b0429..e3e36732ac7855 100644 --- a/packages/block-editor/src/components/border-radius-control/style.scss +++ b/packages/block-editor/src/components/border-radius-control/style.scss @@ -43,3 +43,7 @@ } } } + +.component-border-radius-control__custom-toggle { + flex: 0 0 auto; +} \ No newline at end of file diff --git a/packages/block-editor/src/components/border-radius-control/utils.js b/packages/block-editor/src/components/border-radius-control/utils.js index 0738ef80399eb6..f16d6cc18b7770 100644 --- a/packages/block-editor/src/components/border-radius-control/utils.js +++ b/packages/block-editor/src/components/border-radius-control/utils.js @@ -117,3 +117,91 @@ export function hasDefinedValues( values ) { return !! filteredValues.length; } + +/** + * Checks is given value is a spacing preset. + * + * @param {string} value Value to check + * + * @return {boolean} Return true if value is string in format var:preset|spacing|. + */ +export function isValuePreset( value ) { + if ( ! value?.includes ) { + return false; + } + return value === '0' || value.includes( 'var:preset|border-radius|' ); +} + +/** + * Returns the slug section of the given preset string. + * + * @param {string} value Value to extract slug from. + * + * @return {string|undefined} The int value of the slug from given preset. + */ +export function getPresetSlug( value ) { + if ( ! value ) { + return; + } + + if ( value === '0' || value === 'default' ) { + return value; + } + + const slug = value.match( /var:preset\|border-radius\|(.+)/ ); + + return slug ? slug[ 1 ] : undefined; +} + +/** + * Converts spacing preset value into a Range component value . + * + * @param {string} presetValue Value to convert to Range value. + * @param {Array} presets Array of current radius preset value objects. + * + * @return {number} The int value for use in Range control. + */ +export function getSliderValueFromPreset( presetValue, presets ) { + if ( presetValue === undefined ) { + return 0; + } + const slug = + parseFloat( presetValue, 10 ) === 0 + ? '0' + : getPresetSlug( presetValue ); + const sliderValue = presets.findIndex( ( size ) => { + return String( size.slug ) === slug; + } ); + + // Returning NaN rather than undefined as undefined makes range control thumb sit in center + return sliderValue !== -1 ? sliderValue : NaN; +} + +/** + * Converts a control value into a preset value. + * + * @param {number} controlValue to convert to preset value. + * @param {string} controlType Type of control + * @param {Array} presets Array of current radius preset value objects. + * + * @return {string} The custom value for use in Range control. + */ +export function getPresetValueFromControlValue( + controlValue, + controlType, + presets +) { + const size = parseInt( controlValue, 10 ); + + if ( controlType === 'selectList' ) { + if ( size === 0 ) { + return undefined; + } + if ( size === 1 ) { + return '0'; + } + } else if ( size === 0 ) { + return '0'; + } + return `var:preset|border-radius|${ presets[ controlValue ]?.slug }`; +}