diff --git a/packages/components/src/box-control/all-input-control.js b/packages/components/src/box-control/all-input-control.js index 1f1260898505d1..ec6822f283fa50 100644 --- a/packages/components/src/box-control/all-input-control.js +++ b/packages/components/src/box-control/all-input-control.js @@ -14,6 +14,7 @@ export default function AllInputControl( { onHoverOn = noop, onHoverOff = noop, values, + sides, ...props } ) { const allValue = getAllValue( values ); @@ -28,11 +29,11 @@ export default function AllInputControl( { const handleOnChange = ( next ) => { const nextValues = { ...values }; + const selectedSides = sides?.length + ? sides + : [ 'top', 'right', 'bottom', 'left' ]; - nextValues.top = next; - nextValues.bottom = next; - nextValues.left = next; - nextValues.right = next; + selectedSides.forEach( ( side ) => ( nextValues[ side ] = next ) ); onChange( nextValues ); }; diff --git a/packages/components/src/box-control/icon.js b/packages/components/src/box-control/icon.js index 15249c01e4db13..f60375f627eb5e 100644 --- a/packages/components/src/box-control/icon.js +++ b/packages/components/src/box-control/icon.js @@ -15,12 +15,24 @@ const BASE_ICON_SIZE = 24; export default function BoxControlIcon( { size = 24, side = 'all', + sides, ...props } ) { - const top = getSide( side, 'top' ); - const right = getSide( side, 'right' ); - const bottom = getSide( side, 'bottom' ); - const left = getSide( side, 'left' ); + const isSideDisabled = ( value ) => + sides?.length && ! sides.includes( value ); + + const getSide = ( value ) => { + if ( isSideDisabled( value ) ) { + return false; + } + + return side === 'all' || side === value; + }; + + const top = getSide( 'top' ); + const right = getSide( 'right' ); + const bottom = getSide( 'bottom' ); + const left = getSide( 'left' ); // Simulates SVG Icon scaling const scale = size / BASE_ICON_SIZE; @@ -36,7 +48,3 @@ export default function BoxControlIcon( { ); } - -function getSide( side, value ) { - return side === 'all' || side === value; -} diff --git a/packages/components/src/box-control/index.js b/packages/components/src/box-control/index.js index 187e8f10214011..9421792b564717 100644 --- a/packages/components/src/box-control/index.js +++ b/packages/components/src/box-control/index.js @@ -51,16 +51,19 @@ export default function BoxControl( { label = __( 'Box Control' ), values: valuesProp, units, + sides, + resetValues = DEFAULT_VALUES, } ) { const [ values, setValues ] = useControlledState( valuesProp, { fallback: DEFAULT_VALUES, } ); const inputValues = values || DEFAULT_VALUES; const hasInitialValue = isValuesDefined( valuesProp ); + const hasOneSide = sides?.length === 1; const [ isDirty, setIsDirty ] = useState( hasInitialValue ); const [ isLinked, setIsLinked ] = useState( - ! hasInitialValue || ! isValuesMixed( inputValues ) + ! hasInitialValue || ! isValuesMixed( inputValues ) || hasOneSide ); const [ side, setSide ] = useState( isLinked ? 'all' : 'top' ); @@ -92,10 +95,8 @@ export default function BoxControl( { }; const handleOnReset = () => { - const initialValues = DEFAULT_VALUES; - - onChange( initialValues ); - setValues( initialValues ); + onChange( resetValues ); + setValues( resetValues ); setIsDirty( false ); }; @@ -107,6 +108,7 @@ export default function BoxControl( { onHoverOff: handleOnHoverOff, isLinked, units, + sides, values: inputValues, }; @@ -135,7 +137,7 @@ export default function BoxControl( { - + { isLinked && ( @@ -145,12 +147,14 @@ export default function BoxControl( { /> ) } - - - + { ! hasOneSide && ( + + + + ) } { ! isLinked && } diff --git a/packages/components/src/box-control/input-controls.js b/packages/components/src/box-control/input-controls.js index 0177052151273f..036f7054a5669d 100644 --- a/packages/components/src/box-control/input-controls.js +++ b/packages/components/src/box-control/input-controls.js @@ -10,12 +10,15 @@ import UnitControl from './unit-control'; import { LABELS } from './utils'; import { LayoutContainer, Layout } from './styles/box-control-styles'; +const allSides = [ 'top', 'right', 'bottom', 'left' ]; + export default function BoxInputControls( { onChange = noop, onFocus = noop, onHoverOn = noop, onHoverOff = noop, values, + sides, ...props } ) { const createHandleOnFocus = ( side ) => ( event ) => { @@ -34,8 +37,6 @@ export default function BoxInputControls( { onChange( nextValues ); }; - const { top, right, bottom, left } = values; - const createHandleOnChange = ( side ) => ( next, { event } ) => { const { altKey } = event; const nextValues = { ...values }; @@ -66,6 +67,15 @@ export default function BoxInputControls( { handleOnChange( nextValues ); }; + // Filter sides if custom configuration provided, maintaining default order. + const filteredSides = sides?.length + ? allSides.filter( ( side ) => sides.includes( side ) ) + : allSides; + + const first = filteredSides[ 0 ]; + const last = filteredSides[ filteredSides.length - 1 ]; + const only = first === last && first; + return ( - - - - + { filteredSides.map( ( side ) => ( + + ) ) } ); diff --git a/packages/components/src/box-control/styles/box-control-styles.js b/packages/components/src/box-control/styles/box-control-styles.js index 78cf6ceb9a6968..7d42aa42dcb186 100644 --- a/packages/components/src/box-control/styles/box-control-styles.js +++ b/packages/components/src/box-control/styles/box-control-styles.js @@ -40,6 +40,7 @@ export const Layout = styled( Flex )` position: relative; height: 100%; width: 100%; + justify-content: flex-start; `; const unitControlBorderRadiusStyles = ( { isFirst, isLast, isOnly } ) => { diff --git a/packages/components/src/input-control/input-field.js b/packages/components/src/input-control/input-field.js index 18044ee455ac9c..5931c789f651b9 100644 --- a/packages/components/src/input-control/input-field.js +++ b/packages/components/src/input-control/input-field.js @@ -71,7 +71,7 @@ function InputField( const dragCursor = useDragCursor( isDragging, dragDirection ); /* - * Handles syncronization of external and internal value state. + * Handles synchronization of external and internal value state. * If not focused and did not hold a dirty value[1] on blur * updates the value from the props. Otherwise if not holding * a dirty value[1] propagates the value and event through onChange. @@ -155,6 +155,9 @@ function InputField( const dragGestureProps = useDrag( ( dragProps ) => { const { distance, dragging, event } = dragProps; + // The event is persisted to prevent errors in components using this + // to check if a modifier key was held while dragging. + event.persist(); if ( ! distance ) return; event.stopPropagation();