Skip to content

Commit

Permalink
Adding a11y and RTL support to AlignmentMatrixControl
Browse files Browse the repository at this point in the history
Also refactors isRTL / useRTL from the rtl utils.
  • Loading branch information
Jon Q committed Apr 1, 2020
1 parent 73219e2 commit e5d0c43
Show file tree
Hide file tree
Showing 10 changed files with 331 additions and 93 deletions.
21 changes: 21 additions & 0 deletions packages/components/src/alignment-matrix-control/cell.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Internal dependencies
*/
import {
Cell as CellView,
Point,
} from './styles/alignment-matrix-control-styles';

export default function Cell( { isActive = false, value, ...props } ) {
return (
<CellView
aria-selected={ isActive }
aria-label={ value }
role="option"
tabIndex={ -1 }
{ ...props }
>
<Point isActive={ isActive } role="presentation" />
</CellView>
);
}
21 changes: 19 additions & 2 deletions packages/components/src/alignment-matrix-control/icon.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* Internal dependencies
*/
Expand All @@ -9,6 +14,7 @@ import {
} from './styles/alignment-matrix-control-icon-styles';

export default function AlignmentMatrixControlIcon( {
className,
height,
size: sizeProp = 24,
value = 'center',
Expand All @@ -18,12 +24,23 @@ export default function AlignmentMatrixControlIcon( {
const alignIndex = getAlignmentIndex( value );
const size = sizeProp || width || height;

const classes = classnames(
'component-alignment-matrix-control-icon',
className
);

return (
<Root { ...props } size={ size }>
<Root
{ ...props }
className={ classes }
role="presentation"
size={ size }
>
{ ALIGNMENTS.map( ( align, index ) => {
const isActive = alignIndex === index;

return (
<Cell tabIndex={ -1 } key={ align }>
<Cell key={ align } tabIndex={ -1 }>
<Point isActive={ isActive } />
</Cell>
);
Expand Down
70 changes: 48 additions & 22 deletions packages/components/src/alignment-matrix-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
* External dependencies
*/
import { noop } from 'lodash';
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { useInstanceId } from '@wordpress/compose';
import { useEffect, useRef } from '@wordpress/element';
import { UP, DOWN, LEFT, RIGHT } from '@wordpress/keycodes';

Expand All @@ -19,22 +22,27 @@ import {
getAlignmentValueFromIndex,
getNextIndexFromDirection,
} from './utils';
import { Root, Cell, Point } from './styles/alignment-matrix-control-styles';
import Cell from './cell';
import { Root } from './styles/alignment-matrix-control-styles';
import { useControlledState } from '../utils/hooks';
import { useRTL } from '../utils/rtl';
import AlignmentMatrixControlIcon from './icon';

// TODO: Account for RTL alignments
export default function AlignmentMatrixControl( {
className,
label = __( 'Alignment Matrix Control' ),
hasFocusBorder = true,
onChange = noop,
onKeyDown = noop,
value = 'center',
...props
} ) {
const isRTL = useRTL();
const [ alignIndex, setAlignIndex ] = useControlledState(
getAlignmentIndex( value )
);
const nodeRef = useRef();
const instanceId = useInstanceId( AlignmentMatrixControl );

const handleOnChange = ( nextIndex, changeProps ) => {
const alignName = getAlignmentValueFromIndex( nextIndex );
Expand All @@ -46,41 +54,42 @@ export default function AlignmentMatrixControl( {
const handleOnKeyDown = ( event ) => {
const { keyCode } = event;
let nextIndex;
let direction;

onKeyDown( event );

switch ( keyCode ) {
case UP:
event.preventDefault();
nextIndex = getNextIndexFromDirection(
alignIndex,
DIRECTION.UP
);
direction = DIRECTION.UP;

nextIndex = getNextIndexFromDirection( alignIndex, direction );
handleOnChange( nextIndex, { event } );

break;
case DOWN:
event.preventDefault();
nextIndex = getNextIndexFromDirection(
alignIndex,
DIRECTION.DOWN
);
direction = DIRECTION.DOWN;

nextIndex = getNextIndexFromDirection( alignIndex, direction );
handleOnChange( nextIndex, { event } );

break;
case LEFT:
event.preventDefault();
nextIndex = getNextIndexFromDirection(
alignIndex,
DIRECTION.LEFT
);
direction = isRTL ? DIRECTION.RIGHT : DIRECTION.LEFT;

nextIndex = getNextIndexFromDirection( alignIndex, direction );
handleOnChange( nextIndex, { event } );

break;
case RIGHT:
event.preventDefault();
nextIndex = getNextIndexFromDirection(
alignIndex,
DIRECTION.RIGHT
);
direction = isRTL ? DIRECTION.LEFT : DIRECTION.RIGHT;

nextIndex = getNextIndexFromDirection( alignIndex, direction );
handleOnChange( nextIndex, { event } );

break;
default:
break;
Expand Down Expand Up @@ -111,23 +120,40 @@ export default function AlignmentMatrixControl( {
};
}, [ handleOnKeyDown ] );

const id = `alignment-matrix-control-${ instanceId }`;
const activeCellId = `${ id }-${ alignIndex }`;

const classes = classnames(
'component-alignment-matrix-control',
className
);

return (
<Root
{ ...props }
aria-activedescendant={ activeCellId }
aria-label={ label }
aria-labelledby={ id }
className={ classes }
hasFocusBorder={ hasFocusBorder }
id={ id }
ref={ nodeRef }
role="listbox"
tabIndex={ 0 }
>
{ ALIGNMENTS.map( ( align, index ) => {
const isActive = alignIndex === index;
const cellId = `${ id }-${ index }`;
const cellValue = getAlignmentValueFromIndex( index );

return (
<Cell
tabIndex={ -1 }
id={ cellId }
isActive={ isActive }
key={ align }
onClick={ createHandleOnClick( index ) }
>
<Point isActive={ isActive } />
</Cell>
value={ cellValue }
/>
);
} ) }
</Root>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export const Root = styled.div`
grid-template-rows: repeat( 3, calc( var( --width ) / 3 ) );
width: var( --width, 92px );
${rootBase};
${rootBorder};
${rootBase}
${rootBorder}
`;

const pointActive = ( { isActive } ) => {
Expand Down Expand Up @@ -66,15 +66,15 @@ export const pointBase = ( props ) => {
margin: auto;
transition: all 120ms linear;
${reduceMotion( 'transition' )};
${pointActive( props )};
${reduceMotion( 'transition' )}
${pointActive( props )}
`;
};

export const Point = styled.span`
height: 6px;
width: 6px;
${pointBase};
${pointBase}
`;

export const Cell = styled.span`
Expand Down
40 changes: 40 additions & 0 deletions packages/components/src/alignment-matrix-control/test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* External dependencies
*/
import { render, unmountComponentAtNode } from 'react-dom';
import { act } from 'react-dom/test-utils';

/**
* Internal dependencies
*/
import AlignmentMatrixControl from '../';

let container = null;

beforeEach( () => {
container = document.createElement( 'div' );
document.body.appendChild( container );
} );

afterEach( () => {
unmountComponentAtNode( container );
container.remove();
container = null;
} );

const getControl = () => {
return container.querySelector( '.component-alignment-matrix-control' );
};

describe( 'AlignmentMatrixControl', () => {
describe( 'Basic rendering', () => {
it( 'should render', () => {
act( () => {
render( <AlignmentMatrixControl />, container );
} );
const control = getControl();

expect( control ).toBeTruthy();
} );
} );
} );
Loading

0 comments on commit e5d0c43

Please sign in to comment.