From 269fad605eb30d3d6debee5d4110c5e2b122b70d Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 21 Apr 2022 10:08:06 +0100 Subject: [PATCH 1/2] Add visualizers for padding and margin for all blocks --- .../src/components/block-popover/index.js | 22 +++- .../src/components/block-popover/style.scss | 3 + packages/block-editor/src/hooks/dimensions.js | 82 +++++++------ packages/block-editor/src/hooks/margin.js | 79 +++++++++--- packages/block-editor/src/hooks/padding.js | 75 ++++++++--- packages/block-editor/src/hooks/padding.scss | 12 ++ packages/block-editor/src/style.scss | 1 + packages/block-library/src/cover/edit.js | 9 -- packages/block-library/src/cover/style.scss | 4 - packages/components/src/box-control/README.md | 74 ----------- packages/components/src/box-control/index.js | 15 --- .../src/box-control/stories/index.js | 29 ----- packages/components/src/box-control/utils.js | 7 -- .../components/src/box-control/visualizer.js | 116 ------------------ 14 files changed, 204 insertions(+), 324 deletions(-) create mode 100644 packages/block-editor/src/hooks/padding.scss delete mode 100644 packages/components/src/box-control/visualizer.js diff --git a/packages/block-editor/src/components/block-popover/index.js b/packages/block-editor/src/components/block-popover/index.js index 2bff678f977b6..ae493fb9cf5b5 100644 --- a/packages/block-editor/src/components/block-popover/index.js +++ b/packages/block-editor/src/components/block-popover/index.js @@ -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 @@ -19,6 +20,8 @@ export default function BlockPopover( { clientId, bottomClientId, children, + __unstableRefreshSize, + __unstableCoverTarget = false, __unstablePopoverSlot, __unstableContentRef, ...props @@ -26,6 +29,17 @@ export default function BlockPopover( { 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; @@ -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 } @@ -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 &&
{ children }
} + { ! __unstableCoverTarget && children } ); } diff --git a/packages/block-editor/src/components/block-popover/style.scss b/packages/block-editor/src/components/block-popover/style.scss index 86d11ed94007f..c120f05faa2e8 100644 --- a/packages/block-editor/src/components/block-popover/style.scss +++ b/packages/block-editor/src/components/block-popover/style.scss @@ -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; diff --git a/packages/block-editor/src/hooks/dimensions.js b/packages/block-editor/src/hooks/dimensions.js index ecfb0fa164c34..9252844d8b576 100644 --- a/packages/block-editor/src/hooks/dimensions.js +++ b/packages/block-editor/src/hooks/dimensions.js @@ -19,6 +19,7 @@ import { } from './gap'; import { MarginEdit, + MarginVisualizer, hasMarginSupport, hasMarginValue, resetMargin, @@ -26,6 +27,7 @@ import { } from './margin'; import { PaddingEdit, + PaddingVisualizer, hasPaddingSupport, hasPaddingValue, resetPadding, @@ -71,44 +73,48 @@ export function DimensionsPanel( props ) { } ); return ( - - { ! isPaddingDisabled && ( - hasPaddingValue( props ) } - label={ __( 'Padding' ) } - onDeselect={ () => resetPadding( props ) } - resetAllFilter={ createResetAllFilter( 'padding' ) } - isShownByDefault={ defaultSpacingControls?.padding } - panelId={ props.clientId } - > - - - ) } - { ! isMarginDisabled && ( - hasMarginValue( props ) } - label={ __( 'Margin' ) } - onDeselect={ () => resetMargin( props ) } - resetAllFilter={ createResetAllFilter( 'margin' ) } - isShownByDefault={ defaultSpacingControls?.margin } - panelId={ props.clientId } - > - - - ) } - { ! isGapDisabled && ( - hasGapValue( props ) } - label={ __( 'Block spacing' ) } - onDeselect={ () => resetGap( props ) } - resetAllFilter={ createResetAllFilter( 'blockGap' ) } - isShownByDefault={ defaultSpacingControls?.blockGap } - panelId={ props.clientId } - > - - - ) } - + <> + + { ! isPaddingDisabled && ( + hasPaddingValue( props ) } + label={ __( 'Padding' ) } + onDeselect={ () => resetPadding( props ) } + resetAllFilter={ createResetAllFilter( 'padding' ) } + isShownByDefault={ defaultSpacingControls?.padding } + panelId={ props.clientId } + > + + + ) } + { ! isMarginDisabled && ( + hasMarginValue( props ) } + label={ __( 'Margin' ) } + onDeselect={ () => resetMargin( props ) } + resetAllFilter={ createResetAllFilter( 'margin' ) } + isShownByDefault={ defaultSpacingControls?.margin } + panelId={ props.clientId } + > + + + ) } + { ! isGapDisabled && ( + hasGapValue( props ) } + label={ __( 'Block spacing' ) } + onDeselect={ () => resetGap( props ) } + resetAllFilter={ createResetAllFilter( 'blockGap' ) } + isShownByDefault={ defaultSpacingControls?.blockGap } + panelId={ props.clientId } + > + + + ) } + + { ! isPaddingDisabled && } + { ! isMarginDisabled && } + ); } diff --git a/packages/block-editor/src/hooks/margin.js b/packages/block-editor/src/hooks/margin.js index 8ae0a9d7d9083..8efb5b542b9e8 100644 --- a/packages/block-editor/src/hooks/margin.js +++ b/packages/block-editor/src/hooks/margin.js @@ -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 @@ -20,6 +27,7 @@ import { useIsDimensionsSupportValid, } from './dimensions'; import { cleanEmptyObject } from './utils'; +import BlockPopover from '../components/block-popover'; /** * Determines if there is margin support. @@ -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: ( <> { + 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 ( + +
+ + ); +} diff --git a/packages/block-editor/src/hooks/padding.js b/packages/block-editor/src/hooks/padding.js index f01276baefdf1..02a371db0d6a3 100644 --- a/packages/block-editor/src/hooks/padding.js +++ b/packages/block-editor/src/hooks/padding.js @@ -2,12 +2,19 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { Platform } from '@wordpress/element'; +import { + Platform, + useState, + useRef, + useEffect, + useMemo, +} 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 @@ -20,6 +27,7 @@ import { useIsDimensionsSupportValid, } from './dimensions'; import { cleanEmptyObject } from './utils'; +import BlockPopover from '../components/block-popover'; /** * Determines if there is padding support. @@ -124,26 +132,12 @@ export function PaddingEdit( props ) { } ); }; - const onChangeShowVisualizer = ( next ) => { - const newStyle = { - ...style, - visualizers: { - padding: next, - }, - }; - - setAttributes( { - style: cleanEmptyObject( newStyle ), - } ); - }; - return Platform.select( { web: ( <> { + return { + borderTopWidth: padding?.top ?? 0, + borderRightWidth: padding?.right ?? 0, + borderBottomWidth: padding?.bottom ?? 0, + borderLeftWidth: padding?.left ?? 0, + }; + }, [ padding ] ); + + const [ isActive, setIsActive ] = useState( false ); + const valueRef = useRef( padding ); + const timeoutRef = useRef(); + + const clearTimer = () => { + if ( timeoutRef.current ) { + window.clearTimeout( timeoutRef.current ); + } + }; + + useEffect( () => { + if ( ! isShallowEqual( padding, valueRef.current ) ) { + setIsActive( true ); + valueRef.current = padding; + + clearTimer(); + + timeoutRef.current = setTimeout( () => { + setIsActive( false ); + }, 400 ); + } + + return () => clearTimer(); + }, [ padding ] ); + + if ( ! isActive ) { + return null; + } + + return ( + +
+ + ); +} diff --git a/packages/block-editor/src/hooks/padding.scss b/packages/block-editor/src/hooks/padding.scss new file mode 100644 index 0000000000000..dbb9991988189 --- /dev/null +++ b/packages/block-editor/src/hooks/padding.scss @@ -0,0 +1,12 @@ +.block-editor__padding-visualizer { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + opacity: 0.5; + border-color: var(--wp-admin-theme-color); + border-style: solid; + pointer-events: none; + box-sizing: border-box; +} diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss index b2228762f12db..cd7e64118ff44 100644 --- a/packages/block-editor/src/style.scss +++ b/packages/block-editor/src/style.scss @@ -59,6 +59,7 @@ @import "./hooks/dimensions.scss"; @import "./hooks/typography.scss"; @import "./hooks/color.scss"; +@import "./hooks/padding.scss"; @import "./components/block-toolbar/style.scss"; @import "./components/inserter/style.scss"; diff --git a/packages/block-library/src/cover/edit.js b/packages/block-library/src/cover/edit.js index 45a090768f6a6..7481bf4640769 100644 --- a/packages/block-library/src/cover/edit.js +++ b/packages/block-library/src/cover/edit.js @@ -31,7 +31,6 @@ import { ToggleControl, ToolbarButton, __experimentalUseCustomUnits as useCustomUnits, - __experimentalBoxControl as BoxControl, __experimentalToolsPanelItem as ToolsPanelItem, __experimentalUnitControl as UnitControl, __experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue, @@ -77,8 +76,6 @@ import { extend( [ namesPlugin ] ); -const { __Visualizer: BoxControlVisualizer } = BoxControl; - function getInnerBlocksTemplate( attributes ) { return [ [ @@ -313,7 +310,6 @@ function CoverEdit( { isRepeated, minHeight, minHeightUnit, - style: styleAttribute, alt, allowedBlocks, templateLock, @@ -744,11 +740,6 @@ function CoverEdit( { style={ { ...style, ...blockProps.style } } data-url={ url } > - { diff --git a/packages/block-library/src/cover/style.scss b/packages/block-library/src/cover/style.scss index db543cb731e5c..a9328ff17e52b 100644 --- a/packages/block-library/src/cover/style.scss +++ b/packages/block-library/src/cover/style.scss @@ -96,10 +96,6 @@ } } - .block-library-cover__padding-visualizer { - z-index: z-index(".block-library-cover__padding-visualizer"); - } - // Apply max-width to floated items that have no intrinsic width &.alignleft, &.alignright { diff --git a/packages/components/src/box-control/README.md b/packages/components/src/box-control/README.md index 328bfb78c6772..8a704482cacd1 100644 --- a/packages/components/src/box-control/README.md +++ b/packages/components/src/box-control/README.md @@ -29,73 +29,6 @@ const Example = () => { }; ``` -### Visualizer - -BoxControl provides a companion component that visually renders value changes. Place the component you would like the sides visualized within the companion `` component. - -```jsx -import { __experimentalBoxControl as BoxControl } from '@wordpress/components'; -import { useState } from '@wordpress/element'; - -import MyComponent from './my-component'; - -const { Visualizer } = BoxControl; - -const Example = () => { - const [ values, setValues ] = useState( { - top: '50px', - left: '10%', - right: '10%', - bottom: '50px', - } ); - - return ( - <> - setValues( nextValues ) } - /> - - - - - ); -}; -``` - -Alternatively, the `` can be nested as a sibling to the component you would like visualized. Using `` in this manner will require the parent element having a `position` style. - -```jsx -import { __experimentalBoxControl as BoxControl } from '@wordpress/components'; -import { useState } from '@wordpress/element'; - -import MyComponent from './my-component'; - -const { Visualizer } = BoxControl; - -const Example = () => { - const [ values, setValues ] = useState( { - top: '50px', - left: '10%', - right: '10%', - bottom: '50px', - } ); - - return ( - <> - setValues( nextValues ) } - /> -
- - -
- - ); -}; -``` - ## Props ### allowReset @@ -135,13 +68,6 @@ A callback function when an input value changes. - Type: `Function` - Required: Yes -### onChangeShowVisualizer - -A callback function for visualizer changes, based on input hover interactions. - -- Type: `Function` -- Required: Yes - ### resetValues The `top`, `right`, `bottom`, and `left` box dimension values to use when the control is reset. diff --git a/packages/components/src/box-control/index.js b/packages/components/src/box-control/index.js index 54377010e5df2..cbd11e1995435 100644 --- a/packages/components/src/box-control/index.js +++ b/packages/components/src/box-control/index.js @@ -21,7 +21,6 @@ import AxialInputControls from './axial-input-controls'; import BoxControlIcon from './icon'; import { Text } from '../text'; import LinkedButton from './linked-button'; -import Visualizer from './visualizer'; import { Root, Header, @@ -30,7 +29,6 @@ import { import { parseQuantityAndUnitFromRawValue } from '../unit-control/utils'; import { DEFAULT_VALUES, - DEFAULT_VISUALIZER_VALUES, getInitialSide, isValuesMixed, isValuesDefined, @@ -50,7 +48,6 @@ export default function BoxControl( { id: idProp, inputProps = defaultInputProps, onChange = noop, - onChangeShowVisualizer = noop, label = __( 'Box Control' ), values: valuesProp, units, @@ -103,14 +100,6 @@ export default function BoxControl( { setIsDirty( true ); }; - const handleOnHoverOn = ( next = {} ) => { - onChangeShowVisualizer( { ...DEFAULT_VISUALIZER_VALUES, ...next } ); - }; - - const handleOnHoverOff = ( next = {} ) => { - onChangeShowVisualizer( { ...DEFAULT_VISUALIZER_VALUES, ...next } ); - }; - const handleOnReset = () => { onChange( resetValues ); setValues( resetValues ); @@ -122,8 +111,6 @@ export default function BoxControl( { ...inputProps, onChange: handleOnChange, onFocus: handleOnFocus, - onHoverOn: handleOnHoverOn, - onHoverOff: handleOnHoverOff, isLinked, units, selectedUnits, @@ -189,5 +176,3 @@ export default function BoxControl( { ); } - -BoxControl.__Visualizer = Visualizer; diff --git a/packages/components/src/box-control/stories/index.js b/packages/components/src/box-control/stories/index.js index c05263adefb79..f0bab8e21481d 100644 --- a/packages/components/src/box-control/stories/index.js +++ b/packages/components/src/box-control/stories/index.js @@ -11,7 +11,6 @@ import { useState } from '@wordpress/element'; * Internal dependencies */ import BoxControl from '../'; -import BoxControlVisualizer from '../visualizer'; import { Flex, FlexBlock } from '../../flex'; export default { @@ -36,7 +35,6 @@ function DemoExample( { splitOnAxis = false, } ) { const [ values, setValues ] = useState( defaultValues ); - const [ showVisualizer, setShowVisualizer ] = useState( {} ); return ( @@ -47,31 +45,14 @@ function DemoExample( { values={ values } sides={ sides } onChange={ setValues } - onChangeShowVisualizer={ setShowVisualizer } splitOnAxis={ splitOnAxis } /> - - - - - - - - - ); } -export const visualizer = () => { - return ; -}; - export const arbitrarySides = () => { return (