feat(keycodes): add utilities for checking modifier keys (#13933)

Based off of the conversation in #13790, these changes add some utilities for dealing with modifier keys on keyboard events.
This commit is contained in:
Kristiyan Kostadinov
2018-11-07 18:40:10 +00:00
committed by vivian-hu
parent 31bffb38fe
commit 78998638d3
7 changed files with 109 additions and 12 deletions
+18 -2
View File
@@ -1,10 +1,26 @@
package(default_visibility=["//visibility:public"])
load("//tools:defaults.bzl", "ts_library")
load("//tools:defaults.bzl", "ts_library", "ts_web_test_suite")
ts_library(
name = "keycodes",
module_name = "@angular/cdk/keycodes",
srcs = glob(["**/*.ts"], exclude=["**/*.spec.ts"]),
module_name = "@angular/cdk/keycodes",
deps = ["@matdeps//tslib"],
)
ts_library(
name = "keycodes_test_sources",
srcs = glob(["**/*.spec.ts"]),
deps = [
"@matdeps//@types/jasmine",
"//src/cdk/testing",
":keycodes"
],
testonly = 1,
)
ts_web_test_suite(
name = "unit_tests",
deps = [":keycodes_test_sources"],
)
+56
View File
@@ -0,0 +1,56 @@
import {createKeyboardEvent} from '@angular/cdk/testing';
import {hasModifierKey} from './modifiers';
describe('keyboard modifiers', () => {
it('should check whether the alt key is pressed', () => {
const event = createKeyboardEvent('keydown', 0);
expect(hasModifierKey(event)).toBe(false);
Object.defineProperty(event, 'altKey', {get: () => true});
expect(hasModifierKey(event)).toBe(true);
});
it('should check whether the shift key is pressed', () => {
const event = createKeyboardEvent('keydown', 0);
expect(hasModifierKey(event)).toBe(false);
Object.defineProperty(event, 'shiftKey', {get: () => true});
expect(hasModifierKey(event)).toBe(true);
});
it('should check whether the meta key is pressed', () => {
const event = createKeyboardEvent('keydown', 0);
expect(hasModifierKey(event)).toBe(false);
Object.defineProperty(event, 'metaKey', {get: () => true});
expect(hasModifierKey(event)).toBe(true);
});
it('should check whether the ctrl key is pressed', () => {
const event = createKeyboardEvent('keydown', 0);
expect(hasModifierKey(event)).toBe(false);
Object.defineProperty(event, 'ctrlKey', {get: () => true});
expect(hasModifierKey(event)).toBe(true);
});
it('should check if a particular modifier key is pressed', () => {
const event = createKeyboardEvent('keydown', 0);
Object.defineProperty(event, 'ctrlKey', {get: () => true});
expect(hasModifierKey(event, 'altKey')).toBe(false);
Object.defineProperty(event, 'altKey', {get: () => true});
expect(hasModifierKey(event, 'altKey')).toBe(true);
});
it('should check if multiple specific modifier keys are pressed', () => {
const event = createKeyboardEvent('keydown', 0);
Object.defineProperty(event, 'ctrlKey', {get: () => true});
expect(hasModifierKey(event, 'altKey', 'shiftKey')).toBe(false);
Object.defineProperty(event, 'altKey', {get: () => true});
Object.defineProperty(event, 'shiftKey', {get: () => true});
expect(hasModifierKey(event, 'altKey', 'shiftKey')).toBe(true);
});
});
+21
View File
@@ -0,0 +1,21 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
type ModifierKey = 'altKey' | 'shiftKey' | 'ctrlKey' | 'metaKey';
/**
* Checks whether a modifier key is pressed.
* @param event Event to be checked.
*/
export function hasModifierKey(event: KeyboardEvent, ...modifiers: ModifierKey[]): boolean {
if (modifiers.length) {
return modifiers.some(modifier => event[modifier]);
}
return event.altKey || event.shiftKey || event.ctrlKey || event.metaKey;
}
+1
View File
@@ -7,3 +7,4 @@
*/
export * from './keycodes';
export * from './modifiers';
+2 -4
View File
@@ -9,7 +9,7 @@
import {FocusableOption, FocusKeyManager} from '@angular/cdk/a11y';
import {Direction, Directionality} from '@angular/cdk/bidi';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {END, ENTER, HOME, SPACE} from '@angular/cdk/keycodes';
import {END, ENTER, HOME, SPACE, hasModifierKey} from '@angular/cdk/keycodes';
import {
AfterViewInit,
ChangeDetectionStrategy,
@@ -442,9 +442,7 @@ export class CdkStepper implements AfterViewInit, OnDestroy {
}
_onKeydown(event: KeyboardEvent) {
// TODO(crisbeto): move into a CDK utility once
// the similar PRs for other components are merged in.
const hasModifier = event.altKey || event.shiftKey || event.ctrlKey || event.metaKey;
const hasModifier = hasModifierKey(event);
const keyCode = event.keyCode;
const manager = this._keyManager;
+2 -2
View File
@@ -7,7 +7,7 @@
*/
import {FocusMonitor, FocusableOption, FocusOrigin} from '@angular/cdk/a11y';
import {ENTER, SPACE} from '@angular/cdk/keycodes';
import {ENTER, SPACE, hasModifierKey} from '@angular/cdk/keycodes';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
@@ -140,7 +140,7 @@ export class MatExpansionPanelHeader implements OnDestroy, FocusableOption {
// Toggle for space and enter keys.
case SPACE:
case ENTER:
if (!event.altKey && !event.metaKey && !event.shiftKey && !event.ctrlKey) {
if (!hasModifierKey(event)) {
event.preventDefault();
this._toggle();
}
+9 -4
View File
@@ -75,7 +75,14 @@ def ng_test_library(deps = [], tsconfig = None, **kwargs):
**kwargs
)
def ng_web_test_suite(deps = [], srcs = [], static_css = [], bootstrap = [], **kwargs):
def ts_web_test_suite(srcs = [], **kwargs):
_ts_web_test_suite(
# Required for running the compiled ng modules that use TypeScript import helpers.
srcs = ["@matdeps//node_modules/tslib:tslib.js"] + srcs,
**kwargs
)
def ng_web_test_suite(deps = [], static_css = [], bootstrap = [], **kwargs):
# Always include a prebuilt theme in the test suite because otherwise tests, which depend on CSS
# that is needed for measuring, will unexpectedly fail. Also always adding a prebuilt theme
# reduces the amount of setup that is needed to create a test suite Bazel target. Note that the
@@ -109,9 +116,7 @@ def ng_web_test_suite(deps = [], srcs = [], static_css = [], bootstrap = [], **k
""" % css_label
)
_ts_web_test_suite(
# Required for running the compiled ng modules that use TypeScript import helpers.
srcs = ["@matdeps//node_modules/tslib:tslib.js"] + srcs,
ts_web_test_suite(
# Depend on our custom test initialization script. This needs to be the first dependency.
deps = ["//test:angular_test_init"] + deps,
bootstrap = [