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

Components: Make Toolbar accessible #17875

Closed
wants to merge 86 commits into from
Closed
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
a406f95
Add initial accessible toolbar implementation
diegohaz Oct 10, 2019
968ed0b
Merge branch 'master' into try/accessible-toolbar
diegohaz Oct 10, 2019
85792cb
Fix ToolbarButton style by putting box-sizing on the component styles
diegohaz Oct 10, 2019
b39d864
Support current ToolbarButton usage
diegohaz Oct 12, 2019
f47de25
Remove useMemo
diegohaz Oct 12, 2019
3fe4c5a
Re-export current native versions
diegohaz Oct 12, 2019
73226d1
Fix AccessibleToolbarButton overwriting existing IconButton props
diegohaz Oct 12, 2019
adef315
Add label to Toolbar
diegohaz Oct 12, 2019
0b81861
Create stories
diegohaz Oct 12, 2019
f7aaa2e
Upgrade reakit dependency
diegohaz Oct 12, 2019
1ab4179
Fix ToolbarContext value
diegohaz Oct 12, 2019
98d1f25
Update package-lock.json
diegohaz Oct 12, 2019
d180767
Use accessibilityLabel instead of label
diegohaz Oct 12, 2019
f3152cd
Merge toggleProps event handlers in DropdownMenu
diegohaz Oct 14, 2019
544f5b9
Add ToolbarGroup component
diegohaz Oct 14, 2019
7161889
Use ToolbarGroup on Toolbar legacy
diegohaz Oct 14, 2019
60d67a8
Update Toolbar stories
diegohaz Oct 14, 2019
ef73ced
Update Toolbar README.md
diegohaz Oct 14, 2019
8dca51c
Fix ToolbarGroup not being included in the tab order on the legacy usage
diegohaz Oct 14, 2019
72ce182
Update AccessibleToolbarButton
diegohaz Oct 17, 2019
8a9e381
Refactor ToolbarContext and deprecate Toolbar being used as collapsib…
diegohaz Oct 17, 2019
064a47c
Update stories
diegohaz Oct 17, 2019
f9492bb
Refactor ToolbarGroup
diegohaz Oct 17, 2019
1f85dc3
Export ToolbarGroup
diegohaz Oct 18, 2019
5e9a548
Fix tests
diegohaz Oct 18, 2019
d7e41f4
Fix Styling
diegohaz Oct 18, 2019
fadd820
Update comments
diegohaz Oct 18, 2019
797a6be
Test Toolbar
diegohaz Oct 24, 2019
f5c314a
Replace `callAll` by inline merge on DropdownMenu
diegohaz Oct 24, 2019
de78c1b
Add hint to deprecation warning
diegohaz Oct 24, 2019
3d68c02
Add jsdocs to Toolbar
diegohaz Oct 24, 2019
77311b5
Import toolbar-group style into style.css
diegohaz Oct 24, 2019
fe8a04f
Rename Toolbar/ToolbarGroup class names
diegohaz Oct 24, 2019
3ecfb34
Update Toolbar usage in components
diegohaz Oct 24, 2019
7d98ff3
Update snapshots
diegohaz Oct 24, 2019
c53718b
Merge branch 'master' into try/accessible-toolbar
diegohaz Oct 24, 2019
eaf1160
Update experimental Toolbar usage
diegohaz Oct 24, 2019
cd388c4
Update header toolbar
diegohaz Oct 24, 2019
d7339b7
Fix Fill not updating when Slot fillProps change
diegohaz Oct 26, 2019
1b4b0bc
Update Toolbar
diegohaz Oct 27, 2019
8d4e0ff
Move data-toolbar-button to the accessible toolbar button
diegohaz Oct 27, 2019
c095e19
Update Toolbar stories
diegohaz Oct 27, 2019
bc97f6d
Update BlockControls and BlockFormatControls slots
diegohaz Oct 27, 2019
5a03322
Use ToolbarButton instead of IconButton?
diegohaz Oct 27, 2019
cf32751
Revert "Use ToolbarButton instead of IconButton?"
diegohaz Oct 27, 2019
6e1ff35
Update styles
diegohaz Oct 27, 2019
a812fd9
Extend toolbar context to accept any button
diegohaz Oct 28, 2019
2fce082
Separate toolbar context
diegohaz Oct 28, 2019
798c708
Update Toolbar Group styles
diegohaz Oct 28, 2019
c8e0f87
Revert DropdownMenu to master version
diegohaz Oct 28, 2019
550aa48
Merge branch 'master' into try/accessible-toolbar
diegohaz Oct 28, 2019
d3fe09f
Check if button is descendant of Toolbar
diegohaz Oct 31, 2019
0a1fa12
Fix toolbar button
diegohaz Oct 31, 2019
a80ec3d
Try some weird stuff
diegohaz Oct 31, 2019
131bb6b
Merge branch 'master' into try/accessible-toolbar
diegohaz Oct 31, 2019
e89b247
Merge branch 'master' into try/accessible-toolbar
diegohaz Nov 1, 2019
755a008
Tweaks
diegohaz Nov 2, 2019
4c88edc
Merge branch 'master' into try/accessible-toolbar
diegohaz Nov 2, 2019
3bada40
Update package-lock.json
diegohaz Nov 2, 2019
da8049f
Migrate missing Toolbar
diegohaz Nov 2, 2019
ccdd9ed
Delay Toolbar focus on mount
diegohaz Nov 2, 2019
21ad7af
Fix Toolbar styling
diegohaz Nov 2, 2019
5c6baf7
Fix tabThroughBlockToolbar e2e test
diegohaz Nov 3, 2019
d88a79f
Merge branch 'master' into try/accessible-toolbar
diegohaz Nov 3, 2019
8116145
Fix Tab navigation on block-hierarchy navigation test
diegohaz Nov 3, 2019
1d7e9c9
Try without isMounted on Slot
diegohaz Nov 3, 2019
a1328b2
Try without useMountedToolbarState
diegohaz Nov 3, 2019
7f48985
Remove ToolbarSlotFill
diegohaz Nov 5, 2019
efe8ee0
Put ToolbarProvider closer to the block contextual toolbar and the bl…
diegohaz Nov 5, 2019
7d61565
Update BlockListBlock format
diegohaz Nov 5, 2019
c715bc3
Use Header Toolbar Provider when contextual toolbar is not shown
diegohaz Nov 5, 2019
634156a
Remove Contextual Toolbar context only when there is a fixed toolbar
diegohaz Nov 6, 2019
b6e6b57
Revert to a1328b2
diegohaz Nov 6, 2019
228068c
Remove ToolbarSlotFill from components package
diegohaz Nov 6, 2019
0bfb8cb
Merge branch 'master' into try/accessible-toolbar
diegohaz Nov 11, 2019
d410b77
Fix toolbar group styling
diegohaz Nov 11, 2019
d8c0673
Remove subscript prop from ToolbarGroup tests
diegohaz Nov 11, 2019
2eecd53
Fix DropdownMenu items don't receiving focus on Storybook
diegohaz Nov 11, 2019
7a182b8
Merge branch 'master' into try/accessible-toolbar
diegohaz Nov 11, 2019
3a9bf79
ToolbarContext -> __experimentalToolbarContext
diegohaz Nov 12, 2019
5e033bc
Add missing JSDocs to ToolbarGroup
diegohaz Nov 12, 2019
4133551
Fix ref merging on useIsWithinToolbar
diegohaz Nov 12, 2019
3605055
Add missing JSDoc descriptions
diegohaz Nov 12, 2019
8d47333
Merge branch 'master' into try/accessible-toolbar
diegohaz Nov 12, 2019
d422d7e
Update stories
diegohaz Nov 12, 2019
6170843
Merge branch 'master' into try/accessible-toolbar
diegohaz Nov 13, 2019
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
30 changes: 28 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"re-resizable": "^6.0.0",
"react-dates": "^17.1.1",
"react-spring": "^8.0.20",
"reakit": "^1.0.0-beta.9",
"rememo": "^3.0.0",
"tinycolor2": "^1.4.1",
"uuid": "^3.3.2"
Expand Down
14 changes: 12 additions & 2 deletions packages/components/src/dropdown-menu/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ function mergeProps( defaultProps = {}, props = {} ) {
return mergedProps;
}

function callAll( ...fns ) {
diegohaz marked this conversation as resolved.
Show resolved Hide resolved
return ( ...args ) => {
for ( const fn of fns ) {
if ( typeof fn === 'function' ) {
fn( ...args );
}
}
};
}

function DropdownMenu( {
children,
className,
Expand Down Expand Up @@ -98,8 +108,8 @@ function DropdownMenu( {
<IconButton
{ ...mergedToggleProps }
icon={ icon }
onClick={ onToggle }
onKeyDown={ openOnArrowDown }
onClick={ callAll( onToggle, mergedToggleProps.onClick ) }
onKeyDown={ callAll( openOnArrowDown, mergedToggleProps.onKeyDown ) }
aria-haspopup="true"
aria-expanded={ isOpen }
label={ label }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* External dependencies
*/
import { useToolbarItem } from 'reakit/Toolbar';

/**
* WordPress dependencies
*/
import { useContext, Children, cloneElement } from '@wordpress/element';

/**
* Internal dependencies
*/
import ToolbarContext from '../toolbar-context';

function AccessibleToolbarButtonContainer( props ) {
const toolbar = useContext( ToolbarContext );
const button = Children.only( props.children );
const itemHTMLProps = useToolbarItem( toolbar, button.props );
return (
<div { ...props }>
{ cloneElement( button, itemHTMLProps ) }
</div>
);
}

export default AccessibleToolbarButtonContainer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Internal dependencies
*/
import ToolbarButtonContainer from './toolbar-button-container';

export default ToolbarButtonContainer;
56 changes: 38 additions & 18 deletions packages/components/src/toolbar-button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { useContext } from '@wordpress/element';

/**
* Internal dependencies
*/
import IconButton from '../icon-button';
import ToolbarContext from '../toolbar-context';
import AccessibleToolbarButtonContainer from './accessible-toolbar-button-container';
import ToolbarButtonContainer from './toolbar-button-container';

function ToolbarButton( {
Expand All @@ -22,26 +29,39 @@ function ToolbarButton( {
extraProps,
children,
} ) {
const context = useContext( ToolbarContext );
const button = (
<IconButton
icon={ icon }
label={ title }
shortcut={ shortcut }
data-subscript={ subscript }
onClick={ ( event ) => {
event.stopPropagation();
onClick();
} }
className={ classnames(
'components-toolbar__control',
className,
{ 'is-active': isActive }
) }
aria-pressed={ isActive }
disabled={ isDisabled }
{ ...extraProps }
/>
);

if ( context ) {
return (
<AccessibleToolbarButtonContainer className={ containerClassName }>
{ button }
</AccessibleToolbarButtonContainer>
);
}

return (
<ToolbarButtonContainer className={ containerClassName }>
<IconButton
icon={ icon }
label={ title }
shortcut={ shortcut }
data-subscript={ subscript }
onClick={ ( event ) => {
event.stopPropagation();
onClick();
} }
className={ classnames(
'components-toolbar__control',
className,
{ 'is-active': isActive }
) }
aria-pressed={ isActive }
disabled={ isDisabled }
{ ...extraProps }
/>
{ button }
{ children }
</ToolbarButtonContainer>
);
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/toolbar-button/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
border-radius: $radius-round-rectangle;
height: 30px;
width: 30px;
box-sizing: border-box;
}

// Subscript for numbered icon buttons, like headings
Expand Down
8 changes: 8 additions & 0 deletions packages/components/src/toolbar-context/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* WordPress dependencies
*/
import { createContext } from '@wordpress/element';

const ToolbarContext = createContext();

export default ToolbarContext;
95 changes: 95 additions & 0 deletions packages/components/src/toolbar-group/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* External dependencies
*/
import classnames from 'classnames';
import { flatMap } from 'lodash';

/**
* Internal dependencies
*/
import ToolbarButton from '../toolbar-button';
import ToolbarGroupContainer from './toolbar-group-container';
import ToolbarGroupCollapsed from './toolbar-group-collapsed';

/**
* Renders a toolbar with controls.
*
* The `controls` prop accepts an array of sets. A set is an array of controls.
* Controls have the following shape:
*
* ```
* {
* icon: string,
* title: string,
* subscript: string,
* onClick: Function,
* isActive: boolean,
* isDisabled: boolean
* }
* ```
*
* For convenience it is also possible to pass only an array of controls. It is
* then assumed this is the only set.
*
* Either `controls` or `children` is required, otherwise this components
* renders nothing.
*
* @param {Object} props
* @param {Array} [props.controls] The controls to render in this toolbar.
* @param {ReactElement} [props.children] Any other things to render inside the
* toolbar besides the controls.
* @param {string} [props.className] Class to set on the container div.
*
* @return {ReactElement} The rendered toolbar.
*/
function ToolbarGroup( {
controls = [],
children,
className,
isCollapsed,
icon,
label,
...otherProps
} ) {
if ( ( ! controls || ! controls.length ) && ! children ) {
return null;
}

const cls = classnames( 'components-toolbar', className );

// Normalize controls to nested array of objects (sets of controls)
let controlSets = controls;
if ( ! Array.isArray( controlSets[ 0 ] ) ) {
controlSets = [ controlSets ];
}

if ( isCollapsed ) {
return (
<ToolbarGroupCollapsed
icon={ icon }
label={ label }
controls={ controlSets }
className={ cls }
/>
);
}

return (
<ToolbarGroupContainer className={ cls } { ...otherProps }>
{ flatMap( controlSets, ( controlSet, indexOfSet ) =>
controlSet.map( ( control, indexOfControl ) => (
<ToolbarButton
key={ [ indexOfSet, indexOfControl ].join() }
containerClassName={
indexOfSet > 0 && indexOfControl === 0 ? 'has-left-divider' : null
}
{ ...control }
/>
) )
) }
{ children }
</ToolbarGroupContainer>
);
}

export default ToolbarGroup;
11 changes: 11 additions & 0 deletions packages/components/src/toolbar-group/style.native.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.container {
flex-direction: row;
border-left-width: 1px;
border-color: #e9eff3;
padding-left: 5px;
padding-right: 5px;
}

.containerDark {
border-color: #525354;
}
41 changes: 41 additions & 0 deletions packages/components/src/toolbar-group/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.components-toolbar-group {
diegohaz marked this conversation as resolved.
Show resolved Hide resolved
margin: 0;
border: $border-width solid $light-gray-500;
background-color: $white;
display: flex;
flex-shrink: 0;
}

div.components-toolbar-group {
& > div {
// IE11 does not support `position: sticky`, or Flex very well, so use block.
display: block;
@supports (position: sticky) {
display: flex;
}

margin: 0;
}

& > div + div {
margin-left: -3px;

&.has-left-divider {
margin-left: 6px;
position: relative;
overflow: visible;
}

&.has-left-divider::before {
display: inline-block;
content: "";
box-sizing: content-box;
background-color: $light-gray-500;
position: absolute;
top: 8px;
left: -3px;
width: 1px;
height: $icon-button-size - 16px;
}
}
}
Loading