Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix inline block toolbar keyboard navigation #28420

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
/**
* WordPress dependencies
*/
import { Popover } from '@wordpress/components';
import { Popover, Toolbar } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import BlockFormatControls from '../block-format-controls';
import FormatToolbar from './format-toolbar';

const FormatToolbarContainer = ( { inline, anchorRef } ) => {
const FormatToolbarContainer = ( {
inline,
anchorRef,
label = __( 'Format' ),
} ) => {
if ( inline ) {
// Render in popover
return (
Expand All @@ -19,9 +24,12 @@ const FormatToolbarContainer = ( { inline, anchorRef } ) => {
focusOnMount={ false }
anchorRef={ anchorRef }
className="block-editor-rich-text__inline-format-toolbar"
__unstableSlotName="block-toolbar"
// Render inline
__unstableSlotName={ null }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm passing null to the slot name so it renders inline in the React tree, and not on a separate slot as it won't find any slot:

if ( slot.ref ) {
content = <Fill name={ __unstableSlotName }>{ content }</Fill>;
}
if ( anchorRef || anchorRect ) {
return content;
}
return <span ref={ anchorRefFallback }>{ content }</span>;

I don't know if there's a better way to achieve this, but I think we could have an inline prop or something on Popover.

>
<FormatToolbar />
<Toolbar label={ label }>
<FormatToolbar />
</Toolbar>
</Popover>
);
}
Expand Down
2 changes: 2 additions & 0 deletions packages/block-editor/src/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ function RichTextWrapper(
isSelected: originalIsSelected,
multiline,
inlineToolbar,
__experimentalInlineToolbarLabel: inlineToolbarLabel,
wrapperClassName,
autocompleters,
onReplace,
Expand Down Expand Up @@ -628,6 +629,7 @@ function RichTextWrapper(
{ children && children( { value, onChange, onFocus } ) }
{ nestedIsSelected && hasFormats && (
<FormatToolbarContainer
label={ inlineToolbarLabel }
inline={ inlineToolbar }
anchorRef={ ref.current }
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ figcaption.block-editor-rich-text__editable [data-rich-text-placeholder]::before
background-color: $white;
}

.components-accessible-toolbar,
.components-toolbar-group,
.components-toolbar {
// The popover already provides a border.
Expand Down
3 changes: 3 additions & 0 deletions packages/block-library/src/audio/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ function AudioEdit( {
setAttributes( { caption: value } )
}
inlineToolbar
__experimentalInlineToolbarLabel={ __(
'Audio caption format'
) }
__unstableOnSplitAtEnd={ () =>
insertBlocksAfter( createBlock( 'core/paragraph' ) )
}
Expand Down
3 changes: 3 additions & 0 deletions packages/block-library/src/embed/embed-preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ class EmbedPreview extends Component {
value={ caption }
onChange={ onCaptionChange }
inlineToolbar
__experimentalInlineToolbarLabel={ __(
'Caption format'
) }
__unstableOnSplitAtEnd={ () =>
insertBlocksAfter( createBlock( 'core/paragraph' ) )
}
Expand Down
3 changes: 3 additions & 0 deletions packages/block-library/src/gallery/gallery-image.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ class GalleryImage extends Component {
}
unstableOnFocus={ this.onSelectCaption }
inlineToolbar
__experimentalInlineToolbarLabel={ __(
'Image caption format'
) }
/>
) }
</figure>
Expand Down
3 changes: 3 additions & 0 deletions packages/block-library/src/gallery/gallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ export const Gallery = ( props ) => {
unstableOnFocus={ onFocusGalleryCaption }
onChange={ ( value ) => setAttributes( { caption: value } ) }
inlineToolbar
__experimentalInlineToolbarLabel={ __(
'Gallery caption format'
) }
__unstableOnSplitAtEnd={ () =>
insertBlocksAfter( createBlock( 'core/paragraph' ) )
}
Expand Down
3 changes: 3 additions & 0 deletions packages/block-library/src/image/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,9 @@ export default function Image( {
}
isSelected={ captionFocused }
inlineToolbar
__experimentalInlineToolbarLabel={ __(
'Image caption format'
) }
__unstableOnSplitAtEnd={ () =>
insertBlocksAfter( createBlock( 'core/paragraph' ) )
}
Expand Down
3 changes: 3 additions & 0 deletions packages/block-library/src/video/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ function VideoEdit( {
setAttributes( { caption: value } )
}
inlineToolbar
__experimentalInlineToolbarLabel={ __(
'Video caption format'
) }
__unstableOnSplitAtEnd={ () =>
insertBlocksAfter( createBlock( 'core/paragraph' ) )
}
Expand Down
30 changes: 30 additions & 0 deletions packages/e2e-tests/specs/editor/blocks/image.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,4 +288,34 @@ describe( 'Image', () => {
expect( initialImageDataURL ).not.toEqual( updatedImageDataURL );
expect( updatedImageDataURL ).toMatchSnapshot();
} );

it( 'allows navigating through inline and block toolbars with keyboard', async () => {
await insertBlock( 'Image' );
const fileName = await upload( '.wp-block-image input[type="file"]' );
await waitForImage( fileName );

await pressKeyWithModifier( 'shift', 'Tab' );

await expect(
await page.evaluate( () =>
document.activeElement.getAttribute( 'aria-label' )
)
).toBe( 'Bold' );

await pressKeyWithModifier( 'shift', 'Tab' );

await expect(
await page.evaluate( () =>
document.activeElement.getAttribute( 'aria-label' )
)
).toBe( 'Block: Image' );

await pressKeyWithModifier( 'shift', 'Tab' );

await expect(
await page.evaluate( () =>
document.activeElement.getAttribute( 'aria-label' )
)
).toBe( 'Image' );
} );
} );