Skip to content

Commit

Permalink
Gutenboarding: Improve a11y and lints (#38583)
Browse files Browse the repository at this point in the history
* Install reakit and use Dialog to display page selector
* Enable keyboard accessibility in design and layout selector.
* Add hover and focus styling for design picker.
* Style selected layout with grey color when focused / hovered so it can be visually identified

Co-authored-by: Răzvan Papadopol <[email protected]>
  • Loading branch information
sirreal and Răzvan Papadopol committed Jan 6, 2020
1 parent 9d7540a commit 79cfa4d
Show file tree
Hide file tree
Showing 6 changed files with 448 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* External dependencies
*/
import { __ as NO__ } from '@wordpress/i18n';
import React, { FunctionComponent, MouseEventHandler, CSSProperties } from 'react';
import { addQueryArgs, removeQueryArgs } from '@wordpress/url';
import classnames from 'classnames';
Expand All @@ -20,22 +21,37 @@ interface Props {
design: import('@automattic/data-stores').VerticalsTemplates.Template;
onClick: MouseEventHandler< HTMLDivElement >;
style?: CSSProperties;
dialogId: string;
}
const DesignCard: FunctionComponent< Props > = ( { design, onClick, isSelected, style } ) => (
const DesignCard: FunctionComponent< Props > = ( {
design,
dialogId,
isSelected,
onClick,
style,
} ) => (
<Card
as="button"
className={ classnames( 'design-selector__design-option', { 'is-selected': isSelected } ) }
isElevated
onClick={ onClick }
style={ style }
aria-haspopup="dialog"
aria-controls={ dialogId }
>
<CardMedia>
<CardMedia as="span">
<img
width={ 480 }
height={ 360 }
alt={ design.title }
src={ removeQueryArgs( design.preview, 'w' ) }
srcSet={ srcSet( design.preview, [ gridWidth / 2, gridWidth / 4 ] ) }
/>
<span className="design-selector__option-overlay">
<span className="design-selector__option-overlay-text">
{ NO__( 'Select this design' ) }
</span>
</span>
</CardMedia>
</Card>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import classnames from 'classnames';
import { CSSTransition } from 'react-transition-group';
import PageLayoutSelector from './page-layout-selector';
import { partition } from 'lodash';
import { Portal } from 'reakit/Portal';
import { Dialog, DialogBackdrop } from 'reakit/Dialog';

/**
* Internal dependencies
Expand Down Expand Up @@ -37,6 +39,7 @@ const DesignSelector: FunctionComponent = () => {
);

const [ selectedDesign, setSelectedDesign ] = useState< Template | undefined >();

const [ selectedLayouts, setSelectedLayouts ] = useState< Set< string > >( new Set() );
const resetLayouts = () => setSelectedLayouts( new Set() );
const toggleLayout = ( layout: Template ) =>
Expand All @@ -57,8 +60,11 @@ const DesignSelector: FunctionComponent = () => {

const transitionTiming = 250;
const hasSelectedDesign = !! selectedDesign;
const [ isDialogVisible, setIsDialogVisible ] = useState( hasSelectedDesign );
const [ cp, setCp ] = useState< number >();

const dialogId = 'page-selector-modal';

return (
<div className={ classnames( 'design-selector', { 'has-selected-design': selectedDesign } ) }>
<div
Expand All @@ -75,14 +81,12 @@ const DesignSelector: FunctionComponent = () => {
</div>

<CSSTransition in={ ! hasSelectedDesign } timeout={ transitionTiming }>
<div
className="design-selector__grid-container"
onClick={ hasSelectedDesign ? resetState : undefined }
>
<div className="design-selector__grid-container">
<div className="design-selector__grid">
{ designs.map( design => (
<DesignCard
key={ design.slug }
dialogId={ dialogId }
design={ design }
isSelected={ design.slug === selectedDesign?.slug }
style={
Expand All @@ -106,16 +110,37 @@ const DesignSelector: FunctionComponent = () => {
</div>
</CSSTransition>

<CSSTransition in={ hasSelectedDesign } timeout={ transitionTiming } unmountOnExit>
<div className="page-layout-selector__container">
<PageLayoutSelector
selectedDesign={ selectedDesign }
selectedLayouts={ selectedLayouts }
selectLayout={ toggleLayout }
templates={ otherTemplates }
/>
</div>
</CSSTransition>
<Portal>
<DialogBackdrop
visible={ hasSelectedDesign }
className="design-selector__page-layout-backdrop"
/>
</Portal>

<Dialog
visible={ isDialogVisible }
baseId={ dialogId }
hide={ resetState }
aria-labelledby="page-layout-selector__title"
hideOnClickOutside
hideOnEsc
>
<CSSTransition
in={ hasSelectedDesign }
onEnter={ () => setIsDialogVisible( true ) }
onExited={ () => setIsDialogVisible( false ) }
timeout={ transitionTiming }
>
<div className="design-selector__page-layout-container">
<PageLayoutSelector
selectedDesign={ selectedDesign }
selectedLayouts={ selectedLayouts }
selectLayout={ toggleLayout }
templates={ otherTemplates }
/>
</div>
</CSSTransition>
</Dialog>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* External dependencies
*/
import React, { FunctionComponent } from 'react';
import { __ as NO__, sprintf } from '@wordpress/i18n';
import { __ as NO__ } from '@wordpress/i18n';
import classnames from 'classnames';

/**
Expand All @@ -23,31 +23,32 @@ interface Props {
}

const PageLayoutSelector: FunctionComponent< Props > = ( {
selectedDesign,
selectedLayouts,
selectLayout,
templates,
} ) => (
<div className="page-layout-selector">
<div className="page-layout-selector__content">
<h1 className="page-layout-selector__title">
{ selectedDesign
? sprintf( NO__( 'Select the pages you want to use with %s:' ), selectedDesign.title )
: null }
<h1
/* ID for aria-labelledby */ id="page-layout-selector__title"
className="page-layout-selector__title"
>
{ NO__( "Select the pages you'd like to include:" ) }
</h1>
<div className="page-layout-selector__grid">
{ templates.map( template => (
<Card
as="button"
className={ classnames( 'page-layout-selector__item', {
'is-selected': selectedLayouts.has( template.slug ),
} ) }
onClick={ () => selectLayout( template ) }
key={ template.slug }
>
<div className="page-layout-selector__selected-indicator">
<span className="page-layout-selector__selected-indicator">
<Icon icon="yes" size={ 24 } />
</div>
<CardMedia>
</span>
<CardMedia as="span">
<img alt={ template.description } src={ removeQueryArgs( template.preview, 'w' ) } />
</CardMedia>
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,33 +76,42 @@ $deisgn-selector-selection-space: 175px;
@include design-selector-show();
}

.page-layout-selector__container {
.design-selector__page-layout-backdrop {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
}

.design-selector__page-layout-container {
position: absolute;
top: $design-selector-header-vertical-shift + $deisgn-selector-selection-space;
width: 100%;
background: $white;
box-shadow: $dark-gray-300 0 0 12px;
padding: 2em 4em;

@include design-selector-transition();
transition-timing-function: ease-out;

&,
&.enter,
&.exit-active.exit-active, // duplicate selector to override `.exit` below
&.exit-active.exit-active , // duplicate selector to override `.exit` below
&.exit-done {
.page-layout-selector {
@include design-selector-hide();
}
@include design-selector-hide();
}

&.exit,
&.enter-active,
&.enter-done {
.page-layout-selector {
@include design-selector-show();
transform: translate3d( 0, 0, 0 );
}
@include design-selector-show();
}
}

.page-layout-selector {
@include design-selector-transition();
background: $white;
box-shadow: gray 0 0 12px; // use a sass variable
padding: 2em 4em;
max-width: $design-selector-max-width;
margin: 0 auto;
}

.design-selector__header-container {
Expand All @@ -117,7 +126,7 @@ $deisgn-selector-selection-space: 175px;

.page-layout-selector__grid {
display: grid;
grid-gap: 0.75em;
grid-gap: 1.25em;
@include breakpoint( '>660px' ) {
grid-template-columns: 1fr 1fr 1fr;
}
Expand All @@ -137,6 +146,20 @@ $deisgn-selector-selection-space: 175px;
transform: translate3d( 0, 0, 0 );
}
}

&:hover,
&:focus {
border: 3px solid var( --color-neutral-dark );
padding: 0;
.page-layout-selector__selected-indicator {
background: linear-gradient(
to bottom left,
var( --color-neutral-dark ),
var( --color-neutral-dark ) 50%,
transparent 51% /* 1% difference helps prevent a rough edge */
);
}
}
}

.page-layout-selector__selected-indicator {
Expand Down Expand Up @@ -165,4 +188,31 @@ $deisgn-selector-selection-space: 175px;
.design-selector__design-option {
transform: translate3d( 0, 0, 0 );
@include design-selector-transition();

.design-selector__option-overlay {
background-color: rgba( var( --color-primary-rgb ), 0.8 );
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: 400ms;

.design-selector__option-overlay-text {
font-size: 24px;
color: $white;
border-bottom: 2px solid $white;
}
}

&:hover,
&:focus {
.design-selector__option-overlay {
opacity: 1;
}
}
}
Loading

0 comments on commit 79cfa4d

Please sign in to comment.