Skip to content

Commit

Permalink
Add visualizers for padding and margin for all blocks (#40505)
Browse files Browse the repository at this point in the history
Co-authored-by: Miguel Fonseca <miguelcsf@gmail.com>
  • Loading branch information
youknowriad and mcsf committed Apr 21, 2022
1 parent ae9e149 commit 2ce8e8d
Show file tree
Hide file tree
Showing 14 changed files with 204 additions and 324 deletions.
22 changes: 20 additions & 2 deletions packages/block-editor/src/components/block-popover/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import classnames from 'classnames';
*/
import { Popover } from '@wordpress/components';
import { getScrollContainer } from '@wordpress/dom';
import { useMemo } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -19,13 +20,26 @@ export default function BlockPopover( {
clientId,
bottomClientId,
children,
__unstableRefreshSize,
__unstableCoverTarget = false,
__unstablePopoverSlot,
__unstableContentRef,
...props
} ) {
const selectedElement = useBlockElement( clientId );
const lastSelectedElement = useBlockElement( bottomClientId ?? clientId );
const popoverScrollRef = usePopoverScroll( __unstableContentRef );
const style = useMemo( () => {
if ( ! selectedElement || lastSelectedElement !== selectedElement ) {
return {};
}

return {
position: 'absolute',
width: selectedElement.offsetWidth,
height: selectedElement.offsetHeight,
};
}, [ selectedElement, lastSelectedElement, __unstableRefreshSize ] );

if ( ! selectedElement || ( bottomClientId && ! lastSelectedElement ) ) {
return null;
Expand All @@ -50,7 +64,9 @@ export default function BlockPopover( {
position="top right left"
focusOnMount={ false }
anchorRef={ anchorRef }
__unstableStickyBoundaryElement={ stickyBoundaryElement }
__unstableStickyBoundaryElement={
__unstableCoverTarget ? undefined : stickyBoundaryElement
}
// Render in the old slot if needed for backward compatibility,
// otherwise render in place (not in the the default popover slot).
__unstableSlotName={ __unstablePopoverSlot || null }
Expand All @@ -61,13 +77,15 @@ export default function BlockPopover( {
// Used to safeguard sticky position behavior against cases where it would permanently
// obscure specific sections of a block.
__unstableEditorCanvasWrapper={ __unstableContentRef?.current }
__unstableForcePosition={ __unstableCoverTarget }
{ ...props }
className={ classnames(
'block-editor-block-popover',
props.className
) }
>
{ children }
{ __unstableCoverTarget && <div style={ style }>{ children }</div> }
{ ! __unstableCoverTarget && children }
</Popover>
);
}
3 changes: 3 additions & 0 deletions packages/block-editor/src/components/block-popover/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
.components-popover.block-editor-block-popover {
z-index: z-index(".block-editor-block-popover");
position: absolute;
// Shouldn't be needed but it looks
// like the popover is impacted by the block gap margin.
margin: 0 !important;

.components-popover__content {
margin: 0 !important;
Expand Down
82 changes: 44 additions & 38 deletions packages/block-editor/src/hooks/dimensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ import {
} from './gap';
import {
MarginEdit,
MarginVisualizer,
hasMarginSupport,
hasMarginValue,
resetMargin,
useIsMarginDisabled,
} from './margin';
import {
PaddingEdit,
PaddingVisualizer,
hasPaddingSupport,
hasPaddingValue,
resetPadding,
Expand Down Expand Up @@ -71,44 +73,48 @@ export function DimensionsPanel( props ) {
} );

return (
<InspectorControls __experimentalGroup="dimensions">
{ ! isPaddingDisabled && (
<ToolsPanelItem
hasValue={ () => hasPaddingValue( props ) }
label={ __( 'Padding' ) }
onDeselect={ () => resetPadding( props ) }
resetAllFilter={ createResetAllFilter( 'padding' ) }
isShownByDefault={ defaultSpacingControls?.padding }
panelId={ props.clientId }
>
<PaddingEdit { ...props } />
</ToolsPanelItem>
) }
{ ! isMarginDisabled && (
<ToolsPanelItem
hasValue={ () => hasMarginValue( props ) }
label={ __( 'Margin' ) }
onDeselect={ () => resetMargin( props ) }
resetAllFilter={ createResetAllFilter( 'margin' ) }
isShownByDefault={ defaultSpacingControls?.margin }
panelId={ props.clientId }
>
<MarginEdit { ...props } />
</ToolsPanelItem>
) }
{ ! isGapDisabled && (
<ToolsPanelItem
hasValue={ () => hasGapValue( props ) }
label={ __( 'Block spacing' ) }
onDeselect={ () => resetGap( props ) }
resetAllFilter={ createResetAllFilter( 'blockGap' ) }
isShownByDefault={ defaultSpacingControls?.blockGap }
panelId={ props.clientId }
>
<GapEdit { ...props } />
</ToolsPanelItem>
) }
</InspectorControls>
<>
<InspectorControls __experimentalGroup="dimensions">
{ ! isPaddingDisabled && (
<ToolsPanelItem
hasValue={ () => hasPaddingValue( props ) }
label={ __( 'Padding' ) }
onDeselect={ () => resetPadding( props ) }
resetAllFilter={ createResetAllFilter( 'padding' ) }
isShownByDefault={ defaultSpacingControls?.padding }
panelId={ props.clientId }
>
<PaddingEdit { ...props } />
</ToolsPanelItem>
) }
{ ! isMarginDisabled && (
<ToolsPanelItem
hasValue={ () => hasMarginValue( props ) }
label={ __( 'Margin' ) }
onDeselect={ () => resetMargin( props ) }
resetAllFilter={ createResetAllFilter( 'margin' ) }
isShownByDefault={ defaultSpacingControls?.margin }
panelId={ props.clientId }
>
<MarginEdit { ...props } />
</ToolsPanelItem>
) }
{ ! isGapDisabled && (
<ToolsPanelItem
hasValue={ () => hasGapValue( props ) }
label={ __( 'Block spacing' ) }
onDeselect={ () => resetGap( props ) }
resetAllFilter={ createResetAllFilter( 'blockGap' ) }
isShownByDefault={ defaultSpacingControls?.blockGap }
panelId={ props.clientId }
>
<GapEdit { ...props } />
</ToolsPanelItem>
) }
</InspectorControls>
{ ! isPaddingDisabled && <PaddingVisualizer { ...props } /> }
{ ! isMarginDisabled && <MarginVisualizer { ...props } /> }
</>
);
}

Expand Down
79 changes: 64 additions & 15 deletions packages/block-editor/src/hooks/margin.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { Platform } from '@wordpress/element';
import {
Platform,
useMemo,
useRef,
useState,
useEffect,
} from '@wordpress/element';
import { getBlockSupport } from '@wordpress/blocks';
import {
__experimentalUseCustomUnits as useCustomUnits,
__experimentalBoxControl as BoxControl,
} from '@wordpress/components';
import isShallowEqual from '@wordpress/is-shallow-equal';

/**
* Internal dependencies
Expand All @@ -20,6 +27,7 @@ import {
useIsDimensionsSupportValid,
} from './dimensions';
import { cleanEmptyObject } from './utils';
import BlockPopover from '../components/block-popover';

/**
* Determines if there is margin support.
Expand Down Expand Up @@ -124,26 +132,12 @@ export function MarginEdit( props ) {
} );
};

const onChangeShowVisualizer = ( next ) => {
const newStyle = {
...style,
visualizers: {
margin: next,
},
};

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

return Platform.select( {
web: (
<>
<BoxControl
values={ style?.spacing?.margin }
onChange={ onChange }
onChangeShowVisualizer={ onChangeShowVisualizer }
label={ __( 'Margin' ) }
sides={ sides }
units={ units }
Expand All @@ -155,3 +149,58 @@ export function MarginEdit( props ) {
native: null,
} );
}

export function MarginVisualizer( { clientId, attributes } ) {
const margin = attributes?.style?.spacing?.margin;
const style = useMemo( () => {
return {
borderTopWidth: margin?.top ?? 0,
borderRightWidth: margin?.right ?? 0,
borderBottomWidth: margin?.bottom ?? 0,
borderLeftWidth: margin?.left ?? 0,
top: margin?.top ? `-${ margin.top }` : 0,
right: margin?.right ? `-${ margin.right }` : 0,
bottom: margin?.bottom ? `-${ margin.bottom }` : 0,
left: margin?.left ? `-${ margin.left }` : 0,
};
}, [ margin ] );

const [ isActive, setIsActive ] = useState( false );
const valueRef = useRef( margin );
const timeoutRef = useRef();

const clearTimer = () => {
if ( timeoutRef.current ) {
window.clearTimeout( timeoutRef.current );
}
};

useEffect( () => {
if ( ! isShallowEqual( margin, valueRef.current ) ) {
setIsActive( true );
valueRef.current = margin;

clearTimer();

timeoutRef.current = setTimeout( () => {
setIsActive( false );
}, 400 );
}

return () => clearTimer();
}, [ margin ] );

if ( ! isActive ) {
return null;
}

return (
<BlockPopover
clientId={ clientId }
__unstableCoverTarget
__unstableRefreshSize={ margin }
>
<div className="block-editor__padding-visualizer" style={ style } />
</BlockPopover>
);
}

0 comments on commit 2ce8e8d

Please sign in to comment.