mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(ripple): don't launch ripple for fake mouse events (#11997)
When using a screen reader the ripples can get fake mouse events when pressing space or enter. With the following changes we skip launching the ripples in these cases, in order to align the experience with the non-screen-reader.
This commit is contained in:
committed by
Jeremy Elbourn
parent
a2dcf21f9d
commit
4639a874c7
@@ -26,6 +26,10 @@ export function createMouseEvent(type: string, x = 0, y = 0, button = 0) {
|
||||
button, /* button */
|
||||
null /* relatedTarget */);
|
||||
|
||||
// `initMouseEvent` doesn't allow us to pass the `buttons` and
|
||||
// defaults it to 0 which looks like a fake event.
|
||||
Object.defineProperty(event, 'buttons', {get: () => 1});
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ ng_module(
|
||||
":option/optgroup.css",
|
||||
] + glob(["**/*.html"]),
|
||||
deps = [
|
||||
"//src/cdk/a11y",
|
||||
"//src/cdk/bidi",
|
||||
"//src/cdk/coercion",
|
||||
"//src/cdk/keycodes",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
import {ElementRef, NgZone} from '@angular/core';
|
||||
import {Platform, supportsPassiveEventListeners} from '@angular/cdk/platform';
|
||||
import {isFakeMousedownFromScreenReader} from '@angular/cdk/a11y';
|
||||
import {RippleRef, RippleState} from './ripple-ref';
|
||||
|
||||
export type RippleConfig = {
|
||||
@@ -246,10 +247,13 @@ export class RippleRenderer {
|
||||
|
||||
/** Function being called whenever the trigger is being pressed using mouse. */
|
||||
private onMousedown = (event: MouseEvent) => {
|
||||
// Screen readers will fire fake mouse events for space/enter. Skip launching a
|
||||
// ripple in this case for consistency with the non-screen-reader experience.
|
||||
const isFakeMousedown = isFakeMousedownFromScreenReader(event);
|
||||
const isSyntheticEvent = this._lastTouchStartEvent &&
|
||||
Date.now() < this._lastTouchStartEvent + ignoreMouseEventsTimeout;
|
||||
|
||||
if (!this._target.rippleDisabled && !isSyntheticEvent) {
|
||||
if (!this._target.rippleDisabled && !isFakeMousedown && !isSyntheticEvent) {
|
||||
this._isPointerDown = true;
|
||||
this.fadeInRipple(event.clientX, event.clientY, this._target.rippleConfig);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
createTouchEvent,
|
||||
dispatchMouseEvent,
|
||||
dispatchTouchEvent,
|
||||
createMouseEvent,
|
||||
} from '@angular/cdk/testing';
|
||||
import {defaultRippleAnimationConfig, RippleAnimationConfig} from './ripple-renderer';
|
||||
import {
|
||||
@@ -166,6 +167,15 @@ describe('MatRipple', () => {
|
||||
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
|
||||
}));
|
||||
|
||||
it('should ignore fake mouse events from screen readers', () => fakeAsync(() => {
|
||||
const event = createMouseEvent('mousedown');
|
||||
Object.defineProperty(event, 'buttons', {get: () => 0});
|
||||
|
||||
dispatchEvent(rippleTarget, event);
|
||||
tick(enterDuration);
|
||||
expect(rippleTarget.querySelector('.mat-ripple-element')).toBeFalsy();
|
||||
}));
|
||||
|
||||
it('removes ripple after timeout', fakeAsync(() => {
|
||||
dispatchMouseEvent(rippleTarget, 'mousedown');
|
||||
dispatchMouseEvent(rippleTarget, 'mouseup');
|
||||
|
||||
Reference in New Issue
Block a user