Skip to content

Commit

Permalink
Prevent CSS unit only values
Browse files Browse the repository at this point in the history
This also maintains CSS unit selections between the "all" control and the unlinked controls.
  • Loading branch information
aaronrobertshaw committed Jul 16, 2021
1 parent 17898a2 commit 950d59f
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 42 deletions.
59 changes: 45 additions & 14 deletions packages/components/src/box-control/all-input-control.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ import { noop } from 'lodash';
* Internal dependencies
*/
import UnitControl from './unit-control';
import { LABELS, getAllValue, isValuesMixed, isValuesDefined } from './utils';
import {
ALL_SIDES,
LABELS,
getAllValue,
getAllUnitFallback,
isValuesMixed,
isValuesDefined,
} from './utils';

export default function AllInputControl( {
onChange = noop,
Expand All @@ -15,42 +22,64 @@ export default function AllInputControl( {
onHoverOff = noop,
values,
sides,
selectedUnits,
setSelectedUnits,
...props
} ) {
const allValue = getAllValue( values );
const allValue = getAllValue( values, sides );
const hasValues = isValuesDefined( values );
const isMixed = hasValues && isValuesMixed( values );

const isMixed = hasValues && isValuesMixed( values, sides );
const allPlaceholder = isMixed ? LABELS.mixed : null;

// Set meaningful unit selection if no allValue and user has previously
// selected units without assigning values while controls were unlinked.
const allUnitFallback = ! allValue
? getAllUnitFallback( selectedUnits )
: undefined;

const handleOnFocus = ( event ) => {
onFocus( event, { side: 'all' } );
};

const handleOnChange = ( next ) => {
const nextValues = { ...values };
// Applies a value to an object representing top, right, bottom and left
// sides while taking into account any custom side configuration.
const applyValueToSides = ( currentValues, newValue ) => {
const newValues = { ...currentValues };

if ( sides?.length ) {
sides.forEach( ( side ) => {
if ( side === 'vertical' ) {
nextValues.top = next;
nextValues.bottom = next;
newValues.top = newValue;
newValues.bottom = newValue;
} else if ( side === 'horizontal' ) {
nextValues.left = next;
nextValues.right = next;
newValues.left = newValue;
newValues.right = newValue;
} else {
nextValues[ side ] = next;
newValues[ side ] = newValue;
}
} );
} else {
[ 'top', 'right', 'bottom', 'left' ].forEach(
( side ) => ( nextValues[ side ] = next )
);
ALL_SIDES.forEach( ( side ) => ( newValues[ side ] = newValue ) );
}

return newValues;
};

const handleOnChange = ( next ) => {
const isNumeric = ! isNaN( parseFloat( next ) );
const nextValue = isNumeric ? next : undefined;
const nextValues = applyValueToSides( values, nextValue );

onChange( nextValues );
};

// 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 = ( unit ) => {
const newUnits = applyValueToSides( selectedUnits, unit );
setSelectedUnits( newUnits );
};

const handleOnHoverOn = () => {
onHoverOn( {
top: true,
Expand All @@ -75,7 +104,9 @@ export default function AllInputControl( {
disableUnits={ isMixed }
isOnly
value={ allValue }
unit={ allUnitFallback }
onChange={ handleOnChange }
onUnitChange={ handleOnUnitChange }
onFocus={ handleOnFocus }
onHoverOn={ handleOnHoverOn }
onHoverOff={ handleOnHoverOff }
Expand Down
37 changes: 32 additions & 5 deletions packages/components/src/box-control/axial-input-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export default function AxialInputControls( {
onHoverOn,
onHoverOff,
values,
selectedUnits,
setSelectedUnits,
sides,
...props
} ) {
Expand Down Expand Up @@ -64,19 +66,38 @@ export default function AxialInputControls( {
return;
}
const nextValues = { ...values };
const isNumeric = ! isNaN( parseFloat( next ) );
const nextValue = isNumeric ? next : undefined;

if ( side === 'vertical' ) {
nextValues.top = next;
nextValues.bottom = next;
nextValues.top = nextValue;
nextValues.bottom = nextValue;
}

if ( side === 'horizontal' ) {
nextValues.left = next;
nextValues.right = next;
nextValues.left = nextValue;
nextValues.right = nextValue;
}

onChange( nextValues );
};

const createHandleOnUnitChange = ( side ) => ( next ) => {
const newUnits = { ...selectedUnits };

if ( side === 'vertical' ) {
newUnits.top = next;
newUnits.bottom = next;
}

if ( side === 'horizontal' ) {
newUnits.left = next;
newUnits.right = next;
}

setSelectedUnits( newUnits );
};

// Filter sides if custom configuration provided, maintaining default order.
const filteredSides = sides?.length
? groupedSides.filter( ( side ) => sides.includes( side ) )
Expand All @@ -98,8 +119,14 @@ export default function AxialInputControls( {
isFirst={ first === side }
isLast={ last === side }
isOnly={ only === side }
value={ 'vertical' === side ? values.top : values.left }
value={ side === 'vertical' ? values.top : values.left }
unit={
side === 'vertical'
? selectedUnits.top
: selectedUnits.left
}
onChange={ createHandleOnChange( side ) }
onUnitChange={ createHandleOnUnitChange( side ) }
onFocus={ createHandleOnFocus( side ) }
onHoverOn={ createHandleOnHoverOn( side ) }
onHoverOff={ createHandleOnHoverOff( side ) }
Expand Down
14 changes: 14 additions & 0 deletions packages/components/src/box-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
Header,
HeaderControlWrapper,
} from './styles/box-control-styles';
import { parseUnit } from '../unit-control/utils';
import {
DEFAULT_VALUES,
DEFAULT_VISUALIZER_VALUES,
Expand Down Expand Up @@ -74,6 +75,16 @@ export default function BoxControl( {
getInitialSide( isLinked, splitOnAxis )
);

// Tracking selected units via internal state allows filtering of CSS unit
// only values from being saved while maintaining preexisting unit selection
// behaviour. Filtering CSS only values prevents invalid style values.
const [ selectedUnits, setSelectedUnits ] = useState( {
top: parseUnit( valuesProp?.top )[ 1 ],
right: parseUnit( valuesProp?.right )[ 1 ],
bottom: parseUnit( valuesProp?.bottom )[ 1 ],
left: parseUnit( valuesProp?.left )[ 1 ],
} );

const id = useUniqueId( idProp );
const headingId = `${ id }-heading`;

Expand Down Expand Up @@ -103,6 +114,7 @@ export default function BoxControl( {
const handleOnReset = () => {
onChange( resetValues );
setValues( resetValues );
setSelectedUnits( resetValues );
setIsDirty( false );
};

Expand All @@ -114,6 +126,8 @@ export default function BoxControl( {
onHoverOff: handleOnHoverOff,
isLinked,
units,
selectedUnits,
setSelectedUnits,
sides,
values: inputValues,
};
Expand Down
32 changes: 22 additions & 10 deletions packages/components/src/box-control/input-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import { noop } from 'lodash';
* Internal dependencies
*/
import UnitControl from './unit-control';
import { LABELS } from './utils';
import { ALL_SIDES, 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,
selectedUnits,
setSelectedUnits,
sides,
...props
} ) {
Expand All @@ -40,8 +40,10 @@ export default function BoxInputControls( {
const createHandleOnChange = ( side ) => ( next, { event } ) => {
const { altKey } = event;
const nextValues = { ...values };
const isNumeric = ! isNaN( parseFloat( next ) );
const nextValue = isNumeric ? next : undefined;

nextValues[ side ] = next;
nextValues[ side ] = nextValue;

/**
* Supports changing pair sides. For example, holding the ALT key
Expand All @@ -50,27 +52,33 @@ export default function BoxInputControls( {
if ( altKey ) {
switch ( side ) {
case 'top':
nextValues.bottom = next;
nextValues.bottom = nextValue;
break;
case 'bottom':
nextValues.top = next;
nextValues.top = nextValue;
break;
case 'left':
nextValues.right = next;
nextValues.right = nextValue;
break;
case 'right':
nextValues.left = next;
nextValues.left = nextValue;
break;
}
}

handleOnChange( nextValues );
};

const createHandleOnUnitChange = ( side ) => ( next ) => {
const newUnits = { ...selectedUnits };
newUnits[ side ] = next;
setSelectedUnits( newUnits );
};

// Filter sides if custom configuration provided, maintaining default order.
const filteredSides = sides?.length
? allSides.filter( ( side ) => sides.includes( side ) )
: allSides;
? ALL_SIDES.filter( ( side ) => sides.includes( side ) )
: ALL_SIDES;

const first = filteredSides[ 0 ];
const last = filteredSides[ filteredSides.length - 1 ];
Expand All @@ -90,7 +98,11 @@ export default function BoxInputControls( {
isLast={ last === side }
isOnly={ only === side }
value={ values[ side ] }
unit={
values[ side ] ? undefined : selectedUnits[ side ]
}
onChange={ createHandleOnChange( side ) }
onUnitChange={ createHandleOnUnitChange( side ) }
onFocus={ createHandleOnFocus( side ) }
onHoverOn={ createHandleOnHoverOn( side ) }
onHoverOff={ createHandleOnHoverOff( side ) }
Expand Down
Loading

0 comments on commit 950d59f

Please sign in to comment.