Skip to content

Commit

Permalink
Add height dimensions block support
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronrobertshaw committed Jan 21, 2022
1 parent 5062a1e commit 3c62628
Show file tree
Hide file tree
Showing 11 changed files with 273 additions and 28 deletions.
18 changes: 14 additions & 4 deletions lib/block-supports/dimensions.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ function gutenberg_register_dimensions_support( $block_type ) {
}

$has_dimensions_support = gutenberg_block_has_support( $block_type, array( '__experimentalDimensions' ), false );
// Future block supports such as height & width will be added here.

if ( $has_dimensions_support ) {
$block_type->attributes['style'] = array(
Expand All @@ -44,14 +43,24 @@ function gutenberg_register_dimensions_support( $block_type ) {
*
* @return array Block dimensions CSS classes and inline styles.
*/
function gutenberg_apply_dimensions_support( $block_type, $block_attributes ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
function gutenberg_apply_dimensions_support( $block_type, $block_attributes ) {
if ( gutenberg_skip_dimensions_serialization( $block_type ) ) {
return array();
}

$styles = array();

// Height support to be added in near future.
// Height.
$has_height_support = gutenberg_block_has_support( $block_type, array( '__experimentalDimensions', 'height' ), false );

if ( $has_height_support ) {
$height_value = _wp_array_get( $block_attributes, array( 'style', 'dimensions', 'height' ), null );

if ( null !== $height_value ) {
$styles[] = sprintf( 'height: %s;', $height_value );
}
}

// Width support to be added in near future.

return empty( $styles ) ? array() : array( 'style' => implode( ' ', $styles ) );
Expand All @@ -63,10 +72,11 @@ function gutenberg_apply_dimensions_support( $block_type, $block_attributes ) {
*
* @param WP_Block_type $block_type Block type.
*
* @return boolean Whether to serialize spacing support styles & classes.
* @return boolean Whether to serialize dimensions support styles & classes.
*/
function gutenberg_skip_dimensions_serialization( $block_type ) {
$dimensions_support = _wp_array_get( $block_type->supports, array( '__experimentalDimensions' ), false );

return is_array( $dimensions_support ) &&
array_key_exists( '__experimentalSkipSerialization', $dimensions_support ) &&
$dimensions_support['__experimentalSkipSerialization'];
Expand Down
15 changes: 11 additions & 4 deletions lib/compat/wordpress-5.9/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ class WP_Theme_JSON_Gutenberg {
'font-size' => array( 'typography', 'fontSize' ),
'font-style' => array( 'typography', 'fontStyle' ),
'font-weight' => array( 'typography', 'fontWeight' ),
'height' => array( 'dimensions', 'height' ),
'letter-spacing' => array( 'typography', 'letterSpacing' ),
'line-height' => array( 'typography', 'lineHeight' ),
'margin' => array( 'spacing', 'margin' ),
Expand Down Expand Up @@ -238,6 +239,9 @@ class WP_Theme_JSON_Gutenberg {
'text' => null,
),
'custom' => null,
'dimensions' => array(
'height' => null,
),
'layout' => array(
'contentSize' => null,
'wideSize' => null,
Expand Down Expand Up @@ -274,6 +278,9 @@ class WP_Theme_JSON_Gutenberg {
'style' => null,
'width' => null,
),
'dimensions' => array(
'height' => null,
),
'color' => array(
'background' => null,
'gradient' => null,
Expand Down Expand Up @@ -1528,7 +1535,7 @@ public function get_svg_filters( $origins ) {
}

/**
* Returns whether a presets should be overriden or not.
* Returns whether a presets should be overridden or not.
*
* @param array $theme_json The theme.json like structure to inspect.
* @param array $path Path to inspect.
Expand All @@ -1543,8 +1550,8 @@ private static function should_override_preset( $theme_json, $path, $override )
// The relationship between whether to override the defaults
// and whether the defaults are enabled is inverse:
//
// - If defaults are enabled => theme presets should not be overriden
// - If defaults are disabled => theme presets should be overriden
// - If defaults are enabled => theme presets should not be overridden
// - If defaults are disabled => theme presets should be overridden
//
// For example, a theme sets defaultPalette to false,
// making the default palette hidden from the user.
Expand Down Expand Up @@ -1633,7 +1640,7 @@ private function get_name_from_defaults( $slug, $base_path ) {
* Removes the preset values whose slug is equal to any of given slugs.
*
* @param array $node The node with the presets to validate.
* @param array $slugs The slugs that should not be overriden.
* @param array $slugs The slugs that should not be overridden.
*
* @return array The new node
*/
Expand Down
3 changes: 3 additions & 0 deletions lib/compat/wordpress-5.9/theme.json
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,9 @@
],
"text": true
},
"dimensions": {
"height": false
},
"spacing": {
"blockGap": null,
"margin": false,
Expand Down
63 changes: 52 additions & 11 deletions packages/block-editor/src/hooks/dimensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ import {
resetGap,
useIsGapDisabled,
} from './gap';
import {
HeightEdit,
hasHeightSupport,
hasHeightValue,
resetHeight,
useIsHeightDisabled,
} from './height';
import {
MarginEdit,
hasMarginSupport,
Expand All @@ -32,6 +39,7 @@ import {
useIsPaddingDisabled,
} from './padding';

export const DIMENSIONS_SUPPORT_KEY = '__experimentalDimensions';
export const SPACING_SUPPORT_KEY = 'spacing';
export const ALL_SIDES = [ 'top', 'right', 'bottom', 'left' ];
export const AXIAL_SIDES = [ 'vertical', 'horizontal' ];
Expand All @@ -40,44 +48,70 @@ export const AXIAL_SIDES = [ 'vertical', 'horizontal' ];
* Inspector controls for dimensions support.
*
* @param {Object} props Block props.
*
* @return {WPElement} Inspector controls for spacing support features.
* @return {WPElement} Inspector controls for dimensions support features.
*/
export function DimensionsPanel( props ) {
const isGapDisabled = useIsGapDisabled( props );
const isPaddingDisabled = useIsPaddingDisabled( props );
const isMarginDisabled = useIsMarginDisabled( props );
const isHeightDisabled = useIsHeightDisabled( props );
const isDisabled = useIsDimensionsDisabled( props );
const isSupported = hasDimensionsSupport( props.name );

if ( isDisabled || ! isSupported ) {
return null;
}

const defaultDimensionsControls = getBlockSupport( props.name, [
DIMENSIONS_SUPPORT_KEY,
'__experimentalDefaultControls',
] );

const defaultSpacingControls = getBlockSupport( props.name, [
SPACING_SUPPORT_KEY,
'__experimentalDefaultControls',
] );

const createResetAllFilter = ( attribute ) => ( newAttributes ) => ( {
const createResetAllFilter = ( attribute, featureSet ) => (
newAttributes
) => ( {
...newAttributes,
style: {
...newAttributes.style,
spacing: {
...newAttributes.style?.spacing,
[ featureSet ]: {
...newAttributes.style?.[ featureSet ],
[ attribute ]: undefined,
},
},
} );

return (
<InspectorControls __experimentalGroup="dimensions">
{ ! isHeightDisabled && (
<ToolsPanelItem
className="single-column"
hasValue={ () => hasHeightValue( props ) }
label={ __( 'Height' ) }
onDeselect={ () => resetHeight( props ) }
resetAllFilter={ createResetAllFilter(
'height',
'dimensions'
) }
isShownByDefault={ defaultDimensionsControls?.height }
panelId={ props.clientId }
>
<HeightEdit { ...props } />
</ToolsPanelItem>
) }
{ ! isPaddingDisabled && (
<ToolsPanelItem
hasValue={ () => hasPaddingValue( props ) }
label={ __( 'Padding' ) }
onDeselect={ () => resetPadding( props ) }
resetAllFilter={ createResetAllFilter( 'padding' ) }
resetAllFilter={ createResetAllFilter(
'padding',
'spacing'
) }
isShownByDefault={ defaultSpacingControls?.padding }
panelId={ props.clientId }
>
Expand All @@ -89,7 +123,10 @@ export function DimensionsPanel( props ) {
hasValue={ () => hasMarginValue( props ) }
label={ __( 'Margin' ) }
onDeselect={ () => resetMargin( props ) }
resetAllFilter={ createResetAllFilter( 'margin' ) }
resetAllFilter={ createResetAllFilter(
'margin',
'spacing'
) }
isShownByDefault={ defaultSpacingControls?.margin }
panelId={ props.clientId }
>
Expand All @@ -101,7 +138,10 @@ export function DimensionsPanel( props ) {
hasValue={ () => hasGapValue( props ) }
label={ __( 'Block spacing' ) }
onDeselect={ () => resetGap( props ) }
resetAllFilter={ createResetAllFilter( 'blockGap' ) }
resetAllFilter={ createResetAllFilter(
'blockGap',
'spacing'
) }
isShownByDefault={ defaultSpacingControls?.blockGap }
panelId={ props.clientId }
>
Expand All @@ -126,6 +166,7 @@ export function hasDimensionsSupport( blockName ) {

return (
hasGapSupport( blockName ) ||
hasHeightSupport( blockName ) ||
hasPaddingSupport( blockName ) ||
hasMarginSupport( blockName )
);
Expand All @@ -135,15 +176,15 @@ export function hasDimensionsSupport( blockName ) {
* Determines whether dimensions support has been disabled.
*
* @param {Object} props Block properties.
*
* @return {boolean} If spacing support is completely disabled.
* @return {boolean} If dimensions support is completely disabled.
*/
const useIsDimensionsDisabled = ( props = {} ) => {
const gapDisabled = useIsGapDisabled( props );
const heightDisabled = useIsHeightDisabled( props );
const paddingDisabled = useIsPaddingDisabled( props );
const marginDisabled = useIsMarginDisabled( props );

return gapDisabled && paddingDisabled && marginDisabled;
return gapDisabled && heightDisabled && paddingDisabled && marginDisabled;
};

/**
Expand Down
121 changes: 121 additions & 0 deletions packages/block-editor/src/hooks/height.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/**
* WordPress dependencies
*/
import { getBlockSupport } from '@wordpress/blocks';
import {
__experimentalUseCustomUnits as useCustomUnits,
__experimentalUnitControl as UnitControl,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import useSetting from '../components/use-setting';
import { DIMENSIONS_SUPPORT_KEY } from './dimensions';
import { cleanEmptyObject } from './utils';

/**
* Determines if there is height support.
*
* @param {string|Object} blockType Block name or Block Type object.
* @return {boolean} Whether there is support.
*/
export function hasHeightSupport( blockType ) {
const support = getBlockSupport( blockType, DIMENSIONS_SUPPORT_KEY );
return !! ( true === support || support?.height );
}

/**
* Checks if there is a current value in the height block support attributes.
*
* @param {Object} props Block props.
* @return {boolean} Whether or not the block has a height value set.
*/
export function hasHeightValue( props ) {
return props.attributes.style?.dimensions?.height !== undefined;
}

/**
* Resets the height block support attributes. This can be used when
* disabling the height support controls for a block via a progressive
* discovery panel.
*
* @param {Object} props Block props.
* @param {Object} props.attributes Block's attributes.
* @param {Object} props.setAttributes Function to set block's attributes.
*/
export function resetHeight( { attributes = {}, setAttributes } ) {
const { style } = attributes;

setAttributes( {
style: cleanEmptyObject( {
...style,
dimensions: {
...style?.dimensions,
height: undefined,
},
} ),
} );
}

/**
* Custom hook that checks if height controls have been disabled.
*
* @param {string} name The name of the block.
* @return {boolean} Whether height control is disabled.
*/
export function useIsHeightDisabled( { name: blockName } = {} ) {
const isDisabled = ! useSetting( 'dimensions.height' );
return ! hasHeightSupport( blockName ) || isDisabled;
}

/**
* Inspector control panel containing the height related configuration.
*
* @param {Object} props Block props.
* @return {WPElement} Edit component for height.
*/
export function HeightEdit( props ) {
const {
attributes: { style },
setAttributes,
} = props;

const units = useCustomUnits( {
availableUnits: useSetting( 'dimensions.units' ) || [
'%',
'px',
'em',
'rem',
'vh',
'vw',
],
} );

if ( useIsHeightDisabled( props ) ) {
return null;
}

const onChange = ( next ) => {
const newStyle = {
...style,
dimensions: {
...style?.dimensions,
height: next,
},
};

setAttributes( { style: cleanEmptyObject( newStyle ) } );
};

return (
<UnitControl
label={ __( 'Height' ) }
value={ style?.dimensions?.height }
units={ units }
onChange={ onChange }
min={ 0 }
/>
);
}
Loading

0 comments on commit 3c62628

Please sign in to comment.