@@ -341,7 +341,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
disabled={i.disabled}
id={i.id}
tabIndex={0}
- class="alert-radio-button alert-tappable alert-radio"
+ class="alert-radio-button alert-tappable alert-radio ion-focusable"
role="radio"
>
@@ -385,7 +385,8 @@ export class Alert implements ComponentInterface, OverlayInterface {
hostData() {
return {
- role: 'alertdialog',
+ 'role': 'dialog',
+ 'aria-modal': 'true',
style: {
zIndex: 20000 + this.overlayIndex,
},
@@ -451,6 +452,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
function buttonClass(button: AlertButton): CssClassMap {
return {
'alert-button': true,
+ 'ion-focusable': true,
'ion-activatable': true,
...getClassMap(button.cssClass)
};
diff --git a/core/src/components/anchor/anchor.tsx b/core/src/components/anchor/anchor.tsx
index 1eaf574db8..8bc8f149e6 100644
--- a/core/src/components/anchor/anchor.tsx
+++ b/core/src/components/anchor/anchor.tsx
@@ -1,4 +1,4 @@
-import { Component, ComponentInterface, Prop } from '@stencil/core';
+import { Component, ComponentInterface, Listen, Prop } from '@stencil/core';
import { Color, RouterDirection } from '../../interface';
import { createColorClasses, openURL } from '../../utils/theme';
@@ -31,6 +31,11 @@ export class Anchor implements ComponentInterface {
*/
@Prop() routerDirection: RouterDirection = 'forward';
+ @Listen('click')
+ onClick(ev: Event) {
+ openURL(this.win, this.href, ev, this.routerDirection);
+ }
+
hostData() {
return {
class: {
@@ -42,10 +47,7 @@ export class Anchor implements ComponentInterface {
render() {
return (
-
openURL(this.win, this.href, ev, this.routerDirection)}
- >
+
);
diff --git a/core/src/components/app/app.tsx b/core/src/components/app/app.tsx
index 702f329f8e..22f18660fa 100644
--- a/core/src/components/app/app.tsx
+++ b/core/src/components/app/app.tsx
@@ -27,6 +27,7 @@ export class App implements ComponentInterface {
importInputShims(win, config);
importStatusTap(win, config, queue);
importHardwareBackButton(win, config);
+ importFocusVisible(win);
});
}
@@ -54,6 +55,10 @@ function importStatusTap(win: Window, config: Config, queue: QueueApi) {
}
}
+function importFocusVisible(win: Window) {
+ import('../../utils/focus-visible').then(module => module.startFocusVisible(win.document));
+}
+
function importTapClick(win: Window, config: Config) {
import('../../utils/tap-click').then(module => module.startTapClick(win.document, config));
}
diff --git a/core/src/components/back-button/back-button.tsx b/core/src/components/back-button/back-button.tsx
index 51d1180a86..5f55176344 100644
--- a/core/src/components/back-button/back-button.tsx
+++ b/core/src/components/back-button/back-button.tsx
@@ -1,4 +1,4 @@
-import { Component, ComponentInterface, Element, Prop } from '@stencil/core';
+import { Component, ComponentInterface, Element, Listen, Prop } from '@stencil/core';
import { Color, Config, Mode } from '../../interface';
import { createColorClasses, openURL } from '../../utils/theme';
@@ -45,6 +45,7 @@ export class BackButton implements ComponentInterface {
*/
@Prop() text?: string | null;
+ @Listen('click')
async onClick(ev: Event) {
const nav = this.el.closest('ion-nav');
ev.preventDefault();
@@ -78,7 +79,6 @@ export class BackButton implements ComponentInterface {
,
,
];
diff --git a/core/src/components/range/range.tsx b/core/src/components/range/range.tsx
index aa21c46a0e..ff1c446717 100644
--- a/core/src/components/range/range.tsx
+++ b/core/src/components/range/range.tsx
@@ -165,7 +165,7 @@ export class Range implements ComponentInterface {
this.gesture.setDisabled(this.disabled);
}
- private handleKeyboard(knob: string, isIncrease: boolean) {
+ private handleKeyboard = (knob: string, isIncrease: boolean) => {
let step = this.step;
step = step > 0 ? step : 1;
step = step / (this.max - this.min);
@@ -173,9 +173,9 @@ export class Range implements ComponentInterface {
step *= -1;
}
if (knob === 'A') {
- this.ratioA += step;
+ this.ratioA = clamp(0, this.ratioA + step, 1);
} else {
- this.ratioB += step;
+ this.ratioB = clamp(0, this.ratioB + step, 1);
}
this.updateValue();
}
@@ -378,7 +378,7 @@ export class Range implements ComponentInterface {
ratio: this.ratioA,
pin: this.pin,
disabled: this.disabled,
- handleKeyboard: this.handleKeyboard.bind(this),
+ handleKeyboard: this.handleKeyboard,
min,
max
})}
@@ -390,7 +390,7 @@ export class Range implements ComponentInterface {
ratio: this.ratioB,
pin: this.pin,
disabled: this.disabled,
- handleKeyboard: this.handleKeyboard.bind(this),
+ handleKeyboard: this.handleKeyboard,
min,
max
})}
diff --git a/core/src/components/segment-button/segment-button.tsx b/core/src/components/segment-button/segment-button.tsx
index 379b660c68..271423fb22 100644
--- a/core/src/components/segment-button/segment-button.tsx
+++ b/core/src/components/segment-button/segment-button.tsx
@@ -1,4 +1,4 @@
-import { Component, ComponentInterface, Element, Event, EventEmitter, Prop, Watch } from '@stencil/core';
+import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Prop, Watch } from '@stencil/core';
import { Mode, SegmentButtonLayout } from '../../interface';
@@ -53,7 +53,8 @@ export class SegmentButton implements ComponentInterface {
}
}
- private onClick = () => {
+ @Listen('click')
+ onClick() {
this.checked = true;
}
@@ -90,7 +91,6 @@ export class SegmentButton implements ComponentInterface {
aria-pressed={this.checked ? 'true' : null}
class="button-native"
disabled={this.disabled}
- onClick={this.onClick}
>
{this.mode === 'md' &&
}
diff --git a/core/src/components/select/select.scss b/core/src/components/select/select.scss
index b87dd180b7..166515a28b 100644
--- a/core/src/components/select/select.scss
+++ b/core/src/components/select/select.scss
@@ -32,7 +32,7 @@
pointer-events: none;
}
-:host(.select-key) button {
+:host(.ion-focused) button {
border: 2px solid #5e9ed6;
}
diff --git a/core/src/components/select/select.tsx b/core/src/components/select/select.tsx
index 6bd9f579f4..ef3795c028 100644
--- a/core/src/components/select/select.tsx
+++ b/core/src/components/select/select.tsx
@@ -18,6 +18,7 @@ export class Select implements ComponentInterface {
private inputId = `ion-sel-${selectIds++}`;
private overlay?: OverlaySelect;
private didInit = false;
+ private buttonEl?: HTMLButtonElement;
@Element() el!: HTMLIonSelectElement;
@@ -26,7 +27,6 @@ export class Select implements ComponentInterface {
@Prop({ connect: 'ion-popover-controller' }) popoverCtrl!: HTMLIonPopoverControllerElement;
@State() isExpanded = false;
- @State() keyFocus = false;
/**
* The mode determines which platform styles to use.
@@ -138,6 +138,11 @@ export class Select implements ComponentInterface {
}
}
+ @Listen('click')
+ onClick() {
+ this.open();
+ }
+
async componentDidLoad() {
await this.loadOptions();
@@ -174,6 +179,7 @@ export class Select implements ComponentInterface {
overlay.onDidDismiss().then(() => {
this.overlay = undefined;
this.isExpanded = false;
+ this.setFocus();
});
await overlay.present();
return overlay;
@@ -353,6 +359,12 @@ export class Select implements ComponentInterface {
return generateText(this.childOpts, this.value);
}
+ private setFocus() {
+ if (this.buttonEl) {
+ this.buttonEl.focus();
+ }
+ }
+
private emitStyle() {
this.ionStyle.emit({
'interactive': true,
@@ -364,20 +376,11 @@ export class Select implements ComponentInterface {
});
}
- private onClick = (ev: UIEvent) => {
- this.open(ev);
- }
-
- private onKeyUp = () => {
- this.keyFocus = true;
- }
-
private onFocus = () => {
this.ionFocus.emit();
}
private onBlur = () => {
- this.keyFocus = false;
this.ionBlur.emit();
}
@@ -397,7 +400,6 @@ export class Select implements ComponentInterface {
class: {
'in-item': hostContext('ion-item', this.el),
'select-disabled': this.disabled,
- 'select-key': this.keyFocus
}
};
}
@@ -432,10 +434,10 @@ export class Select implements ComponentInterface {
];
diff --git a/core/src/components/toggle/toggle.scss b/core/src/components/toggle/toggle.scss
index eb4bb6d47a..5f868b6a13 100644
--- a/core/src/components/toggle/toggle.scss
+++ b/core/src/components/toggle/toggle.scss
@@ -25,7 +25,7 @@
z-index: $z-index-item-input;
}
-:host(.toggle-key) input {
+:host(.ion-focused) input {
border: 2px solid #5e9ed6;
}
@@ -33,8 +33,7 @@
pointer-events: none;
}
-input {
+button {
@include input-cover();
-
- pointer-events: none;
}
+
diff --git a/core/src/components/toggle/toggle.tsx b/core/src/components/toggle/toggle.tsx
index b5ebcef1aa..bdca2a1daa 100644
--- a/core/src/components/toggle/toggle.tsx
+++ b/core/src/components/toggle/toggle.tsx
@@ -24,7 +24,6 @@ export class Toggle implements ComponentInterface {
@Prop({ context: 'queue' }) queue!: QueueApi;
@State() activated = false;
- @State() keyFocus = false;
/**
* The mode determines which platform styles to use.
@@ -99,27 +98,6 @@ 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();
}
@@ -138,6 +116,11 @@ export class Toggle implements ComponentInterface {
this.disabledChanged();
}
+ @Listen('click')
+ onClick() {
+ this.checked = !this.checked;
+ }
+
private emitStyle() {
this.ionStyle.emit({
'interactive-disabled': this.disabled,
@@ -176,27 +159,34 @@ export class Toggle implements ComponentInterface {
return this.value || '';
}
+ private onFocus = () => {
+ this.ionFocus.emit();
+ }
+
+ private onBlur = () => {
+ this.ionBlur.emit();
+ }
+
hostData() {
- const labelId = this.inputId + '-lbl';
- const label = findItemLabel(this.el);
+ const { inputId, disabled, checked, activated, color, el } = this;
+ const labelId = inputId + '-lbl';
+ const label = findItemLabel(el);
if (label) {
label.id = labelId;
}
return {
'role': 'checkbox',
- 'tabindex': '0',
- 'aria-disabled': this.disabled ? 'true' : null,
- 'aria-checked': `${this.checked}`,
+ 'aria-disabled': disabled ? 'true' : null,
+ 'aria-checked': `${checked}`,
'aria-labelledby': labelId,
class: {
- ...createColorClasses(this.color),
- 'in-item': hostContext('ion-item', this.el),
- 'toggle-activated': this.activated,
- 'toggle-checked': this.checked,
- 'toggle-disabled': this.disabled,
- 'toggle-key': this.keyFocus,
+ ...createColorClasses(color),
+ 'in-item': hostContext('ion-item', el),
+ 'toggle-activated': activated,
+ 'toggle-checked': checked,
+ 'toggle-disabled': disabled,
'interactive': true
}
};
@@ -206,11 +196,18 @@ export class Toggle implements ComponentInterface {
const value = this.getValue();
renderHiddenInput(true, this.el, this.name, (this.checked ? value : ''), this.disabled);
- return (
+ return [