Skip to content

Commit

Permalink
Mobile - getPxFromCssUnit - Updates evalMathExpression, before it was…
Browse files Browse the repository at this point in the history
… 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.
  • Loading branch information
Gerardo committed Feb 1, 2023
1 parent ad56b32 commit 16155cc
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 10 deletions.
46 changes: 36 additions & 10 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,21 +121,43 @@ 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 );
for ( const unit of cssUnitsBits ) {
// The following regex matches numbers that have a following unit
// E.g. 5.25rem, 1vw
const regex = /\d+\.?\d*[a-zA-Z]+|\.\d+[a-zA-Z]+/g;
cssUnit = cssUnit.replace( regex, ( foundUnit ) => {
// Standardize the unit to px and extract the value.
const parsedUnit = parseUnit( getPxFromCssUnit( unit ) );
const parsedUnit = parseUnit( getPxFromCssUnit( foundUnit ) );
if ( ! parseFloat( parsedUnit.value ) ) {
errorFound = true;
// End early since we are dealing with a null value.
break;
return;
}
cssUnit = cssUnit.replace( unit, parsedUnit.value );
return parsedUnit.value;
} );

// 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 ) {
if ( isMathExpression( currentValue ) ) {
const calculatedExpression = calculate( currentValue );

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;
}

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

/**
Expand Down
8 changes: 8 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,14 @@ 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',
],
];

test.each( testData )( 'getPxFromCssUnit( %s )', ( unit, expected ) => {
Expand Down

0 comments on commit 16155cc

Please sign in to comment.