Skip to content

Commit

Permalink
Accessibility: Drop the embeded FormToggle label and replace with hint
Browse files Browse the repository at this point in the history
  • Loading branch information
youknowriad committed May 29, 2017
1 parent 9350454 commit 48ab106
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 112 deletions.
55 changes: 23 additions & 32 deletions components/form-toggle/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,36 @@ import { noop } from 'lodash';
/**
* WordPress dependencies
*/
import { Component } from 'element';
import { __ } from 'i18n';

/**
* Internal dependencies
*/
import './style.scss';

class FormToggle extends Component {
constructor() {
super( ...arguments );
this.id = this.constructor.instances++;
}
function FormToggle( { className, checked, id, onChange = noop, showHint = true } ) {
const wrapperClasses = classNames(
'components-form-toggle',
className,
{ 'is-checked': checked }
);

render() {
const { className, checked, children, onChange = noop } = this.props;
const id = 'toggle-' + this.id;
const wrapperClasses = classNames(
'components-form-toggle',
className,
{ 'is-checked': checked }
);

return (
<div className={ wrapperClasses }>
<input
className="components-form-toggle__input"
id={ id }
type="checkbox"
value={ checked }
onChange={ onChange }
/>
<label className="components-form-toggle__label" htmlFor={ id }>
{ children }
</label>
</div>
);
}
return (
<span className={ wrapperClasses }>
<input
className="components-form-toggle__input"
id={ id }
type="checkbox"
value={ checked }
onChange={ onChange }
/>
{ showHint &&
<span className="components-form-toggle__hint" aria-hidden>
{ checked ? __( 'On' ) : __( 'Off' ) }
</span>
}
</span>
);
}

FormToggle.instances = 1;

export default FormToggle;
50 changes: 30 additions & 20 deletions components/form-toggle/style.scss
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
.components-form-toggle {
position: relative;
}

.components-form-toggle__input[type=checkbox] {
position: absolute;
opacity: 0;
pointer-events: none;
margin: 0;
padding: 0;
}

$toggle-width: 32px;
$toggle-height: 18px;
$toggle-border-width: 2px;
.components-form-toggle__label {

.components-form-toggle {
position: relative;

&:before {
content: '';
display: inline-block;
Expand All @@ -34,11 +25,6 @@ $toggle-border-width: 2px;

&:hover:before {
background-color: $light-gray-500;

.components-form-toggle.is-checked & {
background-color: $blue-medium;
border: $toggle-border-width solid $blue-medium;
}
}

&:after {
Expand All @@ -52,11 +38,35 @@ $toggle-border-width: 2px;
border-radius: 50%;
background: $dark-gray-500;
transition: 0.1s transform ease;
}


.components-form-toggle.is-checked & {
&.is-checked {
&:after {
background-color: $white;
transform: translateX( $toggle-width - ( $toggle-border-width * 4 ) - ( $toggle-height - ( $toggle-border-width * 4 ) ) );
}

&:before {
background-color: $blue-medium;
border: $toggle-border-width solid $blue-medium;
}
}
}

.components-form-toggle__input[type=checkbox] {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
margin: 0;
padding: 0;
z-index: z-index( '.components-form-toggle__input' );
}

.components-form-toggle__hint {
display: inline-block;
margin-left: 10px;
font-weight: 500;
}
1 change: 1 addition & 0 deletions editor/assets/stylesheets/_z-index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ $z-layers: (
'.editor-visual-editor__block:before': -1,
'.editor-visual-editor__block {core/image aligned left or right}': 10,
'.editor-visual-editor__block-controls': 1,
'.components-form-toggle__input': 1,
'.editor-header': 20,
'.editor-post-visibility__dialog': 30,
'.editor-post-schedule__dialog': 30,
Expand Down
65 changes: 40 additions & 25 deletions editor/sidebar/discussion-panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { connect } from 'react-redux';
* WordPress dependencies
*/
import { __ } from 'i18n';
import { Component } from 'element';
import PanelBody from 'components/panel/body';
import FormToggle from 'components/form-toggle';

Expand All @@ -17,33 +18,47 @@ import './style.scss';
import { getEditedPostAttribute } from '../../selectors';
import { editPost } from '../../actions';

function DiscussionPanel( { pingStatus = 'open', commentStatus = 'open', ...props } ) {
const onTogglePingback = () => props.editPost( { ping_status: pingStatus === 'open' ? 'closed' : 'open' } );
const onToggleComments = () => props.editPost( { comment_status: commentStatus === 'open' ? 'closed' : 'open' } );

// Disable Reason: The input is inside the label, we shouldn't need the htmlFor
/* eslint-disable jsx-a11y/label-has-for */
return (
<PanelBody title={ __( 'Discussion' ) } initialOpen={ false }>
<label className="editor-discussion-panel__row">
<span>{ __( 'Allow Comments' ) }</span>
<FormToggle
checked={ commentStatus === 'open' }
onChange={ onToggleComments }
/>
</label>
<label className="editor-discussion-panel__row">
<span>{ __( 'Allow Pingbacks & Trackbacks' ) }</span>
<FormToggle
checked={ pingStatus === 'open' }
onChange={ onTogglePingback }
/>
</label>
</PanelBody>
);
/* eslint-enable jsx-a11y/label-has-for */
class DiscussionPanel extends Component {
constructor() {
super( ...arguments );
this.id = this.constructor.instances++;
}

render() {
const { pingStatus = 'open', commentStatus = 'open', ...props } = this.props;
const onTogglePingback = () => props.editPost( { ping_status: pingStatus === 'open' ? 'closed' : 'open' } );
const onToggleComments = () => props.editPost( { comment_status: commentStatus === 'open' ? 'closed' : 'open' } );

const commentsToggleId = 'allow-comments-toggle-' + this.id;
const pingbacksToggleId = 'allow-pingbacks-toggle-' + this.id;

return (
<PanelBody title={ __( 'Discussion' ) } initialOpen={ false }>
<div className="editor-discussion-panel__row">
<label htmlFor={ commentsToggleId }>{ __( 'Allow Comments' ) }</label>
<FormToggle
checked={ commentStatus === 'open' }
onChange={ onToggleComments }
showHint={ false }
id={ commentsToggleId }
/>
</div>
<div className="editor-discussion-panel__row">
<label htmlFor={ pingbacksToggleId }>{ __( 'Allow Pingbacks & Trackbacks' ) }</label>
<FormToggle
checked={ pingStatus === 'open' }
onChange={ onTogglePingback }
showHint={ false }
id={ pingbacksToggleId }
/>
</div>
</PanelBody>
);
}
}

DiscussionPanel.instances = 1;

export default connect(
( state ) => {
return {
Expand Down
81 changes: 46 additions & 35 deletions editor/sidebar/post-status/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { connect } from 'react-redux';
* WordPress dependencies
*/
import { __ } from 'i18n';
import { Component } from 'element';
import PanelBody from 'components/panel/body';
import FormToggle from 'components/form-toggle';

Expand All @@ -20,45 +21,55 @@ import PostSchedule from '../post-schedule';
import { getEditedPostStatus, getSuggestedPostFormat } from '../../selectors';
import { editPost } from '../../actions';

function PostStatus( { status, onUpdateStatus, suggestedFormat } ) {
const onToggle = () => {
const updatedStatus = status === 'pending' ? 'draft' : 'pending';
onUpdateStatus( updatedStatus );
};
class PostStatus extends Component {
constructor() {
super( ...arguments );
this.id = this.constructor.instances++;
}

render() {
const { status, onUpdateStatus, suggestedFormat } = this.props;
const onToggle = () => {
const updatedStatus = status === 'pending' ? 'draft' : 'pending';
onUpdateStatus( updatedStatus );
};

// Use the suggested post format based on the blocks content of the post
// or the default post format setting for the site.
const format = suggestedFormat || __( 'Standard' );
// Use the suggested post format based on the blocks content of the post
// or the default post format setting for the site.
const format = suggestedFormat || __( 'Standard' );
const pendingId = 'pending-toggle-' + this.id;

// Disable Reason: The input is inside the label, we shouldn't need the htmlFor
/* eslint-disable jsx-a11y/label-has-for */
return (
<PanelBody title={ __( 'Status & Visibility' ) }>
<label className="editor-post-status__row">
<span>{ __( 'Pending review' ) }</span>
<FormToggle
checked={ status === 'pending' }
onChange={ onToggle }
/>
</label>
<div className="editor-post-status__row">
<PostVisibility />
</div>
<div className="editor-post-status__row">
<PostSchedule />
</div>
<div className="editor-post-status__row">
<span>{ __( 'Post Format' ) }</span>
<span>{ format }</span>
</div>
<div className="editor-post-status__row">
<PostTrash />
</div>
</PanelBody>
);
/* eslint-enable jsx-a11y/label-has-for */
return (
<PanelBody title={ __( 'Status & Visibility' ) }>
<div className="editor-post-status__row">
<label htmlFor={ pendingId }>{ __( 'Pending review' ) }</label>
<FormToggle
id={ pendingId }
checked={ status === 'pending' }
onChange={ onToggle }
showHint={ false }
/>
</div>
<div className="editor-post-status__row">
<PostVisibility />
</div>
<div className="editor-post-status__row">
<PostSchedule />
</div>
<div className="editor-post-status__row">
<span>{ __( 'Post Format' ) }</span>
<span>{ format }</span>
</div>
<div className="editor-post-status__row">
<PostTrash />
</div>
</PanelBody>
);
}
}

PostStatus.instances = 1;

export default connect(
( state ) => ( {
status: getEditedPostStatus( state ),
Expand Down

0 comments on commit 48ab106

Please sign in to comment.