From 5fa8316757fd73fef1e053a7ee9ce515ba4d556c Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 6 Dec 2018 17:09:25 +1100 Subject: [PATCH] NUX: Allow collapsed tips to be opened with the keyboard Attempts to improve the accessibility of tips by: - Allowing `DotTip` to be expanded or collapsed using a keyboard shortcut configured with the `shortcut` prop. - Having collapsed tips that have a shortcut configured `speak()` when mounted so that screen reader users are aware of their presense. --- .../components/header/header-toolbar/index.js | 9 +++- packages/nux/src/components/dot-tip/README.md | 23 +++++++-- packages/nux/src/components/dot-tip/index.js | 48 ++++++++++++++----- .../dot-tip/test/__snapshots__/index.js.snap | 2 +- .../nux/src/components/dot-tip/test/index.js | 2 +- 5 files changed, 65 insertions(+), 19 deletions(-) diff --git a/packages/edit-post/src/components/header/header-toolbar/index.js b/packages/edit-post/src/components/header/header-toolbar/index.js index 3e24b3a5e4041..31a43169e2420 100644 --- a/packages/edit-post/src/components/header/header-toolbar/index.js +++ b/packages/edit-post/src/components/header/header-toolbar/index.js @@ -15,6 +15,7 @@ import { NavigableToolbar, BlockNavigationDropdown, } from '@wordpress/editor'; +import { rawShortcut, shortcutAriaLabel } from '@wordpress/keycodes'; /** * Internal dependencies @@ -38,9 +39,13 @@ function HeaderToolbar( { hasFixedToolbar, isLargeViewport, showInserter } ) { isOpen ? __( 'Close tip for “Add block”' ) : __( 'Open tip for “Add block”' ) } className="edit-post-header-toolbar__inserter-button-tip" + isCollapsible + label="Add block" + shortcut={ { + raw: rawShortcut.access( 't' ), + ariaLabel: shortcutAriaLabel.access( 't' ), + } } > { __( 'Welcome to the wonderful world of blocks! Click the “+” (“Add block”) button to add a new block. There are blocks available for all kinds of content: you can insert text, headings, images, lists, and lots more!' ) } diff --git a/packages/nux/src/components/dot-tip/README.md b/packages/nux/src/components/dot-tip/README.md index 3528bf0b6ac1e..4bbae96c4ef3d 100644 --- a/packages/nux/src/components/dot-tip/README.md +++ b/packages/nux/src/components/dot-tip/README.md @@ -41,15 +41,30 @@ Defaults to `false`. ### label -The ARIA label used to describe the button that opens or closes a collapsible tip. +A short string which describes the tip. This is used to label the button which expands or collapses the tip if it is collapsible. -If a function is provided then it will be invoked with `isOpen` as the argument, allowing one to change the label depeneding on whether the button opens or closes the tip. +```jsx + + Click here to add the product to your shopping cart. + +``` + +- Type: `string` +- Required: No + +### shortcut + +An object which, if specified, configures a keyboard shortcut which will expand or collapse the tip if it is collapsible. + +The object must contain a `raw` property which is the keyboard shortcut to bind to. + +Optionally, the object can contain an `ariaLabel` property which is a textual description of the shortcut used for screen readers. ```jsx - isOpen ? 'Close tip' : 'Open tip' }> + Click here to add the product to your shopping cart. ``` -- Type: `string` or `Function` +- Type: `Object` - Required: No diff --git a/packages/nux/src/components/dot-tip/index.js b/packages/nux/src/components/dot-tip/index.js index 23b1a423b5f30..454d7edb8f59c 100644 --- a/packages/nux/src/components/dot-tip/index.js +++ b/packages/nux/src/components/dot-tip/index.js @@ -1,15 +1,16 @@ -/** - * External dependencies - */ -import { isFunction } from 'lodash'; - /** * WordPress dependencies */ import { Component } from '@wordpress/element'; import { compose } from '@wordpress/compose'; -import { Popover, Button, IconButton } from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; +import { + Button, + IconButton, + KeyboardShortcuts, + Popover, + withSpokenMessages, +} from '@wordpress/components'; +import { __, sprintf } from '@wordpress/i18n'; import { withSelect, withDispatch } from '@wordpress/data'; function stopEventPropagation( event ) { @@ -18,7 +19,12 @@ function stopEventPropagation( event ) { event.stopPropagation(); } -function defaultLabel( isOpen ) { +function buildLabel( isOpen, label ) { + if ( label ) { + return isOpen ? + sprintf( __( 'Close tip for “%s”' ), label ) : + sprintf( __( 'Open tip for “%s”' ), label ); + } return isOpen ? __( 'Close tip' ) : __( 'Open tip' ); } @@ -33,6 +39,16 @@ export class DotTip extends Component { }; } + componentDidMount() { + const { isCollapsible, shortcut, label, debouncedSpeak } = this.props; + + if ( isCollapsible && shortcut && shortcut.raw && shortcut.ariaLabel && label ) { + debouncedSpeak( + sprintf( __( 'Press “%s” to open the tip for “%s”.' ), shortcut.ariaLabel, label ) + ); + } + } + toggleIsOpen( event ) { stopEventPropagation( event ); @@ -48,9 +64,10 @@ export class DotTip extends Component { hasNextTip, isCollapsible, isVisible, - label = defaultLabel, + label, onDisable, onDismiss, + shortcut, } = this.props; const { isOpen } = this.state; @@ -94,9 +111,17 @@ export class DotTip extends Component { return isCollapsible ? ( ) : ( @@ -124,5 +149,6 @@ export default compose( disableTips(); }, }; - } ) + } ), + withSpokenMessages )( DotTip ); diff --git a/packages/nux/src/components/dot-tip/test/__snapshots__/index.js.snap b/packages/nux/src/components/dot-tip/test/__snapshots__/index.js.snap index 87ee580190d5c..c1aaa2fa4fcd3 100644 --- a/packages/nux/src/components/dot-tip/test/__snapshots__/index.js.snap +++ b/packages/nux/src/components/dot-tip/test/__snapshots__/index.js.snap @@ -10,7 +10,7 @@ exports[`DotTip should render a button when collapsible 1`] = ` exports[`DotTip should render a custom label when collapsible 1`] = `