diff --git a/packages/block-editor/src/hooks/padding.js b/packages/block-editor/src/hooks/padding.js index 7253ee0629b66..f476a03ce3bfb 100644 --- a/packages/block-editor/src/hooks/padding.js +++ b/packages/block-editor/src/hooks/padding.js @@ -9,16 +9,33 @@ import { __experimentalBoxControl as BoxControl } from '@wordpress/components'; /** * Internal dependencies */ +import useEditorFeature from '../components/use-editor-feature'; +import { SPACING_SUPPORT_KEY, useCustomSides } from './spacing'; import { cleanEmptyObject } from './utils'; import { useCustomUnits } from '../components/unit-control'; -export const SPACING_SUPPORT_KEY = 'spacing'; - -const hasPaddingSupport = ( blockName ) => { - const spacingSupport = getBlockSupport( blockName, SPACING_SUPPORT_KEY ); - return spacingSupport && spacingSupport.padding !== false; +/** + * Determines if there is padding support. + * + * @param {string|Object} blockType Block name or Block Type object. + * @return {boolean} Whether there is support. + */ +const hasPaddingSupport = ( blockType ) => { + const support = getBlockSupport( blockType, SPACING_SUPPORT_KEY ); + return !! ( true === support || support?.padding ); }; +/** + * Custom hook that checks if padding settings have been disabled. + * + * @param {string} name The name of the block. + * @return {boolean} Whether padding setting is disabled. + */ +export function useIsPaddingDisabled( { name: blockName } = {} ) { + const isDisabled = ! useEditorFeature( 'spacing.customPadding' ); + return ! hasPaddingSupport( blockName ) || isDisabled; +} + /** * Inspector control panel containing the padding related configuration * @@ -34,6 +51,7 @@ export function PaddingEdit( props ) { } = props; const units = useCustomUnits(); + const sides = useCustomSides( blockName, 'padding' ); if ( ! hasPaddingSupport( blockName ) ) { return null; @@ -43,6 +61,7 @@ export function PaddingEdit( props ) { const newStyle = { ...style, spacing: { + ...style?.spacing, padding: next, }, }; @@ -73,6 +92,7 @@ export function PaddingEdit( props ) { onChange={ onChange } onChangeShowVisualizer={ onChangeShowVisualizer } label={ __( 'Padding' ) } + sides={ sides } units={ units } /> diff --git a/packages/block-editor/src/hooks/spacing.js b/packages/block-editor/src/hooks/spacing.js new file mode 100644 index 0000000000000..49d2ee7283f75 --- /dev/null +++ b/packages/block-editor/src/hooks/spacing.js @@ -0,0 +1,85 @@ +/** + * WordPress dependencies + */ +import { getBlockSupport } from '@wordpress/blocks'; +import { Platform } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { PaddingEdit, useIsPaddingDisabled } from './padding'; +import SpacingPanelControl from '../components/spacing-panel-control'; + +export const SPACING_SUPPORT_KEY = 'spacing'; + +/** + * Inspector controls for spacing support. + * + * @param {Object} props Block props. + * @return {WPElement} Inspector controls for spacing support features. + */ +export function SpacingPanel( props ) { + const isDisabled = useIsSpacingDisabled( props ); + const isSupported = hasSpacingSupport( props.name ); + + if ( isDisabled || ! isSupported ) { + return null; + } + + return ( + + + + ); +} + +/** + * Determine whether there is block support for padding or margins. + * + * @param {string} blockName Block name. + * @return {boolean} Whether there is support. + */ +export function hasSpacingSupport( blockName ) { + if ( Platform.OS !== 'web' ) { + return false; + } + + const support = getBlockSupport( blockName, SPACING_SUPPORT_KEY ); + + return !! ( true === support || support?.padding || support?.margin ); +} + +/** + * Determines whether spacing support has been disabled. + * + * @param {Object} props Block properties. + * @return {boolean} If spacing support is completely disabled. + */ +const useIsSpacingDisabled = ( props = {} ) => { + const paddingDisabled = useIsPaddingDisabled( props ); + + return paddingDisabled; +}; + +/** + * Custom hook to retrieve which padding/margin is supported + * e.g. top, right, bottom or left. + * + * Sides are opted into by default. It is only if a specific side is set to + * false that it is omitted. + * + * @param {string} blockName Block name. + * @param {string} feature The feature custom sides relate to e.g. padding or margins. + * @return {Object} Sides supporting custom margin. + */ +export function useCustomSides( blockName, feature ) { + const support = getBlockSupport( blockName, SPACING_SUPPORT_KEY ); + + // Return empty config when setting is boolean as theme isn't setting + // arbitrary sides. + if ( typeof support[ feature ] === 'boolean' ) { + return {}; + } + + return support[ feature ]; +} diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index b1c7239b2d791..8bbd8dba1e5fc 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -20,8 +20,7 @@ import { createHigherOrderComponent } from '@wordpress/compose'; import { BORDER_SUPPORT_KEY, BorderPanel } from './border'; import { COLOR_SUPPORT_KEY, ColorEdit } from './color'; import { TypographyPanel, TYPOGRAPHY_SUPPORT_KEYS } from './typography'; -import { SPACING_SUPPORT_KEY, PaddingEdit } from './padding'; -import SpacingPanelControl from '../components/spacing-panel-control'; +import { SPACING_SUPPORT_KEY, SpacingPanel } from './spacing'; const styleSupportKeys = [ ...TYPOGRAPHY_SUPPORT_KEYS, @@ -140,7 +139,7 @@ export function addSaveProps( props, blockType, attributes ) { } /** - * Filters registered block settings to extand the block edit wrapper + * Filters registered block settings to extend the block edit wrapper * to apply the desired styles and classnames properly. * * @param {Object} settings Original block settings @@ -173,23 +172,12 @@ export function addEditProps( settings ) { */ export const withBlockControls = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { - const { name: blockName } = props; - - const hasSpacingSupport = hasBlockSupport( - blockName, - SPACING_SUPPORT_KEY - ); - return [ , , , , - hasSpacingSupport && ( - - - - ), + , ]; }, 'withToolbarControls' diff --git a/packages/block-editor/src/hooks/test/style.js b/packages/block-editor/src/hooks/test/style.js index afa1d45856b2a..bb3880c163fdd 100644 --- a/packages/block-editor/src/hooks/test/style.js +++ b/packages/block-editor/src/hooks/test/style.js @@ -18,6 +18,9 @@ describe( 'getInlineStyles', () => { color: { text: 'red', background: 'black' }, typography: { lineHeight: 1.5, fontSize: 10 }, border: { radius: 10 }, + spacing: { + padding: { top: '10px' }, + }, } ) ).toEqual( { backgroundColor: 'black', @@ -25,6 +28,7 @@ describe( 'getInlineStyles', () => { color: 'red', lineHeight: 1.5, fontSize: 10, + paddingTop: '10px', } ); } ); } ); diff --git a/packages/edit-site/src/components/sidebar/spacing-panel.js b/packages/edit-site/src/components/sidebar/spacing-panel.js index f2609b49c4696..a244491c6a4e1 100644 --- a/packages/edit-site/src/components/sidebar/spacing-panel.js +++ b/packages/edit-site/src/components/sidebar/spacing-panel.js @@ -6,13 +6,20 @@ import { __experimentalBoxControl as BoxControl, PanelBody, } from '@wordpress/components'; +import { getBlockSupport } from '@wordpress/blocks'; /** * Internal dependencies */ import { useEditorFeature } from '../editor/utils'; -export function useHasSpacingPanel( { supports, name } ) { +export function useHasSpacingPanel( context ) { + const hasPadding = useHasPadding( context ); + + return hasPadding; +} + +export function useHasPadding( { name, supports } ) { return ( useEditorFeature( 'spacing.customPadding', name ) && supports.includes( 'padding' ) @@ -35,29 +42,58 @@ function useCustomUnits( { units, contextName } ) { return usedUnits.length === 0 ? false : usedUnits; } -export default function SpacingPanel( { - context: { name }, - getStyle, - setStyle, -} ) { +function useCustomSides( blockName, feature ) { + const support = getBlockSupport( blockName, 'spacing' ); + + // Return empty config when setting is boolean as theme isn't setting + // arbitrary sides. + if ( typeof support[ feature ] === 'boolean' ) { + return {}; + } + + return support[ feature ]; +} + +function filterValuesBySides( values, sides ) { + if ( Object.entries( sides ).length === 0 ) { + // If no custom side configuration all sides are opted into by default. + return values; + } + + // Only include sides opted into within filtered values. + return Object.keys( sides ) + .filter( ( side ) => sides[ side ] ) + .reduce( + ( filtered, side ) => ( { ...filtered, [ side ]: values[ side ] } ), + {} + ); +} + +export default function SpacingPanel( { context, getStyle, setStyle } ) { + const { name } = context; + const showPaddingControl = useHasPadding( context ); const units = useCustomUnits( { contextName: name } ); + const paddingValues = getStyle( name, 'padding' ); - const setPaddingValues = ( { top, right, bottom, left } ) => { - setStyle( name, 'padding', { - top: top || paddingValues?.top, - right: right || paddingValues?.right, - bottom: bottom || paddingValues?.bottom, - left: left || paddingValues?.left, - } ); + const paddingSides = useCustomSides( name, 'padding' ); + + const setPaddingValues = ( newPaddingValues ) => { + const padding = filterValuesBySides( newPaddingValues, paddingSides ); + setStyle( name, 'padding', padding ); }; + return ( - + { showPaddingControl && ( + + ) } ); }