diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js
index a1b3b80b285ed6..eae1bfe610e27c 100644
--- a/packages/block-library/src/gallery/edit.js
+++ b/packages/block-library/src/gallery/edit.js
@@ -6,7 +6,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
-import { compose } from '@wordpress/compose';
+import { compose, usePrevious } from '@wordpress/compose';
import {
BaseControl,
PanelBody,
@@ -14,6 +14,7 @@ import {
ToggleControl,
RangeControl,
Spinner,
+ ToolbarButton,
} from '@wordpress/components';
import {
store as blockEditorStore,
@@ -24,7 +25,13 @@ import {
BlockControls,
MediaReplaceFlow,
} from '@wordpress/block-editor';
-import { Platform, useEffect, useMemo } from '@wordpress/element';
+import {
+ Platform,
+ useCallback,
+ useEffect,
+ useState,
+ useMemo,
+} from '@wordpress/element';
import { __, _x, sprintf } from '@wordpress/i18n';
import { useSelect, useDispatch } from '@wordpress/data';
import { withViewportMatch } from '@wordpress/viewport';
@@ -32,6 +39,7 @@ import { View } from '@wordpress/primitives';
import { createBlock } from '@wordpress/blocks';
import { createBlobURL } from '@wordpress/blob';
import { store as noticesStore } from '@wordpress/notices';
+import { caption as captionIcon } from '@wordpress/icons';
/**
* Internal dependencies
@@ -83,9 +91,37 @@ function GalleryEdit( props ) {
clientId,
isSelected,
insertBlocksAfter,
+ isContentLocked,
} = props;
- const { columns, imageCrop, linkTarget, linkTo, sizeSlug } = attributes;
+ const { columns, imageCrop, linkTarget, linkTo, sizeSlug, caption } =
+ attributes;
+ const [ showCaption, setShowCaption ] = useState( !! caption );
+ const prevCaption = usePrevious( caption );
+
+ // We need to show the caption when changes come from
+ // history navigation(undo/redo).
+ useEffect( () => {
+ if ( caption && ! prevCaption ) {
+ setShowCaption( true );
+ }
+ }, [ caption, prevCaption ] );
+
+ useEffect( () => {
+ if ( ! isSelected && ! caption ) {
+ setShowCaption( false );
+ }
+ }, [ isSelected, caption ] );
+
+ // Focus the caption when we click to add one.
+ const captionRef = useCallback(
+ ( node ) => {
+ if ( node && ! caption ) {
+ node.focus();
+ }
+ },
+ [ caption ]
+ );
const {
__unstableMarkNextChangeAsNotPersistent,
@@ -574,6 +610,25 @@ function GalleryEdit( props ) {
) }
+
+ { ! isContentLocked && (
+ {
+ setShowCaption( ! showCaption );
+ if ( showCaption && caption ) {
+ setAttributes( { caption: undefined } );
+ }
+ } }
+ icon={ captionIcon }
+ isPressed={ showCaption }
+ label={
+ showCaption
+ ? __( 'Remove caption' )
+ : __( 'Add caption' )
+ }
+ />
+ ) }
+
{
+export const Gallery = ( props, captionRef ) => {
const {
attributes,
isSelected,
@@ -24,6 +24,7 @@ export const Gallery = ( props ) => {
insertBlocksAfter,
blockProps,
__unstableLayoutClassNames: layoutClassNames,
+ showCaption,
} = props;
const { align, columns, caption, imageCrop } = attributes;
@@ -49,50 +50,32 @@ export const Gallery = ( props ) => {
{ mediaPlaceholder }
) }
-
+ setAttributes( { caption: value } )
+ }
+ inlineToolbar
+ __unstableOnSplitAtEnd={ () =>
+ insertBlocksAfter(
+ createBlock( getDefaultBlockName() )
+ )
+ }
+ />
) }
- aria-label={ __( 'Gallery caption text' ) }
- placeholder={ __( 'Write gallery caption…' ) }
- value={ caption }
- onChange={ ( value ) => setAttributes( { caption: value } ) }
- inlineToolbar
- __unstableOnSplitAtEnd={ () =>
- insertBlocksAfter( createBlock( getDefaultBlockName() ) )
- }
- />
);
};
-function RichTextVisibilityHelper( {
- isHidden,
- className,
- value,
- placeholder,
- tagName,
- captionRef,
- ...richTextProps
-} ) {
- if ( isHidden ) {
- return ;
- }
-
- return (
-
- );
-}
-
-export default Gallery;
+export default forwardRef( Gallery );
diff --git a/test/e2e/specs/editor/blocks/gallery.spec.js b/test/e2e/specs/editor/blocks/gallery.spec.js
index 936942c9688fa5..3881c31d5b8601 100644
--- a/test/e2e/specs/editor/blocks/gallery.spec.js
+++ b/test/e2e/specs/editor/blocks/gallery.spec.js
@@ -136,12 +136,12 @@ test.describe( 'Gallery', () => {
await expect( gallery ).toBeVisible();
await editor.selectBlocks( gallery );
+ await editor.clickBlockToolbarButton( 'Add caption' );
const caption = gallery.locator(
'role=textbox[name="Gallery caption text"i]'
);
- await expect( caption ).toBeVisible();
- await caption.click();
+ await expect( caption ).toBeFocused();
await page.keyboard.type( galleryCaption );