Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Mobile] - Spacer block - Add initial support for spacing presets #47258

Merged
merged 6 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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