diff --git a/packages/block-editor/src/components/global-styles/background-panel.js b/packages/block-editor/src/components/global-styles/background-panel.js index 307c742befafda..0af1ae06757331 100644 --- a/packages/block-editor/src/components/global-styles/background-panel.js +++ b/packages/block-editor/src/components/global-styles/background-panel.js @@ -22,14 +22,17 @@ import { __experimentalItemGroup as ItemGroup, __experimentalHStack as HStack, __experimentalTruncate as Truncate, + Dropdown, + __experimentalDropdownContentWrapper as DropdownContentWrapper, } from '@wordpress/components'; import { __, _x, sprintf } from '@wordpress/i18n'; import { store as noticesStore } from '@wordpress/notices'; import { getFilename } from '@wordpress/url'; -import { useCallback, Platform, useRef } from '@wordpress/element'; +import { useCallback, Platform, useRef, useState } from '@wordpress/element'; import { useDispatch, useSelect } from '@wordpress/data'; import { focus } from '@wordpress/dom'; import { isBlobURL } from '@wordpress/blob'; +import { reusableBlock, Icon } from '@wordpress/icons'; /** * Internal dependencies @@ -43,7 +46,12 @@ import { getResolvedThemeFilePath } from './theme-file-uri-utils'; const IMAGE_BACKGROUND_TYPE = 'image'; const DEFAULT_CONTROLS = { backgroundImage: true, - backgroundSize: false, + backgroundSize: true, +}; +const BACKGROUND_POPOVER_PROPS = { + placement: 'left-start', + offset: 36, + shift: true, }; /** @@ -141,44 +149,52 @@ export const backgroundPositionToCoords = ( value ) => { return { x, y }; }; -function InspectorImagePreview( { label, filename, url: imgUrl } ) { - const imgLabel = - label || getFilename( imgUrl ) || __( 'Add background image' ); - +function InspectorImagePreviewItem( { + as = 'span', + imgUrl, + toggleProps = {}, + filename, + label, + className, +} ) { return ( - - - { imgUrl && ( - + + + + { imgUrl && ( - - ) } + ) } + - { imgLabel } + { label } { imgUrl ? sprintf( /* translators: %s: file name */ __( 'Background image: %s' ), - filename || imgLabel + filename || label ) : __( 'No background image selected' ) } @@ -188,13 +204,77 @@ function InspectorImagePreview( { label, filename, url: imgUrl } ) { ); } +const noop = () => {}; + +function InspectorImagePreviewToggle( { + label, + filename, + url: imgUrl, + children, + allowPopover = false, + onToggle: onToggleCallback = noop, + hasImageValue, +} ) { + if ( ! hasImageValue ) { + return; + } + + const imgLabel = + label || getFilename( imgUrl ) || __( 'Add background image' ); + + if ( ! allowPopover ) { + return ( + + ); + } + return ( + { + const toggleProps = { + onClick: onToggle, + className: + 'block-editor-global-styles-background-panel__dropdown-toggle', + 'aria-expanded': isOpen, + 'aria-label': __( + 'Background size, position and repeat options.' + ), + }; + onToggleCallback( isOpen ); + return ( + + ); + } } + renderContent={ () => ( + + { children } + + ) } + /> + ); +} + function BackgroundImageToolsPanelItem( { panelId, isShownByDefault, onChange, style, inheritedValue, - themeFileURIs, } ) { const mediaUpload = useSelect( ( select ) => select( blockEditorStore ).getSettings().mediaUpload, @@ -204,9 +284,10 @@ function BackgroundImageToolsPanelItem( { const { id, title, url } = style?.background?.backgroundImage || { ...inheritedValue?.background?.backgroundImage, }; - + const hasImageValue = + hasBackgroundImageValue( style ) || + hasBackgroundImageValue( inheritedValue ); const replaceContainerRef = useRef(); - const { createErrorNotice } = useDispatch( noticesStore ); const onUploadError = ( message ) => { createErrorNotice( message, { type: 'snackbar' } ); @@ -307,7 +388,8 @@ function BackgroundImageToolsPanelItem( { setImmutably( style, [ 'background', 'backgroundImage' ], 'none' ) ); const canRemove = ! hasValue && hasBackgroundImageValue( inheritedValue ); - + const imgLabel = + title || getFilename( url ) || __( 'Add background image' ); return ( -
+
+ hasImageValue ? ( + + ) : ( + + ) } variant="secondary" > @@ -371,8 +452,6 @@ function BackgroundImageToolsPanelItem( { } function BackgroundSizeToolsPanelItem( { - panelId, - isShownByDefault, onChange, style, inheritedValue, @@ -417,22 +496,6 @@ function BackgroundSizeToolsPanelItem( { ( currentValueForToggle === 'cover' && repeatValue === undefined ) ); - const hasValue = hasBackgroundSizeValue( style ); - - const resetAllFilter = useCallback( ( previousValue ) => { - return { - ...previousValue, - style: { - ...previousValue.style, - background: { - ...previousValue.style?.background, - backgroundRepeat: undefined, - backgroundSize: undefined, - }, - }, - }; - }, [] ); - const updateBackgroundSize = ( next ) => { // When switching to 'contain' toggle the repeat off. let nextRepeat = repeatValue; @@ -502,30 +565,11 @@ function BackgroundSizeToolsPanelItem( { ) ); - const resetBackgroundSize = () => - onChange( - setImmutably( style, [ 'background' ], { - ...style?.background, - backgroundPosition: undefined, - backgroundRepeat: undefined, - backgroundSize: undefined, - } ) - ); - return ( - hasValue } - label={ __( 'Size' ) } - onDeselect={ resetBackgroundSize } - isShownByDefault={ isShownByDefault } - resetAllFilter={ resetAllFilter } - panelId={ panelId } - > + + onChange( + setImmutably( value, [ 'background' ], { + ...value?.background, + backgroundPosition: undefined, + backgroundRepeat: undefined, + backgroundSize: undefined, + } ) + ); + //@TODO This causes "Cannot update a component while rendering a different component (`Dropdown`)" error + const [ isDropDownOpen, setIsDropDownOpen ] = useState( false ); return ( - - { shouldShowBackgroundSizeControls && ( - + setIsDropDownOpen( isOpen ) } + hasImageValue={ hasImageValue } + > + + + - ) } +
+ + { /* Dummy ToolsPanel items, so we can control what's in the dropdown popover */ } + hasSizeValue } + label={ __( 'Size' ) } + onDeselect={ resetBackgroundSize } + isShownByDefault={ defaultControls.backgroundImage } + panelId={ panelId } + className="block-editor-global-styles-background-panel__hidden-tools-panel-item" + /> ); } diff --git a/packages/block-editor/src/components/global-styles/style.scss b/packages/block-editor/src/components/global-styles/style.scss index 1630ac2abde574..cfd114ab9f649c 100644 --- a/packages/block-editor/src/components/global-styles/style.scss +++ b/packages/block-editor/src/components/global-styles/style.scss @@ -73,6 +73,40 @@ .block-editor-global-styles-background-panel__inspector-media-replace-container { position: relative; + border: 1px solid $gray-300; + border-radius: 2px; + display: flex; + justify-content: center; + align-items: stretch; + // Full width. ToolsPanel lays out children in a grid. + grid-column: 1 / -1; + + &.is-open { + background-color: $gray-100; + } + + .block-editor-global-styles-background-panel__inspector-preview-inner { + height: 100%; + } + + .block-editor-global-styles-background-panel__image-preview, + .block-editor-global-styles-background-panel__inspector-media-replace { + flex-grow: 1; + } + + .block-editor-global-styles-background-panel__image-preview-content, + .block-editor-global-styles-background-panel__dropdown-toggle { + height: 100%; + width: 100%; + padding-left: $grid-unit-15; + } + + .block-editor-global-styles-background-panel__dropdown-toggle { + cursor: pointer; + background: transparent; + border: none; + } + // Since there is no option to skip rendering the drag'n'drop icon in drop // zone, we hide it for now. .components-drop-zone__content-icon { @@ -84,7 +118,6 @@ box-shadow: inset 0 0 0 $border-width $gray-400; width: 100%; display: block; - height: $grid-unit-50; &:hover { color: var(--wp-admin-theme-color); @@ -111,11 +144,8 @@ } .block-editor-global-styles-background-panel__inspector-image-indicator-wrapper { - display: block; width: 20px; height: 20px; - flex: none; - background: #fff; } .block-editor-global-styles-background-panel__inspector-image-indicator { @@ -141,3 +171,16 @@ box-sizing: inherit; } +.block-editor-global-styles-background-panel__dropdown-content-wrapper { + min-width: 260px; + .components-base-control__help, + .components-toggle-control { + margin-bottom: 0; + } +} + +.block-editor-global-styles-background-panel__hidden-tools-panel-item { + height: 0px; + position: absolute; + width: 0px; +} diff --git a/packages/block-editor/src/hooks/background.js b/packages/block-editor/src/hooks/background.js index 3e23efcbf5fc96..2178eb9a8ea8b3 100644 --- a/packages/block-editor/src/hooks/background.js +++ b/packages/block-editor/src/hooks/background.js @@ -147,10 +147,12 @@ export function BackgroundImagePanel( { return null; } + /* const defaultControls = getBlockSupport( name, [ BACKGROUND_SUPPORT_KEY, '__experimentalDefaultControls', ] ); +*/ const onChange = ( newStyle ) => { setAttributes( { @@ -172,7 +174,9 @@ export function BackgroundImagePanel( {