Skip to content

Commit

Permalink
[Mobile] - Spacer block - Add initial support for spacing presets (#4…
Browse files Browse the repository at this point in the history
…7258)

* Mobile - Spacer block - Add initial support for spacing presets

* Mobile - getPxFromCssUnit - Updates evalMathExpression, before it was splitting by math symbols, this would break for complex values like nested math expressions. Now it will split the string by every number value with a unit, that way it will match all values and convert them to pixel values, to then trigger the math calculation. It will also take into account math expressions wrapped within CSS expressions and take into account this cases.

* Mobile - parse-css-unit-to-px - Update logic to take into account nested calc(). It also brings back the usage of the for loop to keep consistency instead of using replace directly from the string.
  • Loading branch information
Gerardo Pacheco authored Feb 23, 2023
1 parent 5e2269a commit 8ed68ea
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 16 deletions.
5 changes: 5 additions & 0 deletions packages/block-editor/src/components/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ export {
} from './block-settings';
export { default as VideoPlayer, VIDEO_ASPECT_RATIO } from './video-player';

export {
getSpacingPresetCssVar,
getCustomValueFromPreset,
isValueSpacingPreset,
} from './spacing-sizes-control/utils';
// Content Related Components.
export { default as BlockList } from './block-list';
export { default as BlockMover } from './block-mover';
Expand Down
40 changes: 35 additions & 5 deletions packages/block-editor/src/utils/parse-css-unit-to-px.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ function parseUnit( cssUnit ) {
* @return {number} evaluated expression.
*/
function calculate( expression ) {
return Function( `'use strict'; return (${ expression })` )();
try {
return Function( `'use strict'; return (${ expression })` )();
} catch ( err ) {
return null;
}
}

/**
Expand Down Expand Up @@ -117,9 +121,9 @@ function isMathExpression( cssUnit ) {
function evalMathExpression( cssUnit ) {
let errorFound = false;
// Convert every part of the expression to px values.
const cssUnitsBits = cssUnit
.split( /(?!^-)[+*\/-](\s?-)?/g )
.filter( Boolean );
// The following regex matches numbers that have a following unit
// E.g. 5.25rem, 1vw
const cssUnitsBits = cssUnit.match( /\d+\.?\d*[a-zA-Z]+|\.\d+[a-zA-Z]+/g );
for ( const unit of cssUnitsBits ) {
// Standardize the unit to px and extract the value.
const parsedUnit = parseUnit( getPxFromCssUnit( unit ) );
Expand All @@ -131,7 +135,33 @@ function evalMathExpression( cssUnit ) {
cssUnit = cssUnit.replace( unit, parsedUnit.value );
}

return errorFound ? null : calculate( cssUnit ).toFixed( 0 ) + 'px';
// For mixed math expressions wrapped within CSS expressions
if ( ! errorFound && cssUnit.match( /(max|min|clamp)/g ) ) {
const values = cssUnit.split( ',' );
for ( const currentValue of values ) {
// Check for nested calc() and remove them to calculate the value.
const rawCurrentValue = currentValue.replace( /\s|calc/g, '' );

if ( isMathExpression( rawCurrentValue ) ) {
const calculatedExpression = calculate( rawCurrentValue );

if ( calculatedExpression ) {
const calculatedValue =
calculatedExpression.toFixed( 0 ) + 'px';
cssUnit = cssUnit.replace( currentValue, calculatedValue );
}
}
}
const parsedValue = parseUnitFunction( cssUnit );
return ! parsedValue ? null : parsedValue.value + parsedValue.unit;
}

if ( errorFound ) {
return null;
}

const calculatedResult = calculate( cssUnit );
return calculatedResult ? calculatedResult.toFixed( 0 ) + 'px' : null;
}

/**
Expand Down
12 changes: 12 additions & 0 deletions packages/block-editor/src/utils/test/parse-css-unit-to-px.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ describe( 'getPxFromCssUnit', () => {
[ 'console.log("howdy"); + 10px', null ],
[ 'calc(12vw * 10px', null ], // Missing closing bracket.
[ 'calc( 1em + 0.875rem )', '30px' ], // Decimals
[
'clamp(1.8rem, 1.8rem + ((1vw / 0.48rem + 1rem) * 2.885), 3rem)',
'48px',
],
[
'clamp(5rem, 5.25rem + ((1vw - 0.48rem) * 9.096), 8rem)',
'80px',
],
[
'clamp(2.625rem, calc(2.625rem + ((1vw - 0.48rem) * 8.4135)), 3.25rem)',
'42px',
],
];

test.each( testData )( 'getPxFromCssUnit( %s )', ( unit, expected ) => {
Expand Down
18 changes: 13 additions & 5 deletions packages/block-library/src/spacer/controls.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,24 @@ import { __ } from '@wordpress/i18n';
import { MIN_SPACER_SIZE } from './constants';
import styles from './style.scss';

const DEFAULT_VALUES = { px: 100, em: 10, rem: 10, vw: 10, vh: 25 };
export const DEFAULT_VALUES = { px: 100, em: 10, rem: 10, vw: 10, vh: 25 };

function Controls( { attributes, context, setAttributes } ) {
function Controls( {
attributes,
context,
setAttributes,
presetWidth,
presetHeight,
} ) {
const { orientation } = context;
const label = orientation !== 'horizontal' ? __( 'Height' ) : __( 'Width' );

const { height, width } = attributes;
const width = presetWidth || attributes.width;
const height = presetHeight || attributes.height;
const { valueToConvert, valueUnit: unit } =
getValueAndUnit( orientation !== 'horizontal' ? height : width ) || {};
const value = Number( valueToConvert );
const currentUnit = unit || 'px';

const setNewDimensions = ( nextValue, nextUnit ) => {
const valueWithUnit = `${ nextValue }${ nextUnit }`;
Expand All @@ -39,7 +47,7 @@ function Controls( { attributes, context, setAttributes } ) {

const handleChange = useCallback(
( nextValue ) => {
setNewDimensions( nextValue, unit );
setNewDimensions( nextValue, currentUnit );
},
[ height, width ]
);
Expand Down Expand Up @@ -72,7 +80,7 @@ function Controls( { attributes, context, setAttributes } ) {
onChange={ handleChange }
onUnitChange={ handleUnitChange }
units={ units }
unit={ unit }
unit={ currentUnit }
style={ styles.rangeCellContainer }
/>
</PanelBody>
Expand Down
51 changes: 45 additions & 6 deletions packages/block-library/src/spacer/edit.native.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,48 @@
/**
* External dependencies
*/
import { View } from 'react-native';
import { View, useWindowDimensions } from 'react-native';

/**
* WordPress dependencies
*/
import { useConvertUnitToMobile } from '@wordpress/components';
import { withPreferredColorScheme } from '@wordpress/compose';
import { InspectorControls } from '@wordpress/block-editor';
import {
InspectorControls,
isValueSpacingPreset,
useSetting,
getCustomValueFromPreset,
getPxFromCssUnit,
} from '@wordpress/block-editor';
import { useEffect } from '@wordpress/element';

/**
* Internal dependencies
*/
import Controls from './controls';
import Controls, { DEFAULT_VALUES } from './controls';
import styles from './editor.native.scss';

const DEFAULT_FONT_SIZE = 16;

const Spacer = ( {
attributes,
context,
setAttributes,
isSelected,
getStylesFromColorScheme,
} ) => {
const { height: screenHeight, width: screenWidth } = useWindowDimensions();
const cssUnitOptions = {
height: screenHeight,
width: screenWidth,
fontSize: DEFAULT_FONT_SIZE,
};
const { height, width } = attributes;

const spacingSizes = [
{ name: 0, slug: '0', size: 0 },
...( useSetting( 'spacing.spacingSizes' ) || [] ),
];
const { orientation } = context;
const defaultStyle = getStylesFromColorScheme(
styles.staticSpacer,
Expand All @@ -41,8 +58,29 @@ const Spacer = ( {
}
}, [] );

const convertedHeight = useConvertUnitToMobile( height );
const convertedWidth = useConvertUnitToMobile( width );
let convertedHeight = useConvertUnitToMobile( height );
let convertedWidth = useConvertUnitToMobile( width );
const presetValues = {};

if ( isValueSpacingPreset( height ) ) {
const heightValue = getCustomValueFromPreset( height, spacingSizes );
const parsedPresetHeightValue = parseFloat(
getPxFromCssUnit( heightValue, cssUnitOptions )
);

convertedHeight = parsedPresetHeightValue || DEFAULT_VALUES.px;
presetValues.presetHeight = convertedHeight;
}

if ( isValueSpacingPreset( width ) ) {
const widthValue = getCustomValueFromPreset( width, spacingSizes );
const parsedPresetWidthValue = parseFloat(
getPxFromCssUnit( widthValue, cssUnitOptions )
);

convertedWidth = parsedPresetWidthValue || DEFAULT_VALUES.px;
presetValues.presetWidth = convertedWidth;
}

return (
<View
Expand All @@ -58,6 +96,7 @@ const Spacer = ( {
attributes={ attributes }
context={ context }
setAttributes={ setAttributes }
{ ...presetValues }
/>
</InspectorControls>
) }
Expand Down
18 changes: 18 additions & 0 deletions packages/block-library/src/spacer/save.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* WordPress dependencies
*/
import { useBlockProps, getSpacingPresetCssVar } from '@wordpress/block-editor';

export default function save( { attributes: { height, width } } ) {
return (
<div
{ ...useBlockProps.save( {
style: {
height: getSpacingPresetCssVar( height ),
width: getSpacingPresetCssVar( width ),
},
'aria-hidden': true,
} ) }
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ exports[`Spacer block inserts block 1`] = `
<!-- /wp:spacer -->"
`;
exports[`Spacer block inserts block with spacingSizes preset 1`] = `
"<!-- wp:spacer {\\"height\\":\\"70px\\"} -->
<div style=\\"height:70px\\" aria-hidden=\\"true\\" class=\\"wp-block-spacer\\"></div>
<!-- /wp:spacer -->"
`;
exports[`Spacer block inserts block with spacingSizes preset without matching global styles values 1`] = `
"<!-- wp:spacer {\\"height\\":\\"120px\\"} -->
<div style=\\"height:120px\\" aria-hidden=\\"true\\" class=\\"wp-block-spacer\\"></div>
<!-- /wp:spacer -->"
`;
exports[`Spacer block updates height to 25vh 1`] = `
"<!-- wp:spacer {\\"height\\":\\"25vh\\"} -->
<div style=\\"height:25vh\\" aria-hidden=\\"true\\" class=\\"wp-block-spacer\\"></div>
Expand Down
81 changes: 81 additions & 0 deletions packages/block-library/src/spacer/test/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,85 @@ describe( 'Spacer block', () => {

expect( getEditorHtml() ).toMatchSnapshot();
} );

it( 'inserts block with spacingSizes preset', async () => {
// Mock spacingSizes presets
const RAW_STYLES = {
typography: {
fontSize: 16,
},
};
const RAW_FEATURES = {
spacing: {
spacingSizes: {
theme: [
{
size: '3.125rem',
slug: '100',
name: '100',
},
{
size: '3.75rem',
slug: '110',
name: '110',
},
],
},
},
};

const initialHtml = `<!-- wp:spacer {"height":"var:preset|spacing|110"} -->
<div style="height:var(--wp--preset--spacing--110)" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->`;
const screen = await initializeEditor( {
initialHtml,
rawStyles: JSON.stringify( RAW_STYLES ),
rawFeatures: JSON.stringify( RAW_FEATURES ),
} );

// Select Spacer block
const [ spacerBlock ] =
screen.getAllByLabelText( /Spacer Block\. Row 1/ );
fireEvent.press( spacerBlock );

// Open block settings
fireEvent.press( screen.getByLabelText( 'Open Settings' ) );
await waitFor(
() => screen.getByTestId( 'block-settings-modal' ).props.isVisible
);

// Update height attribute
fireEvent.press( screen.getByText( '60' ) );
const heightTextInput = screen.getByDisplayValue( '60' );
fireEvent.changeText( heightTextInput, '70' );

expect( getEditorHtml() ).toMatchSnapshot();
} );

it( 'inserts block with spacingSizes preset without matching global styles values', async () => {
const initialHtml = `<!-- wp:spacer {"height":"var:preset|spacing|30"} -->
<div style="height:var(--wp--preset--spacing--30)" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->`;
const screen = await initializeEditor( {
initialHtml,
} );

// Select Spacer block
const [ spacerBlock ] =
screen.getAllByLabelText( /Spacer Block\. Row 1/ );
fireEvent.press( spacerBlock );

// Open block settings
fireEvent.press( screen.getByLabelText( 'Open Settings' ) );
await waitFor(
() => screen.getByTestId( 'block-settings-modal' ).props.isVisible
);

// Update height attribute
fireEvent.press( screen.getByText( '100' ) );
const heightTextInput = screen.getByDisplayValue( '100' );
fireEvent.changeText( heightTextInput, '120' );

expect( getEditorHtml() ).toMatchSnapshot();
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ export function getGlobalStyles( rawStyles, rawFeatures ) {
fontSizes,
customLineHeight: features?.custom?.[ 'line-height' ],
},
spacing: features?.spacing,
},
__experimentalGlobalStylesBaseStyles: globalStyles,
};
Expand Down

1 comment on commit 8ed68ea

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in 8ed68ea.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/4255425451
📝 Reported issues:

Please sign in to comment.