From f2eb4223571b7e967d53ba2a9592e844217ae774 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 31 Mar 2023 14:16:31 +1000 Subject: [PATCH] Cover: Add border support using ResizableBox via BlockPopover (#41153) --- packages/base-styles/_z-index.scss | 4 +- .../src/components/iframe/index.js | 2 +- .../components/resizable-box-popover/index.js | 27 ++++++ packages/block-editor/src/private-apis.js | 2 + packages/block-library/src/cover/block.json | 12 +++ .../block-library/src/cover/edit/index.js | 81 +++++++++--------- .../src/cover/edit/resizable-cover-popover.js | 82 +++++++++++++++++++ .../src/cover/edit/resizable-cover.js | 61 -------------- packages/block-library/src/cover/editor.scss | 33 +++++--- packages/block-library/src/cover/style.scss | 1 + 10 files changed, 191 insertions(+), 114 deletions(-) create mode 100644 packages/block-editor/src/components/resizable-box-popover/index.js create mode 100644 packages/block-library/src/cover/edit/resizable-cover-popover.js delete mode 100644 packages/block-library/src/cover/edit/resizable-cover.js diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss index d61403d7027073..a85814b4b838a1 100644 --- a/packages/base-styles/_z-index.scss +++ b/packages/base-styles/_z-index.scss @@ -33,8 +33,8 @@ $z-layers: ( ".interface-interface-skeleton__content": 20, ".edit-widgets-header": 30, ".block-library-button__inline-link .block-editor-url-input__suggestions": 6, // URL suggestions for button block above sibling inserter - ".wp-block-cover__inner-container": 1, // InnerBlocks area inside cover image block - ".wp-block-cover.is-placeholder .components-placeholder.is-large": 1, // Cover block resizer component inside a large placeholder. + ".wp-block-cover__inner-container": 32, // InnerBlocks area inside cover image block. Must be higher than block popover and less than drop zone. + ".wp-block-cover.is-placeholder .components-placeholder.is-large": 32, // Cover block resizer component inside a large placeholder. ".wp-block-cover.has-background-dim::before": 1, // Overlay area inside block cover need to be higher than the video background. ".block-library-cover__padding-visualizer": 2, // BoxControl visualizer needs to be +1 higher than .wp-block-cover.has-background-dim::before ".wp-block-cover__image-background": 0, // Image background inside cover block. diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index b7c25fe7dc84b1..c6639f9e057e1c 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -71,7 +71,7 @@ function bubbleEvents( doc ) { } } - const eventTypes = [ 'dragover' ]; + const eventTypes = [ 'dragover', 'mousemove' ]; for ( const name of eventTypes ) { doc.addEventListener( name, bubbleEvent ); diff --git a/packages/block-editor/src/components/resizable-box-popover/index.js b/packages/block-editor/src/components/resizable-box-popover/index.js new file mode 100644 index 00000000000000..c2400dbe07f912 --- /dev/null +++ b/packages/block-editor/src/components/resizable-box-popover/index.js @@ -0,0 +1,27 @@ +/** + * WordPress dependencies + */ +import { ResizableBox } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import BlockPopover from '../block-popover'; + +export default function ResizableBoxPopover( { + clientId, + resizableBoxProps, + ...props +} ) { + return ( + + + + ); +} diff --git a/packages/block-editor/src/private-apis.js b/packages/block-editor/src/private-apis.js index 567849f66f019e..ceb6bcd0e31c02 100644 --- a/packages/block-editor/src/private-apis.js +++ b/packages/block-editor/src/private-apis.js @@ -6,6 +6,7 @@ import { ExperimentalBlockEditorProvider } from './components/provider'; import { lock } from './lock-unlock'; import OffCanvasEditor from './components/off-canvas-editor'; import LeafMoreMenu from './components/off-canvas-editor/leaf-more-menu'; +import ResizableBoxPopover from './components/resizable-box-popover'; import { ComposedPrivateInserter as PrivateInserter } from './components/inserter'; import { PrivateListView } from './components/list-view'; @@ -20,4 +21,5 @@ lock( privateApis, { OffCanvasEditor, PrivateInserter, PrivateListView, + ResizableBoxPopover, } ); diff --git a/packages/block-library/src/cover/block.json b/packages/block-library/src/cover/block.json index 0d272ab4e4cfff..8c7cb0f9143c63 100644 --- a/packages/block-library/src/cover/block.json +++ b/packages/block-library/src/cover/block.json @@ -94,6 +94,18 @@ "blockGap": true } }, + "__experimentalBorder": { + "color": true, + "radius": true, + "style": true, + "width": true, + "__experimentalDefaultControls": { + "color": true, + "radius": true, + "style": true, + "width": true + } + }, "color": { "__experimentalDuotone": "> .wp-block-cover__image-background, > .wp-block-cover__video-background", "text": true, diff --git a/packages/block-library/src/cover/edit/index.js b/packages/block-library/src/cover/edit/index.js index a74ebe8fe18eb2..cbb8ac4e4891b1 100644 --- a/packages/block-library/src/cover/edit/index.js +++ b/packages/block-library/src/cover/edit/index.js @@ -9,9 +9,9 @@ import namesPlugin from 'colord/plugins/names'; * WordPress dependencies */ import { useEntityProp, store as coreStore } from '@wordpress/core-data'; -import { useEffect, useRef } from '@wordpress/element'; +import { useEffect, useMemo, useRef } from '@wordpress/element'; import { Placeholder, Spinner } from '@wordpress/components'; -import { compose } from '@wordpress/compose'; +import { compose, useResizeObserver } from '@wordpress/compose'; import { withColors, ColorPalette, @@ -42,7 +42,7 @@ import useCoverIsDark from './use-cover-is-dark'; import CoverInspectorControls from './inspector-controls'; import CoverBlockControls from './block-controls'; import CoverPlaceholder from './cover-placeholder'; -import ResizableCover from './resizable-cover'; +import ResizableCoverPopover from './resizable-cover-popover'; extend( [ namesPlugin ] ); @@ -146,6 +146,14 @@ function CoverEdit( { const isImageBackground = IMAGE_BACKGROUND_TYPE === backgroundType; const isVideoBackground = VIDEO_BACKGROUND_TYPE === backgroundType; + const [ resizeListener, { height, width } ] = useResizeObserver(); + const resizableBoxDimensions = useMemo( () => { + return { + height: minHeightUnit === 'px' ? minHeight : 'auto', + width: 'auto', + }; + }, [ minHeight, minHeightUnit ] ); + const minHeightWithUnit = minHeight && minHeightUnit ? `${ minHeight }${ minHeightUnit }` @@ -246,24 +254,50 @@ function CoverEdit( { /> ); + const resizableCoverProps = { + className: 'block-library-cover__resize-container', + clientId, + height, + minHeight: minHeightWithUnit, + onResizeStart: () => { + setAttributes( { minHeightUnit: 'px' } ); + toggleSelection( false ); + }, + onResize: ( value ) => { + setAttributes( { minHeight: value } ); + }, + onResizeStop: ( newMinHeight ) => { + toggleSelection( true ); + setAttributes( { minHeight: newMinHeight } ); + }, + showHandle: true, + size: resizableBoxDimensions, + width, + }; + if ( ! useFeaturedImage && ! hasInnerBlocks && ! hasBackground ) { return ( <> { blockControls } { inspectorControls } + { isSelected && ( + + ) } + { resizeListener } @@ -275,21 +309,6 @@ function CoverEdit( { /> - { - setAttributes( { minHeightUnit: 'px' } ); - toggleSelection( false ); - } } - onResize={ ( value ) => { - setAttributes( { minHeight: value } ); - } } - onResizeStop={ ( newMinHeight ) => { - toggleSelection( true ); - setAttributes( { minHeight: newMinHeight } ); - } } - showHandle={ isSelected } - /> > ); @@ -318,22 +337,7 @@ function CoverEdit( { style={ { ...style, ...blockProps.style } } data-url={ url } > - { - setAttributes( { minHeightUnit: 'px' } ); - toggleSelection( false ); - } } - onResize={ ( value ) => { - setAttributes( { minHeight: value } ); - } } - onResizeStop={ ( newMinHeight ) => { - toggleSelection( true ); - setAttributes( { minHeight: newMinHeight } ); - } } - showHandle={ isSelected } - /> - + { resizeListener } { ( ! useFeaturedImage || url ) && ( + { isSelected && ( + + ) } > ); } diff --git a/packages/block-library/src/cover/edit/resizable-cover-popover.js b/packages/block-library/src/cover/edit/resizable-cover-popover.js new file mode 100644 index 00000000000000..7567da82e84362 --- /dev/null +++ b/packages/block-library/src/cover/edit/resizable-cover-popover.js @@ -0,0 +1,82 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { useMemo, useState } from '@wordpress/element'; +import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../../private-apis'; + +const RESIZABLE_BOX_ENABLE_OPTION = { + top: false, + right: false, + bottom: true, + left: false, + topRight: false, + bottomRight: false, + bottomLeft: false, + topLeft: false, +}; + +export default function ResizableCoverPopover( { + className, + height, + minHeight, + onResize, + onResizeStart, + onResizeStop, + showHandle, + size, + width, + ...props +} ) { + const { ResizableBoxPopover } = unlock( blockEditorPrivateApis ); + const [ isResizing, setIsResizing ] = useState( false ); + const dimensions = useMemo( + () => ( { height, minHeight, width } ), + [ minHeight, height, width ] + ); + + const resizableBoxProps = { + className: classnames( className, { 'is-resizing': isResizing } ), + enable: RESIZABLE_BOX_ENABLE_OPTION, + onResizeStart: ( _event, _direction, elt ) => { + onResizeStart( elt.clientHeight ); + onResize( elt.clientHeight ); + }, + onResize: ( _event, _direction, elt ) => { + onResize( elt.clientHeight ); + if ( ! isResizing ) { + setIsResizing( true ); + } + }, + onResizeStop: ( _event, _direction, elt ) => { + onResizeStop( elt.clientHeight ); + setIsResizing( false ); + }, + showHandle, + size, + __experimentalShowTooltip: true, + __experimentalTooltipProps: { + axis: 'y', + position: 'bottom', + isVisible: isResizing, + }, + }; + + return ( + + ); +} diff --git a/packages/block-library/src/cover/edit/resizable-cover.js b/packages/block-library/src/cover/edit/resizable-cover.js deleted file mode 100644 index 7029e5c997e46c..00000000000000 --- a/packages/block-library/src/cover/edit/resizable-cover.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; - -/** - * WordPress dependencies - */ -import { useState } from '@wordpress/element'; -import { ResizableBox } from '@wordpress/components'; - -const RESIZABLE_BOX_ENABLE_OPTION = { - top: false, - right: false, - bottom: true, - left: false, - topRight: false, - bottomRight: false, - bottomLeft: false, - topLeft: false, -}; - -export default function ResizableCover( { - className, - onResizeStart, - onResize, - onResizeStop, - ...props -} ) { - const [ isResizing, setIsResizing ] = useState( false ); - - return ( - { - onResizeStart( elt.clientHeight ); - onResize( elt.clientHeight ); - } } - onResize={ ( _event, _direction, elt ) => { - onResize( elt.clientHeight ); - if ( ! isResizing ) { - setIsResizing( true ); - } - } } - onResizeStop={ ( _event, _direction, elt ) => { - onResizeStop( elt.clientHeight ); - setIsResizing( false ); - } } - __experimentalShowTooltip - __experimentalTooltipProps={ { - axis: 'y', - position: 'bottom', - isVisible: isResizing, - } } - { ...props } - /> - ); -} diff --git a/packages/block-library/src/cover/editor.scss b/packages/block-library/src/cover/editor.scss index 5e8300dcada72d..dad9ba9fd1e73e 100644 --- a/packages/block-library/src/cover/editor.scss +++ b/packages/block-library/src/cover/editor.scss @@ -7,24 +7,23 @@ // Override default cover styles // because we're not ready yet to show the cover block. &.is-placeholder { - min-height: auto !important; padding: 0 !important; + display: flex; + align-items: stretch; + overflow: visible; + min-height: 240px; - // Resizable placeholder for placeholder. - .block-library-cover__resize-container { - display: none; - } .components-placeholder { &.is-large { - min-height: 240px; justify-content: flex-start; z-index: z-index(".wp-block-cover.is-placeholder .components-placeholder.is-large"); - + .block-library-cover__resize-container { - min-height: 240px; - display: block; - } } } + + // Allow focus outline/box-shadow to align with block's min height. + &:focus::after { + min-height: auto; + } } &.components-placeholder h2 { @@ -88,9 +87,17 @@ min-height: 50px; } -.block-library-cover__resize-container:not(.is-resizing) { - // Important is used to have higher specificity than the inline style set by re-resizable library. - height: auto !important; +// Prevent resizable box popover form preventing inner block selection. +.components-popover.block-editor-block-popover.block-library-cover__resizable-box-popover { + // Additional specificity is required to overcome default block popover + // pointer events only for the intended wrappers. The default pointer events + // are still needed for the inner resize handles of the resizable box. + .components-popover__content > div, + .block-library-cover__resize-container { + // The inner drag handle will still have `pointer-events: all` allowing + // it to continue to be interacted with. + pointer-events: none; + } } // When uploading background images, show a transparent overlay. diff --git a/packages/block-library/src/cover/style.scss b/packages/block-library/src/cover/style.scss index dff27609032bd1..0e24a8cff32d59 100644 --- a/packages/block-library/src/cover/style.scss +++ b/packages/block-library/src/cover/style.scss @@ -7,6 +7,7 @@ justify-content: center; align-items: center; padding: 1em; + overflow: hidden; // This block has customizable padding, border-box makes that more predictable. box-sizing: border-box; // Keep the flex layout direction to the physical direction (LTR) in RTL languages.