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

[WIP] Block Support: Add gap block support feature #32571

Closed
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
13 changes: 13 additions & 0 deletions lib/block-supports/dimensions.php
Original file line number Diff line number Diff line change
@@ -63,6 +63,7 @@ function gutenberg_apply_spacing_support( $block_type, $block_attributes ) {

$has_padding_support = gutenberg_block_has_support( $block_type, array( 'spacing', 'padding' ), false );
$has_margin_support = gutenberg_block_has_support( $block_type, array( 'spacing', 'margin' ), false );
$has_gap_support = gutenberg_block_has_support( $block_type, array( 'spacing', 'gap' ), false );
$styles = array();

if ( $has_padding_support ) {
@@ -89,6 +90,18 @@ function gutenberg_apply_spacing_support( $block_type, $block_attributes ) {
}
}

if ( $has_gap_support ) {
$gap_value = _wp_array_get( $block_attributes, array( 'style', 'spacing', 'gap' ), null );

if ( is_array( $gap_value ) ) {
foreach ( $gap_value as $key => $value ) {
$styles[] = sprintf( '--wp--theme--block-%s-gap: %s', $key, $value );
}
} elseif ( null !== $gap_value ) {
$styles[] = sprintf( '--wp--theme--block-: %s', $gap_value );
}
}

return empty( $styles ) ? array() : array( 'style' => implode( ' ', $styles ) );
}

63 changes: 34 additions & 29 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
@@ -61,6 +61,7 @@ class WP_Theme_JSON_Gutenberg {
'text' => null,
),
'spacing' => array(
'gap' => null,
'margin' => null,
'padding' => null,
),
@@ -98,6 +99,7 @@ class WP_Theme_JSON_Gutenberg {
'wideSize' => null,
),
'spacing' => array(
'customGap' => null,
'customMargin' => null,
'customPadding' => null,
'units' => null,
@@ -206,35 +208,38 @@ class WP_Theme_JSON_Gutenberg {
* path to the value in theme.json & block attributes.
*/
const PROPERTIES_METADATA = array(
'background' => array( 'color', 'gradient' ),
'background-color' => array( 'color', 'background' ),
'border-radius' => array( 'border', 'radius' ),
'border-top-left-radius' => array( 'border', 'radius', 'topLeft' ),
'border-top-right-radius' => array( 'border', 'radius', 'topRight' ),
'border-bottom-left-radius' => array( 'border', 'radius', 'bottomLeft' ),
'border-bottom-right-radius' => array( 'border', 'radius', 'bottomRight' ),
'border-color' => array( 'border', 'color' ),
'border-width' => array( 'border', 'width' ),
'border-style' => array( 'border', 'style' ),
'color' => array( 'color', 'text' ),
'font-family' => array( 'typography', 'fontFamily' ),
'font-size' => array( 'typography', 'fontSize' ),
'font-style' => array( 'typography', 'fontStyle' ),
'font-weight' => array( 'typography', 'fontWeight' ),
'letter-spacing' => array( 'typography', 'letterSpacing' ),
'line-height' => array( 'typography', 'lineHeight' ),
'margin' => array( 'spacing', 'margin' ),
'margin-top' => array( 'spacing', 'margin', 'top' ),
'margin-right' => array( 'spacing', 'margin', 'right' ),
'margin-bottom' => array( 'spacing', 'margin', 'bottom' ),
'margin-left' => array( 'spacing', 'margin', 'left' ),
'padding' => array( 'spacing', 'padding' ),
'padding-top' => array( 'spacing', 'padding', 'top' ),
'padding-right' => array( 'spacing', 'padding', 'right' ),
'padding-bottom' => array( 'spacing', 'padding', 'bottom' ),
'padding-left' => array( 'spacing', 'padding', 'left' ),
'text-decoration' => array( 'typography', 'textDecoration' ),
'text-transform' => array( 'typography', 'textTransform' ),
'background' => array( 'color', 'gradient' ),
'background-color' => array( 'color', 'background' ),
'border-radius' => array( 'border', 'radius' ),
'border-top-left-radius' => array( 'border', 'radius', 'topLeft' ),
'border-top-right-radius' => array( 'border', 'radius', 'topRight' ),
'border-bottom-left-radius' => array( 'border', 'radius', 'bottomLeft' ),
'border-bottom-right-radius' => array( 'border', 'radius', 'bottomRight' ),
'border-color' => array( 'border', 'color' ),
'border-width' => array( 'border', 'width' ),
'border-style' => array( 'border', 'style' ),
'color' => array( 'color', 'text' ),
'font-family' => array( 'typography', 'fontFamily' ),
'font-size' => array( 'typography', 'fontSize' ),
'font-style' => array( 'typography', 'fontStyle' ),
'font-weight' => array( 'typography', 'fontWeight' ),
'--wp--theme--block-gap' => array( 'spacing', 'gap' ),
'--wp--theme--block-column-gap' => array( 'spacing', 'gap', 'column' ),
'--wp--theme--block-row-gap' => array( 'spacing', 'gap', 'row' ),
'letter-spacing' => array( 'typography', 'letterSpacing' ),
'line-height' => array( 'typography', 'lineHeight' ),
'margin' => array( 'spacing', 'margin' ),
'margin-top' => array( 'spacing', 'margin', 'top' ),
'margin-right' => array( 'spacing', 'margin', 'right' ),
'margin-bottom' => array( 'spacing', 'margin', 'bottom' ),
'margin-left' => array( 'spacing', 'margin', 'left' ),
'padding' => array( 'spacing', 'padding' ),
'padding-top' => array( 'spacing', 'padding', 'top' ),
'padding-right' => array( 'spacing', 'padding', 'right' ),
'padding-bottom' => array( 'spacing', 'padding', 'bottom' ),
'padding-left' => array( 'spacing', 'padding', 'left' ),
'text-decoration' => array( 'typography', 'textDecoration' ),
'text-transform' => array( 'typography', 'textTransform' ),
);

const ELEMENTS = array(
3 changes: 3 additions & 0 deletions lib/compat.php
Original file line number Diff line number Diff line change
@@ -186,6 +186,9 @@ function gutenberg_safe_style_attrs( $attrs ) {
$attrs[] = 'border-top-right-radius';
$attrs[] = 'border-bottom-right-radius';
$attrs[] = 'border-bottom-left-radius';
$attrs[] = 'gap';
$attrs[] = 'column-gap';
$attrs[] = 'row-gap';

return $attrs;
}
1 change: 1 addition & 0 deletions lib/experimental-default-theme.json
Original file line number Diff line number Diff line change
@@ -211,6 +211,7 @@
]
},
"spacing": {
"customGap": false,
"customMargin": false,
"customPadding": false,
"units": [ "px", "em", "rem", "vh", "vw", "%" ]
28 changes: 26 additions & 2 deletions packages/block-editor/src/hooks/dimensions.js
Original file line number Diff line number Diff line change
@@ -13,6 +13,13 @@ import { getBlockSupport } from '@wordpress/blocks';
* Internal dependencies
*/
import InspectorControls from '../components/inspector-controls';
import {
GapEdit,
hasGapSupport,
hasGapValue,
resetGap,
useIsGapDisabled,
} from './gap';
import {
MarginEdit,
hasMarginSupport,
@@ -39,6 +46,7 @@ export const SPACING_SUPPORT_KEY = 'spacing';
* @return {WPElement} Inspector controls for spacing support features.
*/
export function DimensionsPanel( props ) {
const isGapDisabled = useIsGapDisabled( props );
const isPaddingDisabled = useIsPaddingDisabled( props );
const isMarginDisabled = useIsMarginDisabled( props );
const isDisabled = useIsDimensionsDisabled( props );
@@ -62,6 +70,7 @@ export function DimensionsPanel( props ) {
...style,
spacing: {
...style?.spacing,
gap: undefined,
margin: undefined,
padding: undefined,
},
@@ -96,6 +105,16 @@ export function DimensionsPanel( props ) {
<MarginEdit { ...props } />
</ToolsPanelItem>
) }
{ ! isGapDisabled && (
<ToolsPanelItem
hasValue={ () => hasGapValue( props ) }
label={ __( 'Gap' ) }
onDeselect={ () => resetGap( props ) }
isShownByDefault={ defaultSpacingControls?.gap }
>
<GapEdit { ...props } />
</ToolsPanelItem>
) }
</ToolsPanel>
</InspectorControls>
);
@@ -113,7 +132,11 @@ export function hasDimensionsSupport( blockName ) {
return false;
}

return hasPaddingSupport( blockName ) || hasMarginSupport( blockName );
return (
hasGapSupport( blockName ) ||
hasPaddingSupport( blockName ) ||
hasMarginSupport( blockName )
);
}

/**
@@ -124,10 +147,11 @@ export function hasDimensionsSupport( blockName ) {
* @return {boolean} If spacing support is completely disabled.
*/
const useIsDimensionsDisabled = ( props = {} ) => {
const gapDisabled = useIsGapDisabled( props );
const paddingDisabled = useIsPaddingDisabled( props );
const marginDisabled = useIsMarginDisabled( props );

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

/**
153 changes: 153 additions & 0 deletions packages/block-editor/src/hooks/gap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { Platform } from '@wordpress/element';
import { getBlockSupport } from '@wordpress/blocks';
import {
__experimentalUseCustomUnits as useCustomUnits,
__experimentalBoxControl as BoxControl,
} from '@wordpress/components';

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

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

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

/**
* Resets the gap block support attribute. This can be used when disabling
* the gap 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 resetGap( { attributes = {}, setAttributes } ) {
const { style } = attributes;

setAttributes( {
style: {
...style,
spacing: {
...style?.spacing,
gap: undefined,
},
},
} );
}

/**
* Custom hook that checks if gap settings have been disabled.
*
* @param {string} name The name of the block.
* @return {boolean} Whether the gap setting is disabled.
*/
export function useIsGapDisabled( { name: blockName } = {} ) {
const isDisabled = ! useSetting( 'spacing.customGap' );
return ! hasGapSupport( blockName ) || isDisabled;
}

/**
* Inspector control panel containing the gap related configuration
*
* @param {Object} props
*
* @return {WPElement} Gap edit element.
*/
export function GapEdit( props ) {
const {
name: blockName,
attributes: { style },
setAttributes,
} = props;

const units = useCustomUnits( {
availableUnits: useSetting( 'spacing.units' ) || [
'%',
'px',
'em',
'rem',
'vw',
],
} );
const sides = useCustomSides( blockName, 'gap' );

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

const onChange = ( next ) => {
const newStyle = {
...style,
spacing: {
...style?.spacing,
gap: { row: next?.top, column: next?.left },
},
};

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

const onChangeShowVisualizer = ( next ) => {
const newStyle = {
...style,
visualizers: {
gap: { row: next?.top, column: next?.left },
},
};

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

const boxValues = {
top: style?.spacing?.gap?.row,
right: style?.spacing?.gap?.column,
bottom: style?.spacing?.gap?.row,
left: style?.spacing?.gap?.column,
};

return Platform.select( {
web: (
<>
<BoxControl
values={ boxValues }
onChange={ onChange }
onChangeShowVisualizer={ onChangeShowVisualizer }
label={ __( 'Gap' ) }
sides={ sides }
units={ units }
allowReset={ false }
splitOnAxis={ true }
/>
</>
),
native: null,
} );
}
Loading