Skip to content

Commit

Permalink
Image block: Add support for "more" dropdown for additional tools in …
Browse files Browse the repository at this point in the history
…Write mode (#66605)

Co-authored-by: ntsekouras <[email protected]>
Co-authored-by: mcsf <[email protected]>
Co-authored-by: jasmussen <[email protected]>
Co-authored-by: t-hamano <[email protected]>
  • Loading branch information
5 people authored Nov 1, 2024
1 parent b69bca9 commit 86ca73a
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 109 deletions.
4 changes: 4 additions & 0 deletions packages/block-library/src/image/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
267 changes: 159 additions & 108 deletions packages/block-library/src/image/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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';

Expand Down Expand Up @@ -69,6 +71,10 @@ const scaleOptions = [
},
];

const WRITEMODE_POPOVER_PROPS = {
placement: 'bottom-start',
};

// If the image has a href, wrap in an <a /> tag to trigger any inherited link element styles.
const ImageWrapper = ( { href, children } ) => {
if ( ! href ) {
Expand All @@ -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 (
<>
<ToolbarItem ref={ setPopoverAnchor }>
{ ( toggleProps ) => (
<DropdownMenu
icon={ chevronDown }
/* translators: button label text should, if possible, be under 16 characters. */
label={ __( 'More' ) }
toggleProps={ {
...toggleProps,
description: __( 'Displays more controls.' ),
} }
popoverProps={ WRITEMODE_POPOVER_PROPS }
>
{ ( { onClose } ) => (
<>
<MenuItem
onClick={ () => {
setIsAltDialogOpen( true );
onClose();
} }
>
{ _x(
'Alternative text',
'Alternative text for an image. Block toolbar label, a low character count is preferred.'
) }
</MenuItem>
<MenuItem
onClick={ () => {
setIsTitleDialogOpen( true );
onClose();
} }
>
{ __( 'Title text' ) }
</MenuItem>
</>
) }
</DropdownMenu>
) }
</ToolbarItem>
{ isAltDialogOpen && (
<Popover
placement="bottom-start"
anchor={ popoverAnchor }
onClose={ () => setIsAltDialogOpen( false ) }
offset={ 13 }
variant="toolbar"
>
<div className="wp-block-image__toolbar_content_textarea__container">
<TextareaControl
className="wp-block-image__toolbar_content_textarea"
label={ __( 'Alternative text' ) }
value={ attributes.alt || '' }
onChange={ ( value ) =>
setAttributes( { alt: value } )
}
disabled={ lockAltControls }
help={
lockAltControls ? (
<>{ lockAltControlsMessage }</>
) : (
<>
<ExternalLink
href={
// translators: Localized tutorial, if one exists. W3C Web Accessibility Initiative link has list of existing translations.
__(
'https://www.w3.org/WAI/tutorials/images/decision-tree/'
)
}
>
{ __(
'Describe the purpose of the image.'
) }
</ExternalLink>
<br />
{ __( 'Leave empty if decorative.' ) }
</>
)
}
__nextHasNoMarginBottom
/>
</div>
</Popover>
) }
{ isTitleDialogOpen && (
<Popover
placement="bottom-start"
anchor={ popoverAnchor }
onClose={ () => setIsTitleDialogOpen( false ) }
offset={ 13 }
variant="toolbar"
>
<div className="wp-block-image__toolbar_content_textarea__container">
<TextControl
__next40pxDefaultSize
className="wp-block-image__toolbar_content_textarea"
__nextHasNoMarginBottom
label={ __( 'Title attribute' ) }
value={ attributes.title || '' }
onChange={ ( value ) =>
setAttributes( {
title: value,
} )
}
disabled={ lockTitleControls }
help={
lockTitleControls ? (
<>{ lockTitleControlsMessage }</>
) : (
<>
{ __(
'Describe the role of this image on the page.'
) }
<ExternalLink href="https://www.w3.org/TR/html52/dom.html#the-title-attribute">
{ __(
'(Note: many devices and browsers do not display this text.)'
) }
</ExternalLink>
</>
)
}
/>
</div>
</Popover>
) }
</>
);
}

export default function Image( {
temporaryURL,
attributes,
Expand Down Expand Up @@ -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.
<BlockControls group="other">
<Dropdown
popoverProps={ { position: 'bottom right' } }
renderToggle={ ( { isOpen, onToggle } ) => (
<ToolbarButton
onClick={ onToggle }
aria-haspopup="true"
aria-expanded={ isOpen }
onKeyDown={ ( event ) => {
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.'
) }
</ToolbarButton>
) }
renderContent={ () => (
<TextareaControl
className="wp-block-image__toolbar_content_textarea"
label={ __( 'Alternative text' ) }
value={ alt || '' }
onChange={ updateAlt }
disabled={ lockAltControls }
help={
lockAltControls ? (
<>{ lockAltControlsMessage }</>
) : (
<>
<ExternalLink
href={
// translators: Localized tutorial, if one exists. W3C Web Accessibility Initiative link has list of existing translations.
__(
'https://www.w3.org/WAI/tutorials/images/decision-tree/'
)
}
>
{ __(
'Describe the purpose of the image.'
) }
</ExternalLink>
<br />
{ __(
'Leave empty if decorative.'
) }
</>
)
}
__nextHasNoMarginBottom
/>
) }
<BlockControls group="block">
<ContentOnlyControls
attributes={ attributes }
setAttributes={ setAttributes }
lockAltControls={ lockAltControls }
lockAltControlsMessage={ lockAltControlsMessage }
lockTitleControls={ lockTitleControls }
lockTitleControlsMessage={ lockTitleControlsMessage }
/>
{ title && (
<Dropdown
popoverProps={ { position: 'bottom right' } }
renderToggle={ ( { isOpen, onToggle } ) => (
<ToolbarButton
onClick={ onToggle }
aria-haspopup="true"
aria-expanded={ isOpen }
onKeyDown={ ( event ) => {
if (
! isOpen &&
event.keyCode === DOWN
) {
event.preventDefault();
onToggle();
}
} }
>
{ __( 'Title' ) }
</ToolbarButton>
) }
renderContent={ () => (
<TextControl
__next40pxDefaultSize
className="wp-block-image__toolbar_content_textarea"
__nextHasNoMarginBottom
label={ __( 'Title attribute' ) }
value={ title || '' }
onChange={ onSetTitle }
disabled={ lockTitleControls }
help={
lockTitleControls ? (
<>{ lockTitleControlsMessage }</>
) : (
<>
{ __(
'Describe the role of this image on the page.'
) }
<ExternalLink href="https://www.w3.org/TR/html52/dom.html#the-title-attribute">
{ __(
'(Note: many devices and browsers do not display this text.)'
) }
</ExternalLink>
</>
)
}
/>
) }
/>
) }
</BlockControls>
) }
<InspectorControls>
Expand Down
5 changes: 4 additions & 1 deletion test/e2e/specs/editor/various/pattern-overrides.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' );
Expand Down

0 comments on commit 86ca73a

Please sign in to comment.