Skip to content

Commit

Permalink
fix(material-experimental/mdc-chips): prevent default space and enter
Browse files Browse the repository at this point in the history
We support pressing space or enter on the remove icon of an MDC-based chip, but we don't `preventDefault` which means that we can end up submitting a form or scrolling the page down.
  • Loading branch information
crisbeto committed Jan 1, 2020
1 parent 09dc459 commit ba1f847
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 3 deletions.
60 changes: 59 additions & 1 deletion src/material-experimental/mdc-chips/chip-remove.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import {createFakeEvent} from '@angular/cdk/testing/private';
import {
createFakeEvent,
dispatchKeyboardEvent,
createKeyboardEvent,
dispatchEvent,
} from '@angular/cdk/testing/private';
import {Component, DebugElement} from '@angular/core';
import {By} from '@angular/platform-browser';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {SPACE, ENTER} from '@angular/cdk/keycodes';
import {MatChip, MatChipsModule} from './index';

describe('MDC-based Chip Remove', () => {
Expand Down Expand Up @@ -86,6 +92,58 @@ describe('MDC-based Chip Remove', () => {
expect(buttonElement.hasAttribute('aria-hidden')).toBe(false);
});

it('should prevent the default SPACE action', () => {
const buttonElement = chipNativeElement.querySelector('button')!;

testChip.removable = true;
fixture.detectChanges();

const event = dispatchKeyboardEvent(buttonElement, 'keydown', SPACE);
fixture.detectChanges();

expect(event.defaultPrevented).toBe(true);
});

it('should not prevent the default SPACE action when a modifier key is pressed', () => {
const buttonElement = chipNativeElement.querySelector('button')!;

testChip.removable = true;
fixture.detectChanges();

const event = createKeyboardEvent('keydown', SPACE);
Object.defineProperty(event, 'shiftKey', {get: () => true});
dispatchEvent(buttonElement, event);
fixture.detectChanges();

expect(event.defaultPrevented).toBe(false);
});

it('should prevent the default ENTER action', () => {
const buttonElement = chipNativeElement.querySelector('button')!;

testChip.removable = true;
fixture.detectChanges();

const event = dispatchKeyboardEvent(buttonElement, 'keydown', ENTER);
fixture.detectChanges();

expect(event.defaultPrevented).toBe(true);
});

it('should not prevent the default ENTER action when a modifier key is pressed', () => {
const buttonElement = chipNativeElement.querySelector('button')!;

testChip.removable = true;
fixture.detectChanges();

const event = createKeyboardEvent('keydown', ENTER);
Object.defineProperty(event, 'shiftKey', {get: () => true});
dispatchEvent(buttonElement, event);
fixture.detectChanges();

expect(event.defaultPrevented).toBe(false);
});

});
});

Expand Down
17 changes: 15 additions & 2 deletions src/material-experimental/mdc-chips/chip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
} from '@angular/material/core';
import {MDCChipAdapter, MDCChipFoundation} from '@material/chips';
import {numbers} from '@material/ripple';
import {SPACE, ENTER, hasModifierKey} from '@angular/cdk/keycodes';
import {Subject} from 'rxjs';
import {takeUntil} from 'rxjs/operators';
import {MatChipAvatar, MatChipTrailingIcon, MatChipRemove} from './chip-icons';
Expand Down Expand Up @@ -351,11 +352,23 @@ export class MatChip extends _MatChipMixinBase implements AfterContentInit, Afte
// event, even ones it doesn't handle, so we want to avoid passing it keyboard events
// for which we have a custom handler. Note that we assert the type of the event using
// the `type`, because `instanceof KeyboardEvent` can throw during server-side rendering.
if (this.disabled || (event.type.startsWith('key') &&
this.HANDLED_KEYS.indexOf((event as KeyboardEvent).keyCode) !== -1)) {
const isKeyboardEvent = event.type.startsWith('key');

if (this.disabled || (isKeyboardEvent &&
this.HANDLED_KEYS.indexOf((event as KeyboardEvent).keyCode) !== -1)) {
return;
}

this._chipFoundation.handleTrailingIconInteraction(event);

if (isKeyboardEvent && !hasModifierKey(event as KeyboardEvent)) {
const keyCode = (event as KeyboardEvent).keyCode;

// Prevent default space and enter presses so we don't scroll the page or submit forms.
if (keyCode === SPACE || keyCode === ENTER) {
event.preventDefault();
}
}
});
}

Expand Down

0 comments on commit ba1f847

Please sign in to comment.