fix(alert): alert radio, checkbox and aria fixes

This commit is contained in:
Adam Bradley
2017-10-25 15:07:22 -05:00
parent 21d8a60193
commit 059a1330d9

View File

@ -20,6 +20,7 @@ export class Alert {
private animation: Animation; private animation: Animation;
private activeId: string; private activeId: string;
private inputType: string; private inputType: string;
private hdrId: string;
@Element() private el: HTMLElement; @Element() private el: HTMLElement;
@ -38,7 +39,7 @@ export class Alert {
@Prop() subTitle: string; @Prop() subTitle: string;
@Prop() message: string; @Prop() message: string;
@Prop() buttons: AlertButton[] = []; @Prop() buttons: AlertButton[] = [];
@Prop() inputs: AlertInput[] = []; @Prop({ mutable: true }) inputs: AlertInput[] = [];
@Prop() enableBackdropDismiss: boolean = true; @Prop() enableBackdropDismiss: boolean = true;
@Prop() enterAnimation: AnimationBuilder; @Prop() enterAnimation: AnimationBuilder;
@ -73,6 +74,12 @@ export class Alert {
animation.onFinish((a: any) => { animation.onFinish((a: any) => {
a.destroy(); a.destroy();
const firstInput = this.el.querySelector('[tabindex]') as HTMLElement;
if (firstInput) {
firstInput.focus();
}
this.ionViewDidEnter(); this.ionViewDidEnter();
resolve(); resolve();
}).play(); }).play();
@ -143,22 +150,31 @@ export class Alert {
} }
} }
rbClick(button: any) { rbClick(inputIndex: number) {
this.inputs.forEach(input => { this.inputs = this.inputs.map((input, index) => {
input.checked = (button === input); input.checked = (inputIndex === index);
return input;
}); });
this.activeId = button.id;
if (button.handler) { const rbButton = this.inputs[inputIndex];
button.handler(button); this.activeId = rbButton.id;
if (rbButton.handler) {
rbButton.handler(rbButton);
} }
} }
cbClick(button: any) { cbClick(inputIndex: number) {
button.checked = !button.checked; this.inputs = this.inputs.map((input, index) => {
if (inputIndex === index) {
input.checked = !input.checked;
}
return input;
});
if (button.handler) { const cbButton = this.inputs[inputIndex];
button.handler(button); if (cbButton.handler) {
cbButton.handler(cbButton);
} }
} }
@ -233,8 +249,8 @@ export class Alert {
return ( return (
<div class='alert-checkbox-group'> <div class='alert-checkbox-group'>
{ inputs.map(i => ( { inputs.map((i, index) => (
<button onClick={() => this.cbClick(i)} aria-checked={i.checked} id={i.id} disabled={i.disabled} role='checkbox' class='alert-tappable alert-checkbox alert-checkbox-button'> <button onClick={() => this.cbClick(index)} aria-checked={i.checked} id={i.id} disabled={i.disabled} tabIndex={0} role='checkbox' class='alert-tappable alert-checkbox alert-checkbox-button'>
<div class='button-inner'> <div class='button-inner'>
<div class='alert-checkbox-icon'><div class='alert-checkbox-inner'></div></div> <div class='alert-checkbox-icon'><div class='alert-checkbox-inner'></div></div>
<div class='alert-checkbox-label'> <div class='alert-checkbox-label'>
@ -248,14 +264,12 @@ export class Alert {
} }
renderRadio(inputs: AlertInput[]) { renderRadio(inputs: AlertInput[]) {
const hdrId = 'TODO';
if (inputs.length === 0) return null; if (inputs.length === 0) return null;
return ( return (
<div class='alert-radio-group' role='radiogroup' aria-labelledby={hdrId} aria-activedescendant={this.activeId}> <div class='alert-radio-group' role='radiogroup' aria-labelledby={this.hdrId} aria-activedescendant={this.activeId}>
{ inputs.map(i => ( { inputs.map((i, index) => (
<button onClick={() => this.rbClick(i)} aria-checked={i.checked} disabled={i.disabled} id={i.id} class='alert-radio-button alert-tappable alert-radio' role='radio'> <button onClick={() => this.rbClick(index)} aria-checked={i.checked} disabled={i.disabled} id={i.id} tabIndex={0} class='alert-radio-button alert-tappable alert-radio' role='radio'>
<div class='button-inner'> <div class='button-inner'>
<div class='alert-radio-icon'><div class='alert-radio-inner'></div></div> <div class='alert-radio-icon'><div class='alert-radio-inner'></div></div>
<div class='alert-radio-label'> <div class='alert-radio-label'>
@ -282,6 +296,7 @@ export class Alert {
min={i.min} min={i.min}
max={i.max} max={i.max}
id={i.id} id={i.id}
tabIndex={0}
class='alert-input'/> class='alert-input'/>
</div> </div>
))} ))}
@ -290,16 +305,23 @@ export class Alert {
} }
protected render() { protected render() {
const hdrId = 'TODO'; const hdrId = `${this.alertId}-hdr`;
const subHdrId = 'TODO'; const subHdrId = `${this.alertId}-sub-hdr`;
const msgId = 'TODO'; const msgId = `${this.alertId}-msg`;
if (this.title || !this.subTitle) {
this.hdrId = hdrId;
} else if (this.subTitle) {
this.hdrId = subHdrId;
}
const alertButtonGroupClass = { const alertButtonGroupClass = {
'alert-button-group': true, 'alert-button-group': true,
'alert-button-group-vertical': this.buttons.length > 2 'alert-button-group-vertical': this.buttons.length > 2
}; };
let buttons = this.buttons const buttons = this.buttons
.map(b => { .map(b => {
if (typeof b === 'string') { if (typeof b === 'string') {
b = { text: b }; b = { text: b };
@ -312,9 +334,9 @@ export class Alert {
// checkboxes and inputs are all accepted, but they cannot be mixed. // checkboxes and inputs are all accepted, but they cannot be mixed.
const inputTypes: string[] = []; const inputTypes: string[] = [];
const inputs = this.inputs this.inputs = this.inputs
.map((i, index) => { .map((i, index) => {
const r: AlertInput = { let r: AlertInput = {
type: i.type || 'text', type: i.type || 'text',
name: i.name ? i.name : index + '', name: i.name ? i.name : index + '',
placeholder: i.placeholder ? i.placeholder : '', placeholder: i.placeholder ? i.placeholder : '',
@ -331,7 +353,7 @@ export class Alert {
}) })
.filter(i => i !== null); .filter(i => i !== null);
inputs.forEach(i => { this.inputs.forEach(i => {
if (inputTypes.indexOf(i.type) < 0) { if (inputTypes.indexOf(i.type) < 0) {
inputTypes.push(i.type); inputTypes.push(i.type);
} }
@ -362,19 +384,19 @@ export class Alert {
{(() => { {(() => {
switch (this.inputType) { switch (this.inputType) {
case 'checkbox': case 'checkbox':
return this.renderCheckbox(inputs); return this.renderCheckbox(this.inputs);
case 'radio': case 'radio':
return this.renderRadio(inputs); return this.renderRadio(this.inputs);
default: default:
return this.renderInput(inputs); return this.renderInput(this.inputs);
} }
})()} })()}
<div class={alertButtonGroupClass}> <div class={alertButtonGroupClass}>
{buttons.map(b => {buttons.map(b =>
<button class={this.buttonClass(b)} onClick={() => this.buttonClick(b)}> <button class={this.buttonClass(b)} tabIndex={0} onClick={() => this.buttonClick(b)}>
<span class='button-inner'> <span class='button-inner'>
{b.text} {b.text}
</span> </span>
@ -385,8 +407,15 @@ export class Alert {
]; ];
} }
hostData() {
return {
id: this.alertId
};
}
} }
export interface AlertOptions { export interface AlertOptions {
title?: string; title?: string;
subTitle?: string; subTitle?: string;