@wordpress/block-editor
Version:
207 lines (183 loc) • 5.64 kB
JavaScript
/**
* External dependencies
*/
import clsx from 'clsx';
/**
* WordPress dependencies
*/
import { Platform, useState, useEffect, useCallback } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import { getBlockSupport } from '@wordpress/blocks';
import deprecated from '@wordpress/deprecated';
/**
* Internal dependencies
*/
import InspectorControls from '../components/inspector-controls';
import {
DimensionsPanel as StylesDimensionsPanel,
useHasDimensionsPanel,
} from '../components/global-styles';
import { MarginVisualizer, PaddingVisualizer } from './spacing-visualizer';
import { store as blockEditorStore } from '../store';
import { unlock } from '../lock-unlock';
import { cleanEmptyObject, shouldSkipSerialization } from './utils';
export const DIMENSIONS_SUPPORT_KEY = 'dimensions';
export const SPACING_SUPPORT_KEY = 'spacing';
export const ALL_SIDES = [ 'top', 'right', 'bottom', 'left' ];
export const AXIAL_SIDES = [ 'vertical', 'horizontal' ];
function useVisualizer() {
const [ property, setProperty ] = useState( false );
const { hideBlockInterface, showBlockInterface } = unlock(
useDispatch( blockEditorStore )
);
useEffect( () => {
if ( ! property ) {
showBlockInterface();
} else {
hideBlockInterface();
}
}, [ property, showBlockInterface, hideBlockInterface ] );
return [ property, setProperty ];
}
function DimensionsInspectorControl( { children, resetAllFilter } ) {
const attributesResetAllFilter = useCallback(
( attributes ) => {
const existingStyle = attributes.style;
const updatedStyle = resetAllFilter( existingStyle );
return {
...attributes,
style: updatedStyle,
};
},
[ resetAllFilter ]
);
return (
<InspectorControls
group="dimensions"
resetAllFilter={ attributesResetAllFilter }
>
{ children }
</InspectorControls>
);
}
export function DimensionsPanel( { clientId, name, setAttributes, settings } ) {
const isEnabled = useHasDimensionsPanel( settings );
const value = useSelect(
( select ) =>
select( blockEditorStore ).getBlockAttributes( clientId )?.style,
[ clientId ]
);
const [ visualizedProperty, setVisualizedProperty ] = useVisualizer();
const onChange = ( newStyle ) => {
setAttributes( {
style: cleanEmptyObject( newStyle ),
} );
};
if ( ! isEnabled ) {
return null;
}
const defaultDimensionsControls = getBlockSupport( name, [
DIMENSIONS_SUPPORT_KEY,
'__experimentalDefaultControls',
] );
const defaultSpacingControls = getBlockSupport( name, [
SPACING_SUPPORT_KEY,
'__experimentalDefaultControls',
] );
const defaultControls = {
...defaultDimensionsControls,
...defaultSpacingControls,
};
return (
<>
<StylesDimensionsPanel
as={ DimensionsInspectorControl }
panelId={ clientId }
settings={ settings }
value={ value }
onChange={ onChange }
defaultControls={ defaultControls }
onVisualize={ setVisualizedProperty }
/>
{ !! settings?.spacing?.padding && (
<PaddingVisualizer
forceShow={ visualizedProperty === 'padding' }
clientId={ clientId }
value={ value }
/>
) }
{ !! settings?.spacing?.margin && (
<MarginVisualizer
forceShow={ visualizedProperty === 'margin' }
clientId={ clientId }
value={ value }
/>
) }
</>
);
}
/**
* Determine whether there is block support for dimensions.
*
* @param {string} blockName Block name.
* @param {string} feature Background image feature to check for.
*
* @return {boolean} Whether there is support.
*/
export function hasDimensionsSupport( blockName, feature = 'any' ) {
if ( Platform.OS !== 'web' ) {
return false;
}
const support = getBlockSupport( blockName, DIMENSIONS_SUPPORT_KEY );
if ( support === true ) {
return true;
}
if ( feature === 'any' ) {
return !! ( support?.aspectRatio || !! support?.minHeight );
}
return !! support?.[ feature ];
}
export default {
useBlockProps,
attributeKeys: [ 'minHeight', 'style' ],
hasSupport( name ) {
return hasDimensionsSupport( name, 'aspectRatio' );
},
};
function useBlockProps( { name, minHeight, style } ) {
if (
! hasDimensionsSupport( name, 'aspectRatio' ) ||
shouldSkipSerialization( name, DIMENSIONS_SUPPORT_KEY, 'aspectRatio' )
) {
return {};
}
const className = clsx( {
'has-aspect-ratio': !! style?.dimensions?.aspectRatio,
} );
// Allow dimensions-based inline style overrides to override any global styles rules that
// might be set for the block, and therefore affect the display of the aspect ratio.
const inlineStyleOverrides = {};
// Apply rules to unset incompatible styles.
// Note that a set `aspectRatio` will win out if both an aspect ratio and a minHeight are set.
// This is because the aspect ratio is a newer block support, so (in theory) any aspect ratio
// that is set should be intentional and should override any existing minHeight. The Cover block
// and dimensions controls have logic that will manually clear the aspect ratio if a minHeight
// is set.
if ( style?.dimensions?.aspectRatio ) {
// To ensure the aspect ratio does not get overridden by `minHeight` unset any existing rule.
inlineStyleOverrides.minHeight = 'unset';
} else if ( minHeight || style?.dimensions?.minHeight ) {
// To ensure the minHeight does not get overridden by `aspectRatio` unset any existing rule.
inlineStyleOverrides.aspectRatio = 'unset';
}
return { className, style: inlineStyleOverrides };
}
/**
* @deprecated
*/
export function useCustomSides() {
deprecated( 'wp.blockEditor.__experimentalUseCustomSides', {
since: '6.3',
version: '6.4',
} );
}