@wordpress/block-editor
Version:
199 lines (181 loc) • 4.85 kB
JavaScript
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import {
BaseControl,
Flex,
FlexItem,
RangeControl,
__experimentalUnitControl as UnitControl,
__experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue,
} from '@wordpress/components';
/**
* Internal dependencies
*/
import { appendSelectors, getBlockGapCSS } from './utils';
import { getGapCSSValue } from '../hooks/gap';
import { shouldSkipSerialization } from '../hooks/utils';
const RANGE_CONTROL_MAX_VALUES = {
px: 600,
'%': 100,
vw: 100,
vh: 100,
em: 38,
rem: 38,
};
export default {
name: 'grid',
label: __( 'Grid' ),
inspectorControls: function GridLayoutInspectorControls( {
layout = {},
onChange,
} ) {
return layout?.columnCount ? (
<GridLayoutColumnsControl layout={ layout } onChange={ onChange } />
) : (
<GridLayoutMinimumWidthControl
layout={ layout }
onChange={ onChange }
/>
);
},
toolBarControls: function DefaultLayoutToolbarControls() {
return null;
},
getLayoutStyle: function getLayoutStyle( {
selector,
layout,
style,
blockName,
hasBlockGapSupport,
layoutDefinitions,
} ) {
const { minimumColumnWidth = '12rem', columnCount = null } = layout;
// If a block's block.json skips serialization for spacing or spacing.blockGap,
// don't apply the user-defined value to the styles.
const blockGapValue =
style?.spacing?.blockGap &&
! shouldSkipSerialization( blockName, 'spacing', 'blockGap' )
? getGapCSSValue( style?.spacing?.blockGap, '0.5em' )
: undefined;
let output = '';
const rules = [];
if ( columnCount ) {
rules.push(
`grid-template-columns: repeat(${ columnCount }, minmax(0, 1fr))`
);
} else if ( minimumColumnWidth ) {
rules.push(
`grid-template-columns: repeat(auto-fill, minmax(min(${ minimumColumnWidth }, 100%), 1fr))`
);
}
if ( rules.length ) {
// Reason to disable: the extra line breaks added by prettier mess with the unit tests.
// eslint-disable-next-line prettier/prettier
output = `${ appendSelectors( selector ) } { ${ rules.join(
'; '
) }; }`;
}
// Output blockGap styles based on rules contained in layout definitions in theme.json.
if ( hasBlockGapSupport && blockGapValue ) {
output += getBlockGapCSS(
selector,
layoutDefinitions,
'grid',
blockGapValue
);
}
return output;
},
getOrientation() {
return 'horizontal';
},
getAlignments() {
return [];
},
};
// Enables setting minimum width of grid items.
function GridLayoutMinimumWidthControl( { layout, onChange } ) {
const { minimumColumnWidth: value = '12rem' } = layout;
const [ quantity, unit ] = parseQuantityAndUnitFromRawValue( value );
const handleSliderChange = ( next ) => {
onChange( {
...layout,
minimumColumnWidth: [ next, unit ].join( '' ),
} );
};
// Mostly copied from HeightControl.
const handleUnitChange = ( newUnit ) => {
// Attempt to smooth over differences between currentUnit and newUnit.
// This should slightly improve the experience of switching between unit types.
let newValue;
if ( [ 'em', 'rem' ].includes( newUnit ) && unit === 'px' ) {
// Convert pixel value to an approximate of the new unit, assuming a root size of 16px.
newValue = ( quantity / 16 ).toFixed( 2 ) + newUnit;
} else if ( [ 'em', 'rem' ].includes( unit ) && newUnit === 'px' ) {
// Convert to pixel value assuming a root size of 16px.
newValue = Math.round( quantity * 16 ) + newUnit;
} else if (
[ 'vh', 'vw', '%' ].includes( newUnit ) &&
quantity > 100
) {
// When converting to `vh`, `vw`, or `%` units, cap the new value at 100.
newValue = 100 + newUnit;
}
onChange( {
...layout,
minimumColumnWidth: newValue,
} );
};
return (
<fieldset>
<BaseControl.VisualLabel as="legend">
{ __( 'Minimum column width' ) }
</BaseControl.VisualLabel>
<Flex gap={ 4 }>
<FlexItem isBlock>
<UnitControl
size={ '__unstable-large' }
onChange={ ( newValue ) => {
onChange( {
...layout,
minimumColumnWidth: newValue,
} );
} }
onUnitChange={ handleUnitChange }
value={ value }
min={ 0 }
/>
</FlexItem>
<FlexItem isBlock>
<RangeControl
onChange={ handleSliderChange }
value={ quantity }
min={ 0 }
max={ RANGE_CONTROL_MAX_VALUES[ unit ] || 600 }
withInputField={ false }
/>
</FlexItem>
</Flex>
</fieldset>
);
}
// Enables setting number of grid columns
function GridLayoutColumnsControl( { layout, onChange } ) {
const { columnCount = 3 } = layout;
return (
<RangeControl
label={ __( 'Columns' ) }
value={ columnCount }
onChange={ ( value ) =>
onChange( {
...layout,
columnCount: value,
} )
}
min={ 1 }
max={ 6 }
/>
);
}