From 8360e3a5f7d40877bc211b9b0577143cdc03b928 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Fri, 6 Dec 2024 12:04:04 +0100 Subject: [PATCH 1/7] BoxControl: Add support for presets --- packages/components/src/box-control/README.md | 15 ++ packages/components/src/box-control/index.tsx | 4 + .../src/box-control/input-control.tsx | 183 ++++++++++++++---- .../src/box-control/stories/index.story.tsx | 12 ++ packages/components/src/box-control/types.ts | 18 ++ packages/components/src/box-control/utils.ts | 57 ++++++ 6 files changed, 248 insertions(+), 41 deletions(-) diff --git a/packages/components/src/box-control/README.md b/packages/components/src/box-control/README.md index 8bcb5a5dad8fc..78b4280ffe36e 100644 --- a/packages/components/src/box-control/README.md +++ b/packages/components/src/box-control/README.md @@ -124,3 +124,18 @@ The current values of the control, expressed as an object of `top`, `right`, `bo - Type: `BoxControlValue` - Required: No + +### `presets` + +The list of presets to pick from. + + - Type: `Preset` + - Required: No + +### `presetKey` + +The key of the preset to apply. If you provide a list of presets, you must provide a preset key to use. The format of preset selected values is going to be `var:preset|${ presetKey }|${ presetSlug }` + + - Type: `string` + - Required: No + diff --git a/packages/components/src/box-control/index.tsx b/packages/components/src/box-control/index.tsx index 279dfa55eafe3..d4d4b03f89303 100644 --- a/packages/components/src/box-control/index.tsx +++ b/packages/components/src/box-control/index.tsx @@ -83,6 +83,8 @@ function BoxControl( { splitOnAxis = false, allowReset = true, resetValues = DEFAULT_VALUES, + presets, + presetKey, onMouseOver, onMouseOut, }: BoxControlProps ) { @@ -153,6 +155,8 @@ function BoxControl( { sides, values: inputValues, __next40pxDefaultSize, + presets, + presetKey, }; maybeWarnDeprecated36pxSize( { diff --git a/packages/components/src/box-control/input-control.tsx b/packages/components/src/box-control/input-control.tsx index 2e1765f518a57..b9e26b90bb894 100644 --- a/packages/components/src/box-control/input-control.tsx +++ b/packages/components/src/box-control/input-control.tsx @@ -3,6 +3,8 @@ */ import { useInstanceId } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; +import { useState } from '@wordpress/element'; +import { settings } from '@wordpress/icons'; /** * Internal dependencies @@ -11,10 +13,13 @@ import Tooltip from '../tooltip'; import { parseQuantityAndUnitFromRawValue } from '../unit-control/utils'; import { CUSTOM_VALUE_SETTINGS, - getAllowedSides, getMergedValue, - isValueMixed, + getAllowedSides, + getPresetIndexFromValue, + getPresetValueFromIndex, + isValuePreset, isValuesDefined, + isValueMixed, LABELS, } from './utils'; import { @@ -24,6 +29,7 @@ import { StyledUnitControl, } from './styles/box-control-styles'; import type { BoxControlInputControlProps, BoxControlValue } from './types'; +import Button from '../button'; const noop = () => {}; @@ -79,6 +85,8 @@ export default function BoxInputControl( { sides, side, min = 0, + presets, + presetKey, ...props }: BoxControlInputControlProps ) { const defaultValuesToModify = getSidesToModify( side, sides ); @@ -91,6 +99,15 @@ export default function BoxInputControl( { onChange( nextValues ); }; + const handleRewOnValueChange = ( next?: string ) => { + const nextValues = { ...values }; + defaultValuesToModify.forEach( ( modifiedSide ) => { + nextValues[ modifiedSide ] = next; + } ); + + handleOnChange( nextValues ); + }; + const handleOnValueChange = ( next?: string, extra?: { event: React.SyntheticEvent< Element, Event > } @@ -148,52 +165,136 @@ export default function BoxInputControl( { const usedValue = mergedValue === undefined && computedUnit ? computedUnit : mergedValue; const mixedPlaceholder = isMixed || isMixedUnit ? __( 'Mixed' ) : undefined; + const hasPresets = presets && presets.length > 0 && presetKey; + const hasPresetValue = + hasPresets && + mergedValue !== undefined && + ! isMixed && + isValuePreset( mergedValue, presetKey ); + const [ showCustomValueControl, setShowCustomValueControl ] = useState( + ! hasPresets || + ( ! hasPresetValue && ! isMixed && mergedValue !== undefined ) + ); + const showRangeControl = true; + const presetIndex = hasPresetValue + ? getPresetIndexFromValue( mergedValue, presetKey, presets ) + : undefined; + const marks = hasPresets + ? [ { value: 0, label: __( 'None' ) } ].concat( + presets.map( ( preset, index ) => ( { + value: index + 1, + label: preset.name, + } ) ) + ) + : []; return ( - - + + + + + { + handleOnValueChange( + newValue !== undefined + ? [ newValue, computedUnit ].join( '' ) + : undefined + ); + } } + min={ isFinite( min ) ? min : 0 } + max={ + CUSTOM_VALUE_SETTINGS[ computedUnit ?? 'px' ] + ?.max ?? 10 + } + step={ + CUSTOM_VALUE_SETTINGS[ computedUnit ?? 'px' ] + ?.step ?? 0.1 + } + value={ parsedQuantity ?? 0 } + withInputField={ false } + /> + + ) } + + { hasPresets && ! showCustomValueControl && showRangeControl && ( + { + const newValue = + newIndex === 0 || newIndex === undefined + ? undefined + : getPresetValueFromIndex( + newIndex - 1, + presetKey, + presets + ); + handleRewOnValueChange( newValue ); + } } + withInputField={ false } + aria-valuenow={ + presetIndex !== undefined ? presetIndex + 1 : 0 + } + aria-valuetext={ + marks[ presetIndex !== undefined ? presetIndex + 1 : 0 ] + .label + } + renderTooltipContent={ ( index ) => + marks[ ! index ? 0 : index ].label + } + min={ 0 } + max={ marks.length - 1 } + marks={ marks } label={ LABELS[ side ] } - placeholder={ mixedPlaceholder } hideLabelFromVision + __nextHasNoMarginBottom + /> + ) } + + { hasPresets && ( +