Skip to content

Commit

Permalink
BoxControl: update design (#56665)
Browse files Browse the repository at this point in the history
  • Loading branch information
brookewp authored Jan 12, 2024
1 parent 3dba5c9 commit 9dcd4cc
Show file tree
Hide file tree
Showing 11 changed files with 481 additions and 497 deletions.
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
- `Tabs`: do not render hidden content ([#57046](https://github.com/WordPress/gutenberg/pull/57046)).
- `Tabs`: improve hover and text alignment styles ([#57275](https://github.com/WordPress/gutenberg/pull/57275)).
- `Tabs`: make sure `Tab`s are associated to the right `TabPanel`s, regardless of the order they're rendered in ([#57033](https://github.com/WordPress/gutenberg/pull/57033)).
- `BoxControl`: Update design ([#56665](https://github.com/WordPress/gutenberg/pull/56665)).

## 25.14.0 (2023-12-13)

Expand Down
88 changes: 54 additions & 34 deletions packages/components/src/box-control/all-input-control.tsx
Original file line number Diff line number Diff line change
@@ -1,86 +1,106 @@
/**
* WordPress dependencies
*/
import { useInstanceId } from '@wordpress/compose';
/**
* Internal dependencies
*/
import type { UnitControlProps } from '../unit-control/types';
import {
FlexedRangeControl,
StyledUnitControl,
} from './styles/box-control-styles';
import { HStack } from '../h-stack';
import type { BoxControlInputControlProps } from './types';
import UnitControl from './unit-control';
import { parseQuantityAndUnitFromRawValue } from '../unit-control';
import {
LABELS,
applyValueToSides,
getAllValue,
isValuesMixed,
isValuesDefined,
CUSTOM_VALUE_SETTINGS,
} from './utils';

const noop = () => {};

export default function AllInputControl( {
onChange = noop,
onFocus = noop,
onHoverOn = noop,
onHoverOff = noop,
values,
sides,
selectedUnits,
setSelectedUnits,
...props
}: BoxControlInputControlProps ) {
const inputId = useInstanceId( AllInputControl, 'box-control-input-all' );

const allValue = getAllValue( values, selectedUnits, sides );
const hasValues = isValuesDefined( values );
const isMixed = hasValues && isValuesMixed( values, selectedUnits, sides );
const allPlaceholder = isMixed ? LABELS.mixed : undefined;

const [ parsedQuantity, parsedUnit ] =
parseQuantityAndUnitFromRawValue( allValue );

const handleOnFocus: React.FocusEventHandler< HTMLInputElement > = (
event
) => {
onFocus( event, { side: 'all' } );
};

const handleOnChange: UnitControlProps[ 'onChange' ] = ( next ) => {
const onValueChange = ( next?: string ) => {
const isNumeric = next !== undefined && ! isNaN( parseFloat( next ) );
const nextValue = isNumeric ? next : undefined;
const nextValues = applyValueToSides( values, nextValue, sides );

onChange( nextValues );
};

const sliderOnChange = ( next?: number ) => {
onValueChange(
next !== undefined ? [ next, parsedUnit ].join( '' ) : undefined
);
};

// Set selected unit so it can be used as fallback by unlinked controls
// when individual sides do not have a value containing a unit.
const handleOnUnitChange: UnitControlProps[ 'onUnitChange' ] = ( unit ) => {
const newUnits = applyValueToSides( selectedUnits, unit, sides );
setSelectedUnits( newUnits );
};

const handleOnHoverOn = () => {
onHoverOn( {
top: true,
bottom: true,
left: true,
right: true,
} );
};

const handleOnHoverOff = () => {
onHoverOff( {
top: false,
bottom: false,
left: false,
right: false,
} );
};

return (
<UnitControl
{ ...props }
disableUnits={ isMixed }
isOnly
value={ allValue }
onChange={ handleOnChange }
onUnitChange={ handleOnUnitChange }
onFocus={ handleOnFocus }
onHoverOn={ handleOnHoverOn }
onHoverOff={ handleOnHoverOff }
placeholder={ allPlaceholder }
/>
<HStack>
<StyledUnitControl
{ ...props }
className="component-box-control__unit-control"
disableUnits={ isMixed }
id={ inputId }
isPressEnterToChange
value={ allValue }
onChange={ onValueChange }
onUnitChange={ handleOnUnitChange }
onFocus={ handleOnFocus }
placeholder={ allPlaceholder }
label={ LABELS.all }
hideLabelFromVision
/>

<FlexedRangeControl
__nextHasNoMarginBottom
aria-controls={ inputId }
label={ LABELS.all }
hideLabelFromVision
onChange={ sliderOnChange }
min={ 0 }
max={ CUSTOM_VALUE_SETTINGS[ parsedUnit ?? 'px' ]?.max ?? 10 }
step={
CUSTOM_VALUE_SETTINGS[ parsedUnit ?? 'px' ]?.step ?? 0.1
}
value={ parsedQuantity ?? 0 }
withInputField={ false }
/>
</HStack>
);
}
145 changes: 76 additions & 69 deletions packages/components/src/box-control/axial-input-controls.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
/**
* WordPress dependencies
*/
import { useInstanceId } from '@wordpress/compose';
/**
* Internal dependencies
*/
import { parseQuantityAndUnitFromRawValue } from '../unit-control/utils';
import UnitControl from './unit-control';
import { LABELS } from './utils';
import { Layout } from './styles/box-control-styles';
import Tooltip from '../tooltip';
import { CUSTOM_VALUE_SETTINGS, LABELS } from './utils';
import {
FlexedBoxControlIcon,
FlexedRangeControl,
InputWrapper,
StyledUnitControl,
} from './styles/box-control-styles';
import type { BoxControlInputControlProps } from './types';

const groupedSides = [ 'vertical', 'horizontal' ] as const;
Expand All @@ -13,14 +22,17 @@ type GroupedSide = ( typeof groupedSides )[ number ];
export default function AxialInputControls( {
onChange,
onFocus,
onHoverOn,
onHoverOff,
values,
selectedUnits,
setSelectedUnits,
sides,
...props
}: BoxControlInputControlProps ) {
const generatedId = useInstanceId(
AxialInputControls,
`box-control-input`
);

const createHandleOnFocus =
( side: GroupedSide ) =>
( event: React.FocusEvent< HTMLInputElement > ) => {
Expand All @@ -30,43 +42,7 @@ export default function AxialInputControls( {
onFocus( event, { side } );
};

const createHandleOnHoverOn = ( side: GroupedSide ) => () => {
if ( ! onHoverOn ) {
return;
}
if ( side === 'vertical' ) {
onHoverOn( {
top: true,
bottom: true,
} );
}
if ( side === 'horizontal' ) {
onHoverOn( {
left: true,
right: true,
} );
}
};

const createHandleOnHoverOff = ( side: GroupedSide ) => () => {
if ( ! onHoverOff ) {
return;
}
if ( side === 'vertical' ) {
onHoverOff( {
top: false,
bottom: false,
} );
}
if ( side === 'horizontal' ) {
onHoverOff( {
left: false,
right: false,
} );
}
};

const createHandleOnChange = ( side: GroupedSide ) => ( next?: string ) => {
const handleOnValueChange = ( side: GroupedSide, next?: string ) => {
if ( ! onChange ) {
return;
}
Expand Down Expand Up @@ -109,16 +85,8 @@ export default function AxialInputControls( {
? groupedSides.filter( ( side ) => sides.includes( side ) )
: groupedSides;

const first = filteredSides[ 0 ];
const last = filteredSides[ filteredSides.length - 1 ];
const only = first === last && first;

return (
<Layout
gap={ 0 }
align="top"
className="component-box-control__vertical-horizontal-input-controls"
>
<>
{ filteredSides.map( ( side ) => {
const [ parsedQuantity, parsedUnit ] =
parseQuantityAndUnitFromRawValue(
Expand All @@ -128,26 +96,65 @@ export default function AxialInputControls( {
side === 'vertical'
? selectedUnits.top
: selectedUnits.left;

const inputId = [ generatedId, side ].join( '-' );

return (
<UnitControl
{ ...props }
isFirst={ first === side }
isLast={ last === side }
isOnly={ only === side }
value={ [
parsedQuantity,
selectedUnit ?? parsedUnit,
].join( '' ) }
onChange={ createHandleOnChange( side ) }
onUnitChange={ createHandleOnUnitChange( side ) }
onFocus={ createHandleOnFocus( side ) }
onHoverOn={ createHandleOnHoverOn( side ) }
onHoverOff={ createHandleOnHoverOff( side ) }
label={ LABELS[ side ] }
key={ side }
/>
<InputWrapper key={ side }>
<FlexedBoxControlIcon side={ side } sides={ sides } />
<Tooltip placement="top-end" text={ LABELS[ side ] }>
<StyledUnitControl
{ ...props }
className="component-box-control__unit-control"
id={ inputId }
isPressEnterToChange
value={ [
parsedQuantity,
selectedUnit ?? parsedUnit,
].join( '' ) }
onChange={ ( newValue ) =>
handleOnValueChange( side, newValue )
}
onUnitChange={ createHandleOnUnitChange(
side
) }
onFocus={ createHandleOnFocus( side ) }
label={ LABELS[ side ] }
hideLabelFromVision
key={ side }
/>
</Tooltip>
<FlexedRangeControl
__nextHasNoMarginBottom
aria-controls={ inputId }
label={ LABELS[ side ] }
hideLabelFromVision
onChange={ ( newValue ) =>
handleOnValueChange(
side,
newValue !== undefined
? [
newValue,
selectedUnit ?? parsedUnit,
].join( '' )
: undefined
)
}
min={ 0 }
max={
CUSTOM_VALUE_SETTINGS[ selectedUnit ?? 'px' ]
?.max ?? 10
}
step={
CUSTOM_VALUE_SETTINGS[ selectedUnit ?? 'px' ]
?.step ?? 0.1
}
value={ parsedQuantity ?? 0 }
withInputField={ false }
/>
</InputWrapper>
);
} ) }
</Layout>
</>
);
}
Loading

0 comments on commit 9dcd4cc

Please sign in to comment.