Skip to content

Commit

Permalink
Implement roving tabindex on the header toolbar (#22354)
Browse files Browse the repository at this point in the history
* Implement roving tabindex on the top toolbar

* Update header toolbar styles

* Refactor block navigation dropdown code

* Refactor header toolbar code

* Update inserter is-pressed styles

* Make tool selector unavailable on the header toolbar component

* Support as prop on ToolbarItem
  • Loading branch information
diegohaz committed Jun 8, 2020
1 parent 47cba86 commit 05509fe
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 31 deletions.
26 changes: 20 additions & 6 deletions packages/block-editor/src/components/block-navigation/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Button, Dropdown, SVG, Path } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { useShortcut } from '@wordpress/keyboard-shortcuts';
import { useCallback } from '@wordpress/element';
import { useCallback, forwardRef } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -23,7 +23,13 @@ const MenuIcon = (
</SVG>
);

function BlockNavigationDropdownToggle( { isEnabled, onToggle, isOpen } ) {
function BlockNavigationDropdownToggle( {
isEnabled,
onToggle,
isOpen,
innerRef,
...props
} ) {
useShortcut(
'core/edit-post/toggle-block-navigation',
useCallback( onToggle, [ onToggle ] ),
Expand All @@ -42,6 +48,8 @@ function BlockNavigationDropdownToggle( { isEnabled, onToggle, isOpen } ) {

return (
<Button
{ ...props }
ref={ innerRef }
icon={ MenuIcon }
aria-expanded={ isOpen }
onClick={ isEnabled ? onToggle : undefined }
Expand All @@ -53,7 +61,10 @@ function BlockNavigationDropdownToggle( { isEnabled, onToggle, isOpen } ) {
);
}

function BlockNavigationDropdown( { isDisabled, __experimentalFeatures } ) {
function BlockNavigationDropdown(
{ isDisabled, __experimentalFeatures, ...props },
ref
) {
const hasBlocks = useSelect(
( select ) => !! select( 'core/block-editor' ).getBlockCount(),
[]
Expand All @@ -64,9 +75,12 @@ function BlockNavigationDropdown( { isDisabled, __experimentalFeatures } ) {
<Dropdown
contentClassName="block-editor-block-navigation__popover"
position="bottom right"
renderToggle={ ( toggleProps ) => (
renderToggle={ ( { isOpen, onToggle } ) => (
<BlockNavigationDropdownToggle
{ ...toggleProps }
{ ...props }
innerRef={ ref }
isOpen={ isOpen }
onToggle={ onToggle }
isEnabled={ isEnabled }
/>
) }
Expand All @@ -80,4 +94,4 @@ function BlockNavigationDropdown( { isDisabled, __experimentalFeatures } ) {
);
}

export default BlockNavigationDropdown;
export default forwardRef( BlockNavigationDropdown );
12 changes: 5 additions & 7 deletions packages/block-editor/src/components/tool-selector/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useSelect, useDispatch } from '@wordpress/data';
import { useViewportMatch } from '@wordpress/compose';
import { forwardRef } from '@wordpress/element';

const editIcon = (
<SVG
Expand All @@ -34,16 +34,12 @@ const selectIcon = (
</SVG>
);

function ToolSelector() {
function ToolSelector( props, ref ) {
const isNavigationTool = useSelect(
( select ) => select( 'core/block-editor' ).isNavigationMode(),
[]
);
const { setNavigationMode } = useDispatch( 'core/block-editor' );
const isMediumViewport = useViewportMatch( 'medium' );
if ( ! isMediumViewport ) {
return null;
}

const onSwitchMode = ( mode ) => {
setNavigationMode( mode === 'edit' ? false : true );
Expand All @@ -53,6 +49,8 @@ function ToolSelector() {
<Dropdown
renderToggle={ ( { isOpen, onToggle } ) => (
<Button
{ ...props }
ref={ ref }
icon={ isNavigationTool ? selectIcon : editIcon }
aria-expanded={ isOpen }
onClick={ onToggle }
Expand Down Expand Up @@ -99,4 +97,4 @@ function ToolSelector() {
);
}

export default ToolSelector;
export default forwardRef( ToolSelector );
15 changes: 11 additions & 4 deletions packages/components/src/toolbar-item/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,31 @@ import warning from '@wordpress/warning';
*/
import ToolbarContext from '../toolbar-context';

function ToolbarItem( { children, ...props }, ref ) {
function ToolbarItem( { children, as: Component, ...props }, ref ) {
const accessibleToolbarState = useContext( ToolbarContext );

if ( typeof children !== 'function' ) {
if ( typeof children !== 'function' && ! Component ) {
warning(
'`ToolbarItem` is a generic headless component that accepts only function children props'
'`ToolbarItem` is a generic headless component. You must pass either a `children` prop as a function or an `as` prop as a component.'
);
return null;
}

const allProps = { ...props, ref, 'data-experimental-toolbar-item': true };

if ( ! accessibleToolbarState ) {
if ( Component ) {
return <Component { ...allProps }>{ children }</Component>;
}
return children( allProps );
}

return (
<BaseToolbarItem { ...accessibleToolbarState } { ...allProps }>
<BaseToolbarItem
{ ...accessibleToolbarState }
{ ...allProps }
as={ Component }
>
{ children }
</BaseToolbarItem>
);
Expand Down
24 changes: 17 additions & 7 deletions packages/edit-post/src/components/header/header-toolbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import {
EditorHistoryRedo,
EditorHistoryUndo,
} from '@wordpress/editor';
import { Button } from '@wordpress/components';
import {
Button,
__experimentalToolbarItem as ToolbarItem,
} from '@wordpress/components';
import { plus } from '@wordpress/icons';

function HeaderToolbar( { onToggleInserter, isInserterOpen } ) {
Expand Down Expand Up @@ -65,7 +68,8 @@ function HeaderToolbar( { onToggleInserter, isInserterOpen } ) {
className="edit-post-header-toolbar"
aria-label={ toolbarAriaLabel }
>
<Button
<ToolbarItem
as={ Button }
className="edit-post-header-toolbar__inserter-toggle"
isPrimary
isPressed={ isInserterOpen }
Expand All @@ -77,11 +81,17 @@ function HeaderToolbar( { onToggleInserter, isInserterOpen } ) {
'Generic label for block inserter button'
) }
/>
<ToolSelector />
<EditorHistoryUndo />
<EditorHistoryRedo />
<TableOfContents hasOutlineItemsDisabled={ isTextModeEnabled } />
<BlockNavigationDropdown isDisabled={ isTextModeEnabled } />
{ isLargeViewport && <ToolbarItem as={ ToolSelector } /> }
<ToolbarItem as={ EditorHistoryUndo } />
<ToolbarItem as={ EditorHistoryRedo } />
<ToolbarItem
as={ TableOfContents }
hasOutlineItemsDisabled={ isTextModeEnabled }
/>
<ToolbarItem
as={ BlockNavigationDropdown }
isDisabled={ isTextModeEnabled }
/>
{ displayBlockToolbar && (
<div className="edit-post-header-toolbar__block-toolbar">
<BlockToolbar hideDragHandle />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.edit-post-header-toolbar {
display: inline-flex;
align-items: center;
border: none;

// Hide all action buttons except the inserter on mobile.
> .components-button {
Expand All @@ -23,6 +24,28 @@
display: flex;
}
}

// The Toolbar component adds different styles to buttons, so we reset them
// here to the original button styles
> .components-button.has-icon,
> .components-dropdown > .components-button.has-icon {
height: $button-size;
min-width: $button-size;
padding: 6px;

&.is-pressed {
background: $dark-gray-primary;
}

&:focus:not(:disabled) {
box-shadow: 0 0 0 $border-width-focus $theme-color;
outline: 1px solid transparent;
}

&::before {
display: none;
}
}
}

// Block toolbar when fixed to the top of the screen.
Expand Down Expand Up @@ -82,7 +105,7 @@
}
}

.edit-post-header-toolbar .edit-post-header-toolbar__inserter-toggle {
.edit-post-header-toolbar .edit-post-header-toolbar__inserter-toggle.has-icon {
margin-right: $grid-unit-10;
// Special dimensions for this button.
min-width: 32px;
Expand Down
11 changes: 9 additions & 2 deletions packages/editor/src/components/editor-history/redo.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import { withSelect, withDispatch } from '@wordpress/data';
import { compose } from '@wordpress/compose';
import { displayShortcut } from '@wordpress/keycodes';
import { redo as redoIcon } from '@wordpress/icons';
import { forwardRef } from '@wordpress/element';

function EditorHistoryRedo( { hasRedo, redo } ) {
function EditorHistoryRedo( { hasRedo, redo, innerRef, ...props } ) {
return (
<Button
{ ...props }
ref={ innerRef }
icon={ redoIcon }
label={ __( 'Redo' ) }
shortcut={ displayShortcut.primaryShift( 'z' ) }
Expand All @@ -24,11 +27,15 @@ function EditorHistoryRedo( { hasRedo, redo } ) {
);
}

export default compose( [
const EnhancedEditorHistoryRedo = compose( [
withSelect( ( select ) => ( {
hasRedo: select( 'core/editor' ).hasEditorRedo(),
} ) ),
withDispatch( ( dispatch ) => ( {
redo: dispatch( 'core/editor' ).redo,
} ) ),
] )( EditorHistoryRedo );

export default forwardRef( ( props, ref ) => (
<EnhancedEditorHistoryRedo { ...props } innerRef={ ref } />
) );
11 changes: 9 additions & 2 deletions packages/editor/src/components/editor-history/undo.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import { withSelect, withDispatch } from '@wordpress/data';
import { compose } from '@wordpress/compose';
import { displayShortcut } from '@wordpress/keycodes';
import { undo as undoIcon } from '@wordpress/icons';
import { forwardRef } from '@wordpress/element';

function EditorHistoryUndo( { hasUndo, undo } ) {
function EditorHistoryUndo( { hasUndo, undo, innerRef, ...props } ) {
return (
<Button
{ ...props }
ref={ innerRef }
icon={ undoIcon }
label={ __( 'Undo' ) }
shortcut={ displayShortcut.primary( 'z' ) }
Expand All @@ -24,11 +27,15 @@ function EditorHistoryUndo( { hasUndo, undo } ) {
);
}

export default compose( [
const EnhancedEditorHistoryUndo = compose( [
withSelect( ( select ) => ( {
hasUndo: select( 'core/editor' ).hasEditorUndo(),
} ) ),
withDispatch( ( dispatch ) => ( {
undo: dispatch( 'core/editor' ).undo,
} ) ),
] )( EditorHistoryUndo );

export default forwardRef( ( props, ref ) => (
<EnhancedEditorHistoryUndo { ...props } innerRef={ ref } />
) );
16 changes: 14 additions & 2 deletions packages/editor/src/components/table-of-contents/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,28 @@ import { __ } from '@wordpress/i18n';
import { Dropdown, Button } from '@wordpress/components';
import { withSelect } from '@wordpress/data';
import { info } from '@wordpress/icons';
import { forwardRef } from '@wordpress/element';

/**
* Internal dependencies
*/
import TableOfContentsPanel from './panel';

function TableOfContents( { hasBlocks, hasOutlineItemsDisabled } ) {
function TableOfContents( {
hasBlocks,
hasOutlineItemsDisabled,
innerRef,
...props
} ) {
return (
<Dropdown
position="bottom"
className="table-of-contents"
contentClassName="table-of-contents__popover"
renderToggle={ ( { isOpen, onToggle } ) => (
<Button
{ ...props }
ref={ innerRef }
onClick={ hasBlocks ? onToggle : undefined }
icon={ info }
aria-expanded={ isOpen }
Expand All @@ -37,8 +45,12 @@ function TableOfContents( { hasBlocks, hasOutlineItemsDisabled } ) {
);
}

export default withSelect( ( select ) => {
const TableOfContentsWithSelect = withSelect( ( select ) => {
return {
hasBlocks: !! select( 'core/block-editor' ).getBlockCount(),
};
} )( TableOfContents );

export default forwardRef( ( props, ref ) => (
<TableOfContentsWithSelect { ...props } innerRef={ ref } />
) );

0 comments on commit 05509fe

Please sign in to comment.