Skip to content

Commit

Permalink
Allow picking presets
Browse files Browse the repository at this point in the history
  • Loading branch information
youknowriad committed Dec 3, 2024
1 parent e0b4e47 commit addbac0
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down Expand Up @@ -109,6 +109,7 @@ export default function BorderRadiusControl( { onChange, values, presets } ) {
values={ values }
units={ units }
corner="all"
presets={ options }
/>
</>
) : (
Expand All @@ -127,6 +128,7 @@ export default function BorderRadiusControl( { onChange, values, presets } ) {
values={ values || DEFAULT_VALUES }
units={ units }
corner={ corner }
presets={ options }
/>
) ) }
</VStack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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' ),
Expand All @@ -27,6 +36,7 @@ const MAX_BORDER_RADIUS_VALUES = {
em: 20,
rem: 20,
};
const RANGE_CONTROL_MAX_SIZE = 8;

export default function SingleInputControl( {
corner,
Expand All @@ -35,6 +45,7 @@ export default function SingleInputControl( {
setSelectedUnits,
values: valuesProp,
units,
presets,
} ) {
const onChangeValue = ( next ) => {
if ( ! onChange ) {
Expand Down Expand Up @@ -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 =
Expand All @@ -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 (
<div className="components-border-radius-control__input-controls-wrapper">
<Tooltip text={ CORNERS[ corner ] } placement="top">
<div className="components-border-radius-control__tooltip-wrapper">
<UnitControl
className="components-border-radius-control__unit-control"
aria-label={ CORNERS[ corner ] }
value={ [ parsedQuantity, computedUnit ].join( '' ) }
onChange={ onChangeValue }
onUnitChange={ onChangeUnit }
size="__unstable-large"
min={ MIN_BORDER_RADIUS_VALUE }
units={ units }
/>
</div>
</Tooltip>
<RangeControl
__next40pxDefaultSize
label={ __( 'Border radius' ) }
hideLabelFromVision
className="components-border-radius-control__range-control"
value={ parsedQuantity ?? '' }
min={ MIN_BORDER_RADIUS_VALUE }
max={ MAX_BORDER_RADIUS_VALUES[ computedUnit ] }
initialPosition={ 0 }
withInputField={ false }
onChange={ handleSliderChange }
step={ step }
__nextHasNoMarginBottom
<HStack>
{ ! hasPresets ||
( showCustomValueControl && (
<div className="components-border-radius-control__input-controls-wrapper">
<Tooltip text={ CORNERS[ corner ] } placement="top">
<div className="components-border-radius-control__tooltip-wrapper">
<UnitControl
className="components-border-radius-control__unit-control"
aria-label={ CORNERS[ corner ] }
value={ [
parsedQuantity,
computedUnit,
].join( '' ) }
onChange={ onChangeValue }
onUnitChange={ onChangeUnit }
size="__unstable-large"
min={ MIN_BORDER_RADIUS_VALUE }
units={ units }
/>
</div>
</Tooltip>
<RangeControl
__next40pxDefaultSize
label={ __( 'Border radius' ) }
hideLabelFromVision
className="components-border-radius-control__range-control"
value={ parsedQuantity ?? '' }
min={ MIN_BORDER_RADIUS_VALUE }
max={ MAX_BORDER_RADIUS_VALUES[ computedUnit ] }
initialPosition={ 0 }
withInputField={ false }
onChange={ handleSliderChange }
step={ step }
__nextHasNoMarginBottom
/>
</div>
) ) }
{ hasPresets && showRangeControl && ! showCustomValueControl && (
<RangeControl
__next40pxDefaultSize
//onMouseOver={ onMouseOver }
//onMouseOut={ onMouseOut }
className="spacing-sizes-control__range-control"
value={ presetValue }
onChange={ ( newSize ) =>
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 }*/
/>
) }
<Button
label={
showCustomValueControl
? __( 'Use border radius preset' )
: __( 'Set custom border radius' )
}
icon={ settings }
onClick={ () => {
setShowCustomValueControl( ! showCustomValueControl );
} }
isPressed={ showCustomValueControl }
size="small"
className="components-border-radius-control__custom-toggle"
iconSize={ 24 }
/>
</div>
</HStack>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@
}
}
}

.component-border-radius-control__custom-toggle {
flex: 0 0 auto;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 }`;
}

0 comments on commit addbac0

Please sign in to comment.