Skip to content

Commit

Permalink
Editor: Associate NavigableToolbar by keybind scope
Browse files Browse the repository at this point in the history
  • Loading branch information
aduth committed Oct 30, 2018
1 parent 4bee05c commit 24f8046
Show file tree
Hide file tree
Showing 11 changed files with 270 additions and 146 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function HeaderToolbar( { hasFixedToolbar, isLargeViewport, mode } ) {
<NavigableToolbar
className="edit-post-header-toolbar"
aria-label={ toolbarAriaLabel }
scopeId="edit-post-header"
>
<FullscreenModeClose />
<div>
Expand Down
102 changes: 54 additions & 48 deletions packages/edit-post/src/components/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
EditorNotices,
PostPublishPanel,
PreserveScrollInReorder,
NavigableToolbar,
} from '@wordpress/editor';
import { withDispatch, withSelect } from '@wordpress/data';
import { Fragment } from '@wordpress/element';
Expand Down Expand Up @@ -70,56 +71,61 @@ function Layout( {
<UnsavedChangesWarning />
<AutosaveMonitor />
<Header />
<div
className="edit-post-layout__content"
role="region"
/* translators: accessibility text for the content landmark region. */
aria-label={ __( 'Editor content' ) }
tabIndex="-1"
<NavigableToolbar.KeybindScope
scopeId="edit-post-header"
className="edit-post-layout__navigable-toolbar-scope"
>
<EditorNotices />
<PreserveScrollInReorder />
<EditorModeKeyboardShortcuts />
<KeyboardShortcutHelpModal />
<OptionsModal />
{ mode === 'text' && <TextEditor /> }
{ mode === 'visual' && <VisualEditor /> }
<div className="edit-post-layout__metaboxes">
<MetaBoxes location="normal" />
</div>
<div className="edit-post-layout__metaboxes">
<MetaBoxes location="advanced" />
</div>
</div>
{ publishSidebarOpened ? (
<PostPublishPanel
{ ...publishLandmarkProps }
onClose={ closePublishSidebar }
forceIsDirty={ hasActiveMetaboxes }
forceIsSaving={ isSaving }
PrePublishExtension={ PluginPrePublishPanel.Slot }
PostPublishExtension={ PluginPostPublishPanel.Slot }
/>
) : (
<Fragment>
<div className="edit-post-toggle-publish-panel" { ...publishLandmarkProps }>
<Button
isDefault
type="button"
className="edit-post-toggle-publish-panel__button"
onClick={ togglePublishSidebar }
aria-expanded={ false }
>
{ __( 'Open publish panel' ) }
</Button>
<div
className="edit-post-layout__content"
role="region"
/* translators: accessibility text for the content landmark region. */
aria-label={ __( 'Editor content' ) }
tabIndex="-1"
>
<EditorNotices />
<PreserveScrollInReorder />
<EditorModeKeyboardShortcuts />
<KeyboardShortcutHelpModal />
<OptionsModal />
{ mode === 'text' && <TextEditor /> }
{ mode === 'visual' && <VisualEditor /> }
<div className="edit-post-layout__metaboxes">
<MetaBoxes location="normal" />
</div>
<SettingsSidebar />
<Sidebar.Slot />
{
isMobileViewport && sidebarIsOpened && <ScrollLock />
}
</Fragment>
) }
<div className="edit-post-layout__metaboxes">
<MetaBoxes location="advanced" />
</div>
</div>
{ publishSidebarOpened ? (
<PostPublishPanel
{ ...publishLandmarkProps }
onClose={ closePublishSidebar }
forceIsDirty={ hasActiveMetaboxes }
forceIsSaving={ isSaving }
PrePublishExtension={ PluginPrePublishPanel.Slot }
PostPublishExtension={ PluginPostPublishPanel.Slot }
/>
) : (
<Fragment>
<div className="edit-post-toggle-publish-panel" { ...publishLandmarkProps }>
<Button
isDefault
type="button"
className="edit-post-toggle-publish-panel__button"
onClick={ togglePublishSidebar }
aria-expanded={ false }
>
{ __( 'Open publish panel' ) }
</Button>
</div>
<SettingsSidebar />
<Sidebar.Slot />
{
isMobileViewport && sidebarIsOpened && <ScrollLock />
}
</Fragment>
) }
</NavigableToolbar.KeybindScope>
<Popover.Slot />
<PluginArea />
</div>
Expand Down
3 changes: 2 additions & 1 deletion packages/edit-post/src/components/layout/style.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.edit-post-layout,
.edit-post-layout__content {
.edit-post-layout__content,
.edit-post-layout__navigable-toolbar-scope {
height: 100%;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import NavigableToolbar from '../navigable-toolbar';
import { BlockToolbar } from '../';

function BlockContextualToolbar() {
return (
<NavigableToolbar
className="editor-block-contextual-toolbar"
aria-label={ __( 'Block Toolbar' ) }
>
<div className="editor-block-contextual-toolbar">
<BlockToolbar />
</NavigableToolbar>
</div>
);
}

Expand Down
49 changes: 23 additions & 26 deletions packages/editor/src/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import BlockMobileToolbar from './block-mobile-toolbar';
import BlockInsertionPoint from './insertion-point';
import IgnoreNestedEvents from '../ignore-nested-events';
import InserterWithShortcuts from '../inserter-with-shortcuts';
import NavigableToolbar from '../navigable-toolbar';
import Inserter from '../inserter';
import withHoverAreas from './with-hover-areas';
import { isInsideRootBlock } from '../../utils/dom';
Expand Down Expand Up @@ -93,12 +94,6 @@ export class BlockListBlock extends Component {
if ( this.props.isSelected && ! prevProps.isSelected ) {
this.focusTabbable( true );
}

// When triggering a multi-selection,
// move the focus to the wrapper of the first selected block.
if ( this.props.isFirstMultiSelected && ! prevProps.isFirstMultiSelected ) {
this.wrapperNode.focus();
}
}

setBlockListRef( node ) {
Expand Down Expand Up @@ -538,27 +533,29 @@ export class BlockListBlock extends Component {
className="editor-block-list__block-edit"
data-block={ clientId }
>
<BlockCrashBoundary onError={ this.onBlockError }>
{ isValid && blockEdit }
{ isValid && mode === 'html' && (
<BlockHtml clientId={ clientId } />
<NavigableToolbar.KeybindScope scopeId={ 'block-' + clientId }>
<BlockCrashBoundary onError={ this.onBlockError }>
{ isValid && blockEdit }
{ isValid && mode === 'html' && (
<BlockHtml clientId={ clientId } />
) }
{ ! isValid && [
<BlockInvalidWarning
key="invalid-warning"
block={ block }
/>,
<div key="invalid-preview">
{ getSaveElement( blockType, block.attributes ) }
</div>,
] }
</BlockCrashBoundary>
{ shouldShowMobileToolbar && (
<BlockMobileToolbar
clientId={ clientId }
/>
) }
{ ! isValid && [
<BlockInvalidWarning
key="invalid-warning"
block={ block }
/>,
<div key="invalid-preview">
{ getSaveElement( blockType, block.attributes ) }
</div>,
] }
</BlockCrashBoundary>
{ shouldShowMobileToolbar && (
<BlockMobileToolbar
clientId={ clientId }
/>
) }
{ !! error && <BlockCrashWarning /> }
{ !! error && <BlockCrashWarning /> }
</NavigableToolbar.KeybindScope>
</IgnoreNestedEvents>
{ showEmptyBlockSideInserter && (
<Fragment>
Expand Down
38 changes: 23 additions & 15 deletions packages/editor/src/components/block-toolbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import { withSelect } from '@wordpress/data';
import { Fragment } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal Dependencies
Expand All @@ -12,32 +13,39 @@ import MultiBlocksSwitcher from '../block-switcher/multi-blocks-switcher';
import BlockControls from '../block-controls';
import BlockFormatControls from '../block-format-controls';
import BlockSettingsMenu from '../block-settings-menu';
import NavigableToolbar from '../navigable-toolbar';

function BlockToolbar( { blockClientIds, isValid, mode } ) {
if ( blockClientIds.length === 0 ) {
return null;
}

if ( blockClientIds.length > 1 ) {
return (
<div className="editor-block-toolbar">
<MultiBlocksSwitcher />
<BlockSettingsMenu clientIds={ blockClientIds } />
</div>
const hasMultiSelection = blockClientIds.length > 1;

let controls;
if ( hasMultiSelection ) {
controls = (
<MultiBlocksSwitcher />
);
} else if ( mode === 'visual' && isValid ) {
controls = (
<Fragment>
<BlockSwitcher clientIds={ blockClientIds } />
<BlockControls.Slot />
<BlockFormatControls.Slot />
</Fragment>
);
}

return (
<div className="editor-block-toolbar">
{ mode === 'visual' && isValid && (
<Fragment>
<BlockSwitcher clientIds={ blockClientIds } />
<BlockControls.Slot />
<BlockFormatControls.Slot />
</Fragment>
) }
<NavigableToolbar
className="editor-block-toolbar"
aria-label={ __( 'Block Toolbar' ) }
scopeId={ 'block-' + blockClientIds[ 0 ] }
>
{ controls }
<BlockSettingsMenu clientIds={ blockClientIds } />
</div>
</NavigableToolbar>
);
}

Expand Down
29 changes: 29 additions & 0 deletions packages/editor/src/components/navigable-toolbar/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
NavigableToolbar
================

NavigableToolbar is a set of components which renders a toolbar menu and coordinates focus to and from the toolbar by contextual keyboard shortcuts.

While focused within the scope of a `NavigableToolbar.KeybindScope` component, pressing <kbd>Alt + F10</kbd> will direct focus to the corresponding toolbar by scope identifier. Pressing <kbd>Escape</kbd> while in a toolbar will return focus to the element which had focus at the time of the <kbd>Alt + F10</kbd> key combination, if applicable.

## Usage

Render a `NavigableToolbar` with an assigned scopeId. Elsewhere, render one or more `NavigableToolbar.KeybindScope` wrapping the context(s) in which the toolbar's keyboard shortcut should be observed.

```jsx
import { NavigableToolbar } from '@wordpress/editor';
import { Toolbar } from '@wordpress/components';
import { Fragment } from '@wordpress/element';

function MyNavigableToolbar() {
return (
<Fragment>
<NavigableToolbar scopeId="my-toolbar">
<Toolbar controls={ [ /* ... */ ] } />
</NavigableToolbar>
<NavigableToolbar.KeybindScope scopeId="my-toolbar">
<textarea />
</NavigableToolbar.KeybindScope>
</Fragment>
);
}
```
Loading

0 comments on commit 24f8046

Please sign in to comment.