fix(inputs): fix aria with shadow-dom (#16329)

This commit is contained in:
Manu MA
2018-11-16 19:26:55 +01:00
committed by GitHub
parent 10971cc3ca
commit fd79b57748
41 changed files with 399 additions and 327 deletions

View File

@ -26,7 +26,6 @@ Toggles change the state of a single option. Toggles can be switched on or off b
| `ionBlur` | Emitted when the toggle loses focus. | void |
| `ionChange` | Emitted when the value property has changed. | CheckedInputChangeEvent |
| `ionFocus` | Emitted when the toggle has focus. | void |
| `ionStyle` | Emitted when the styles change. | StyleEvent |
## CSS Custom Properties

View File

@ -77,6 +77,9 @@ describe('toggle', () => {
// spy on the ionChange event
const ionChange = await page.spyOnEvent('ionChange');
// check aria
expect(toggle).toEqualAttribute('aria-checked', 'true');
// find the hidden input in the light dom
const hiddenInput = await page.find('ion-toggle input[type=hidden]');
@ -86,16 +89,6 @@ describe('toggle', () => {
// hidden in put should have aux-input class
expect(hiddenInput).toHaveClass('aux-input');
// find the checkbox input in the shadow dom
const checkboxInput = await page.find('ion-toggle >>> input[type=checkbox]');
// checkbox input should have value on
expect(checkboxInput).toEqualAttribute('value', 'on');
// checkbox input should have checked property true
const checkedValue = await checkboxInput.getProperty('checked');
expect(checkedValue).toBe(true);
// set checked true again, no actual change
toggle.setProperty('checked', true);
@ -116,7 +109,7 @@ describe('toggle', () => {
expect(checkedValue2).toBe(false);
// hidden input property should no value
expect(hiddenInput).toEqualAttribute('value', '');
expect(toggle).toEqualAttribute('aria-checked', 'false');
expect(ionChange).toHaveReceivedEventTimes(1);

View File

@ -17,6 +17,8 @@
display: inline-block;
outline: none;
contain: content;
cursor: pointer;
touch-action: none;
@ -28,10 +30,6 @@
border: 2px solid #5e9ed6;
}
:host(:focus) {
outline: none;
}
:host(.toggle-disabled) {
pointer-events: none;
}

View File

@ -1,8 +1,8 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Prop, QueueApi, State, Watch } from '@stencil/core';
import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Prop, QueueApi, State, Watch } from '@stencil/core';
import { CheckedInputChangeEvent, Color, Gesture, GestureDetail, Mode, StyleEvent } from '../../interface';
import { hapticSelection } from '../../utils/haptic';
import { renderHiddenInput } from '../../utils/helpers';
import { findItemLabel, renderHiddenInput } from '../../utils/helpers';
import { createColorClasses, hostContext } from '../../utils/theme';
@Component({
@ -16,7 +16,6 @@ import { createColorClasses, hostContext } from '../../utils/theme';
export class Toggle implements ComponentInterface {
private inputId = `ion-tg-${toggleIds++}`;
private nativeInput!: HTMLInputElement;
private pivotX = 0;
private gesture?: Gesture;
@ -80,6 +79,7 @@ export class Toggle implements ComponentInterface {
/**
* Emitted when the styles change.
* @internal
*/
@Event() ionStyle!: EventEmitter<StyleEvent>;
@ -99,20 +99,32 @@ export class Toggle implements ComponentInterface {
}
}
@Listen('click')
onClick() {
this.checked = !this.checked;
}
@Listen('keyup')
onKeyUp() {
this.keyFocus = true;
}
@Listen('focus')
onFocus() {
this.ionFocus.emit();
}
@Listen('blur')
onBlur() {
this.keyFocus = false;
this.ionBlur.emit();
}
componentWillLoad() {
this.emitStyle();
}
async componentDidLoad() {
const parentItem = this.nativeInput.closest('ion-item');
if (parentItem) {
const itemLabel = parentItem.querySelector('ion-label');
if (itemLabel) {
itemLabel.id = this.inputId + '-lbl';
this.nativeInput.setAttribute('aria-labelledby', itemLabel.id);
}
}
this.gesture = (await import('../../utils/gesture/gesture')).createGesture({
el: this.el,
queue: this.queue,
@ -158,24 +170,6 @@ export class Toggle implements ComponentInterface {
}
this.activated = false;
this.nativeInput.focus();
}
private onChange = () => {
this.checked = !this.checked;
}
private onKeyUp = () => {
this.keyFocus = true;
}
private onFocus = () => {
this.ionFocus.emit();
}
private onBlur = () => {
this.keyFocus = false;
this.ionBlur.emit();
}
private getValue() {
@ -183,7 +177,19 @@ export class Toggle implements ComponentInterface {
}
hostData() {
const labelId = this.inputId + '-lbl';
const label = findItemLabel(this.el);
if (label) {
label.id = labelId;
}
return {
'role': 'checkbox',
'tabindex': '0',
'aria-disabled': this.disabled ? 'true' : null,
'aria-checked': `${this.checked}`,
'aria-labelledby': labelId,
class: {
...createColorClasses(this.color),
'in-item': hostContext('ion-item', this.el),
@ -198,27 +204,13 @@ export class Toggle implements ComponentInterface {
render() {
const value = this.getValue();
renderHiddenInput(this.el, this.name, (this.checked ? value : ''), this.disabled);
renderHiddenInput(true, this.el, this.name, (this.checked ? value : ''), this.disabled);
return [
return (
<div class="toggle-icon">
<div class="toggle-inner"/>
</div>,
<input
type="checkbox"
onChange={this.onChange}
onFocus={this.onFocus}
onBlur={this.onBlur}
onKeyUp={this.onKeyUp}
checked={this.checked}
id={this.inputId}
name={this.name}
value={value}
disabled={this.disabled}
ref={r => this.nativeInput = (r as any)}
/>,
<slot></slot>
];
</div>
);
}
}