From 86ca73a86541f0a1a16e30a906ebed3ba2ad66d2 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Fri, 1 Nov 2024 13:38:11 +0200 Subject: [PATCH] Image block: Add support for "more" dropdown for additional tools in Write mode (#66605) Co-authored-by: ntsekouras Co-authored-by: mcsf Co-authored-by: jasmussen Co-authored-by: t-hamano --- packages/block-library/src/image/editor.scss | 4 + packages/block-library/src/image/image.js | 267 +++++++++++------- .../editor/various/pattern-overrides.spec.js | 5 +- 3 files changed, 167 insertions(+), 109 deletions(-) diff --git a/packages/block-library/src/image/editor.scss b/packages/block-library/src/image/editor.scss index 34f65d690d3d7..35b05a063c299 100644 --- a/packages/block-library/src/image/editor.scss +++ b/packages/block-library/src/image/editor.scss @@ -159,6 +159,10 @@ figure.wp-block-image:not(.wp-block) { } } +.wp-block-image__toolbar_content_textarea__container { + padding: $grid-unit; +} + .wp-block-image__toolbar_content_textarea { // Corresponds to the size of the textarea in the block inspector. width: 250px; diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 89bf31f92664b..a8d6595163552 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -10,11 +10,14 @@ import { TextControl, ToolbarButton, ToolbarGroup, - Dropdown, __experimentalToolsPanel as ToolsPanel, __experimentalToolsPanelItem as ToolsPanelItem, __experimentalUseCustomUnits as useCustomUnits, Placeholder, + MenuItem, + ToolbarItem, + DropdownMenu, + Popover, } from '@wordpress/components'; import { useViewportMatch } from '@wordpress/compose'; import { useSelect, useDispatch } from '@wordpress/data'; @@ -32,10 +35,9 @@ import { } from '@wordpress/block-editor'; import { useEffect, useMemo, useState, useRef } from '@wordpress/element'; import { __, _x, sprintf, isRTL } from '@wordpress/i18n'; -import { DOWN } from '@wordpress/keycodes'; import { getFilename } from '@wordpress/url'; import { getBlockBindingsSource, switchToBlockType } from '@wordpress/blocks'; -import { crop, overlayText, upload } from '@wordpress/icons'; +import { crop, overlayText, upload, chevronDown } from '@wordpress/icons'; import { store as noticesStore } from '@wordpress/notices'; import { store as coreStore } from '@wordpress/core-data'; @@ -69,6 +71,10 @@ const scaleOptions = [ }, ]; +const WRITEMODE_POPOVER_PROPS = { + placement: 'bottom-start', +}; + // If the image has a href, wrap in an tag to trigger any inherited link element styles. const ImageWrapper = ( { href, children } ) => { if ( ! href ) { @@ -94,6 +100,148 @@ const ImageWrapper = ( { href, children } ) => { ); }; +function ContentOnlyControls( { + attributes, + setAttributes, + lockAltControls, + lockAltControlsMessage, + lockTitleControls, + lockTitleControlsMessage, +} ) { + // Use internal state instead of a ref to make sure that the component + // re-renders when the popover's anchor updates. + const [ popoverAnchor, setPopoverAnchor ] = useState( null ); + const [ isAltDialogOpen, setIsAltDialogOpen ] = useState( false ); + const [ isTitleDialogOpen, setIsTitleDialogOpen ] = useState( false ); + return ( + <> + + { ( toggleProps ) => ( + + { ( { onClose } ) => ( + <> + { + setIsAltDialogOpen( true ); + onClose(); + } } + > + { _x( + 'Alternative text', + 'Alternative text for an image. Block toolbar label, a low character count is preferred.' + ) } + + { + setIsTitleDialogOpen( true ); + onClose(); + } } + > + { __( 'Title text' ) } + + + ) } + + ) } + + { isAltDialogOpen && ( + setIsAltDialogOpen( false ) } + offset={ 13 } + variant="toolbar" + > +
+ + setAttributes( { alt: value } ) + } + disabled={ lockAltControls } + help={ + lockAltControls ? ( + <>{ lockAltControlsMessage } + ) : ( + <> + + { __( + 'Describe the purpose of the image.' + ) } + +
+ { __( 'Leave empty if decorative.' ) } + + ) + } + __nextHasNoMarginBottom + /> +
+
+ ) } + { isTitleDialogOpen && ( + setIsTitleDialogOpen( false ) } + offset={ 13 } + variant="toolbar" + > +
+ + setAttributes( { + title: value, + } ) + } + disabled={ lockTitleControls } + help={ + lockTitleControls ? ( + <>{ lockTitleControlsMessage } + ) : ( + <> + { __( + 'Describe the role of this image on the page.' + ) } + + { __( + '(Note: many devices and browsers do not display this text.)' + ) } + + + ) + } + /> +
+
+ ) } + + ); +} + export default function Image( { temporaryURL, attributes, @@ -625,112 +773,15 @@ export default function Image( { // Add some extra controls for content attributes when content only mode is active. // With content only mode active, the inspector is hidden, so users need another way // to edit these attributes. - - ( - { - if ( ! isOpen && event.keyCode === DOWN ) { - event.preventDefault(); - onToggle(); - } - } } - > - { _x( - 'Alternative text', - 'Alternative text for an image. Block toolbar label, a low character count is preferred.' - ) } - - ) } - renderContent={ () => ( - { lockAltControlsMessage } - ) : ( - <> - - { __( - 'Describe the purpose of the image.' - ) } - -
- { __( - 'Leave empty if decorative.' - ) } - - ) - } - __nextHasNoMarginBottom - /> - ) } + + - { title && ( - ( - { - if ( - ! isOpen && - event.keyCode === DOWN - ) { - event.preventDefault(); - onToggle(); - } - } } - > - { __( 'Title' ) } - - ) } - renderContent={ () => ( - { lockTitleControlsMessage } - ) : ( - <> - { __( - 'Describe the role of this image on the page.' - ) } - - { __( - '(Note: many devices and browsers do not display this text.)' - ) } - - - ) - } - /> - ) } - /> - ) } ) } diff --git a/test/e2e/specs/editor/various/pattern-overrides.spec.js b/test/e2e/specs/editor/various/pattern-overrides.spec.js index 5fbd0e66b5fd0..6f4a592930052 100644 --- a/test/e2e/specs/editor/various/pattern-overrides.spec.js +++ b/test/e2e/specs/editor/various/pattern-overrides.spec.js @@ -1131,7 +1131,10 @@ test.describe( 'Pattern Overrides', () => { /\/wp-content\/uploads\// ); await editor.showBlockToolbar(); - await editor.clickBlockToolbarButton( 'Alternative text' ); + await editor.clickBlockToolbarButton( 'More' ); + await page + .getByRole( 'menuitem', { name: 'Alternative text' } ) + .click(); await page .getByRole( 'textbox', { name: 'alternative text' } ) .fill( 'Test Image' );