Skip to content

Commit

Permalink
fix(switch): pressing enter toggles the switch
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 638508692
  • Loading branch information
asyncLiz authored and copybara-github committed May 30, 2024
1 parent dc2ba2a commit 99ec9e2
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 6 deletions.
34 changes: 28 additions & 6 deletions switch/internal/switch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import {property, query} from 'lit/decorators.js';
import {ClassInfo, classMap} from 'lit/directives/class-map.js';

import {requestUpdateOnAriaChange} from '../../internal/aria/delegate.js';
import {
afterDispatch,
setupDispatchHooks,
} from '../../internal/events/dispatch-hooks.js';
import {
dispatchActivationClick,
isActivationClick,
Expand Down Expand Up @@ -88,15 +92,33 @@ export class Switch extends switchBaseClass {

constructor() {
super();
if (!isServer) {
this.addEventListener('click', (event: MouseEvent) => {
if (!isActivationClick(event) || !this.input) {
if (isServer) {
return;
}

// This click listener does not currently need dispatch hooks since it does
// not check `event.defaultPrevented`.
this.addEventListener('click', (event: MouseEvent) => {
if (!isActivationClick(event) || !this.input) {
return;
}
this.focus();
dispatchActivationClick(this.input);
});

// Add the aria keyboard interaction pattern for switch and the Enter key.
// See https://www.w3.org/WAI/ARIA/apg/patterns/switch/.
setupDispatchHooks(this, 'keydown');
this.addEventListener('keydown', (event: KeyboardEvent) => {
afterDispatch(event, () => {
const ignoreEvent = event.defaultPrevented || event.key !== 'Enter';
if (ignoreEvent || this.disabled || !this.input) {
return;
}
this.focus();
dispatchActivationClick(this.input);

this.input.click();
});
}
});
}

protected override render(): TemplateResult {
Expand Down
73 changes: 73 additions & 0 deletions switch/switch_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@

import {html} from 'lit';

import {Environment} from '../testing/environment.js';
import {createFormTests} from '../testing/forms.js';
import {createTokenTests} from '../testing/tokens.js';

import {SwitchHarness} from './harness.js';
import {MdSwitch} from './switch.js';

describe('<md-switch>', () => {
const env = new Environment();

describe('.styles', () => {
createTokenTests(MdSwitch.styles);
});
Expand Down Expand Up @@ -117,4 +121,73 @@ describe('<md-switch>', () => {
],
});
});

describe('enter key activation', () => {
// Don't use harness.clickWithKeyboard() since it simulates a click event.
// The underlying `<input type="checkbox">` will not dispatch click events
// in response to the Enter key.

it('should toggle the switch on', async () => {
// Arrange
const root = env.render(html`<md-switch></md-switch>`);
const harness = new SwitchHarness(root.querySelector('md-switch')!);

// Act
await harness.keypress('Enter');
await harness.element.updateComplete;

// Assert
expect(harness.element.selected)
.withContext('switch is selected after Enter')
.toBeTrue();
});

it('should toggle the switch off', async () => {
// Arrange
const root = env.render(html`<md-switch selected></md-switch>`);
const harness = new SwitchHarness(root.querySelector('md-switch')!);

// Act
await harness.keypress('Enter');
await harness.element.updateComplete;

// Assert
expect(harness.element.selected)
.withContext('switch is unselected after Enter')
.toBeFalse();
});

it('should not toggle the switch when disabled', async () => {
// Arrange
const root = env.render(html`<md-switch disabled></md-switch>`);
const harness = new SwitchHarness(root.querySelector('md-switch')!);

// Act
await harness.keypress('Enter');
await harness.element.updateComplete;

// Assert
expect(harness.element.selected)
.withContext('disabled switch is not selected after Enter')
.toBeFalse();
});

it('should not toggle the switch when keydown event is canceled', async () => {
// Arrange
const root = env.render(html`<md-switch></md-switch>`);
const harness = new SwitchHarness(root.querySelector('md-switch')!);
harness.element.addEventListener('keydown', (event) => {
event.preventDefault();
});

// Act
await harness.keypress('Enter');
await harness.element.updateComplete;

// Assert
expect(harness.element.selected)
.withContext('switch is not selected when Enter is canceled')
.toBeFalse();
});
});
});

0 comments on commit 99ec9e2

Please sign in to comment.