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

Try to make the inline toolbars navigable toolbars and make Alt+F10 work #6302

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
9 changes: 7 additions & 2 deletions blocks/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { Component, Fragment, compose } from '@wordpress/element';
import { keycodes, createBlobURL, isHorizontalEdge, getRectangleFromRange, getScrollContainer } from '@wordpress/utils';
import { withSafeTimeout, Slot } from '@wordpress/components';
import { withSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
Expand All @@ -37,6 +38,7 @@ import patterns from './patterns';
import { EVENTS } from './constants';
import { withBlockEditContext } from '../block-edit/context';
import { domToFormat, valueToString, isEmpty } from './format';
import NavigableToolbar from '../../editor/components/navigable-toolbar';

const { BACKSPACE, DELETE, ENTER } = keycodes;

Expand Down Expand Up @@ -822,9 +824,12 @@ export class RichText extends Component {
</BlockFormatControls>
) }
{ isSelected && inlineToolbar && (
<div className="block-rich-text__inline-toolbar">
<NavigableToolbar
className="block-rich-text__inline-toolbar"
aria-label={ __( 'Block secondary controls' ) }
>
{ formatToolbar }
</div>
</NavigableToolbar>
) }
<Autocomplete onReplace={ this.props.onReplace } completers={ autocompleters }>
{ ( { isExpanded, listBoxId, activeId } ) => (
Expand Down
2 changes: 1 addition & 1 deletion editor/components/block-list/block-contextual-toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function BlockContextualToolbar() {
return (
<NavigableToolbar
className="editor-block-contextual-toolbar"
aria-label={ __( 'Block Toolbar' ) }
aria-label={ __( 'Block controls' ) }
>
<BlockToolbar />
</NavigableToolbar>
Expand Down
52 changes: 37 additions & 15 deletions editor/components/navigable-toolbar/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
/**
* External dependencies
*/
import { cond, matchesProperty } from 'lodash';
import { cond, matchesProperty, omit } from 'lodash';

/**
* WordPress dependencies
*/
import { NavigableMenu, KeyboardShortcuts } from '@wordpress/components';
import { Component, findDOMNode } from '@wordpress/element';
import { Component, findDOMNode, createRef } from '@wordpress/element';
import { focus, keycodes } from '@wordpress/utils';
import { withSelect } from '@wordpress/data';

/**
* Internal Dependencies
*/
import { getBlockFocusableWrapper } from '../../utils/dom';

/**
* Browser dependencies
Expand All @@ -25,7 +31,7 @@ class NavigableToolbar extends Component {
constructor() {
super( ...arguments );

this.bindNode = this.bindNode.bind( this );
this.toolbar = createRef();
this.focusToolbar = this.focusToolbar.bind( this );
this.focusSelection = this.focusSelection.bind( this );

Expand All @@ -34,15 +40,13 @@ class NavigableToolbar extends Component {
] );
}

bindNode( ref ) {
focusToolbar() {
// Disable reason: Need DOM node for finding first focusable element
// on keyboard interaction to shift to toolbar.
// eslint-disable-next-line react/no-find-dom-node
this.toolbar = findDOMNode( ref );
}
const toolbar = findDOMNode( this.toolbar.current );

focusToolbar() {
const tabbables = focus.tabbable.find( this.toolbar );
const tabbables = focus.tabbable.find( toolbar );
if ( tabbables.length ) {
tabbables[ 0 ].focus();
}
Expand All @@ -55,15 +59,28 @@ class NavigableToolbar extends Component {
focusSelection() {
// Ensure that a selection exists.
const selection = getSelection();
if ( ! selection ) {
if ( ! selection || ! selection.focusNode ) {
return;
}

// Focus node may be a text node, which cannot be focused directly.
// Find its parent element instead.
const { focusNode } = selection;
const { selectedBlockUID } = this.props;
const selectedBlockFocusableWrapper = getBlockFocusableWrapper( selectedBlockUID );
let focusElement = focusNode;
if ( focusElement.nodeType !== Node.ELEMENT_NODE ) {

/*
* Not all blocks have editable fields that can have a selection, or they
* can have both editable fields and other UI parts that can't have a selection.
* In these cases the current selection could be the one from another block.
* Move focus back to the selected block wrapper.
*/
if ( ! selectedBlockFocusableWrapper.contains( focusNode ) ) {
focusElement = selectedBlockFocusableWrapper;
} else if ( focusElement.nodeType !== Node.ELEMENT_NODE ) {
/*
* Focus node may be a text node, which cannot be focused directly.
* Find its parent element instead.
*/
focusElement = focusElement.parentElement;
}

Expand All @@ -73,13 +90,14 @@ class NavigableToolbar extends Component {
}

render() {
const { children, ...props } = this.props;
const { children, ...props } = omit( this.props, 'selectedBlockUID' );

return (
<NavigableMenu
orientation="horizontal"
role="toolbar"
deep
ref={ this.bindNode }
ref={ this.toolbar }
onKeyDown={ this.switchOnKeyDown }
{ ...props }
>
Expand All @@ -97,4 +115,8 @@ class NavigableToolbar extends Component {
}
}

export default NavigableToolbar;
export default withSelect( ( select ) => {
return {
selectedBlockUID: select( 'core/editor' ).getBlockSelectionStart(),
};
} )( NavigableToolbar );