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();