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

Add visualizers for padding and margin for all blocks #40505

Merged
merged 2 commits into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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>
);
}
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,
youknowriad marked this conversation as resolved.
Show resolved Hide resolved
};
}, [ 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>
);
}