Skip to content

Commit 23dfbbb

Browse files
authored
fix(material/slider): don't interrupt pointer dragging when keyboard is pressed (#22849)
The slider is currently set up to "slide" either with the keyboard or the pointer, but we don't dinstinguish between the two. This means that when a `keyup` fires, it'll interrupt pointer scrolling as well. These changes add some logic to prevent the two from interfering with each other. Fixes #22719.
1 parent 3aa65ba commit 23dfbbb

File tree

3 files changed

+36
-10
lines changed

3 files changed

+36
-10
lines changed

src/material/slider/slider.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
PAGE_UP,
1010
RIGHT_ARROW,
1111
UP_ARROW,
12+
A,
1213
} from '@angular/cdk/keycodes';
1314
import {
1415
createMouseEvent,
@@ -139,6 +140,28 @@ describe('MatSlider', () => {
139140
expect(sliderNativeElement.classList).not.toContain('mat-slider-sliding');
140141
});
141142

143+
it('should not interrupt sliding by pressing a key', () => {
144+
expect(sliderNativeElement.classList).not.toContain('mat-slider-sliding');
145+
146+
dispatchSlideStartEvent(sliderNativeElement, 0);
147+
fixture.detectChanges();
148+
149+
expect(sliderNativeElement.classList).toContain('mat-slider-sliding');
150+
151+
// Any key code will do here. Use A since it isn't associated with other actions.
152+
dispatchKeyboardEvent(sliderNativeElement, 'keydown', A);
153+
fixture.detectChanges();
154+
dispatchKeyboardEvent(sliderNativeElement, 'keyup', A);
155+
fixture.detectChanges();
156+
157+
expect(sliderNativeElement.classList).toContain('mat-slider-sliding');
158+
159+
dispatchSlideEndEvent(sliderNativeElement, 0.34);
160+
fixture.detectChanges();
161+
162+
expect(sliderNativeElement.classList).not.toContain('mat-slider-sliding');
163+
});
164+
142165
it('should stop dragging if the page loses focus', () => {
143166
const classlist = sliderNativeElement.classList;
144167

src/material/slider/slider.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -326,10 +326,10 @@ export class MatSlider extends _MatSliderBase
326326
private _percent: number = 0;
327327

328328
/**
329-
* Whether or not the thumb is sliding.
329+
* Whether or not the thumb is sliding and what the user is using to slide it with.
330330
* Used to determine if there should be a transition for the thumb and fill track.
331331
*/
332-
_isSliding: boolean = false;
332+
_isSliding: 'keyboard' | 'pointer' | null = null;
333333

334334
/**
335335
* Whether or not the slider is active (clicked or sliding).
@@ -569,7 +569,8 @@ export class MatSlider extends _MatSliderBase
569569
}
570570

571571
_onKeydown(event: KeyboardEvent) {
572-
if (this.disabled || hasModifierKey(event)) {
572+
if (this.disabled || hasModifierKey(event) ||
573+
(this._isSliding && this._isSliding !== 'keyboard')) {
573574
return;
574575
}
575576

@@ -619,12 +620,14 @@ export class MatSlider extends _MatSliderBase
619620
this._emitChangeEvent();
620621
}
621622

622-
this._isSliding = true;
623+
this._isSliding = 'keyboard';
623624
event.preventDefault();
624625
}
625626

626627
_onKeyup() {
627-
this._isSliding = false;
628+
if (this._isSliding === 'keyboard') {
629+
this._isSliding = null;
630+
}
628631
}
629632

630633
/** Called when the user has put their pointer down on the slider. */
@@ -642,7 +645,7 @@ export class MatSlider extends _MatSliderBase
642645

643646
if (pointerPosition) {
644647
const oldValue = this.value;
645-
this._isSliding = true;
648+
this._isSliding = 'pointer';
646649
this._lastPointerEvent = event;
647650
event.preventDefault();
648651
this._focusHostElement();
@@ -665,7 +668,7 @@ export class MatSlider extends _MatSliderBase
665668
* starting to drag. Bound on the document level.
666669
*/
667670
private _pointerMove = (event: TouchEvent | MouseEvent) => {
668-
if (this._isSliding) {
671+
if (this._isSliding === 'pointer') {
669672
const pointerPosition = getPointerPositionOnPage(event, this._touchId);
670673

671674
if (pointerPosition) {
@@ -685,14 +688,14 @@ export class MatSlider extends _MatSliderBase
685688

686689
/** Called when the user has lifted their pointer. Bound on the document level. */
687690
private _pointerUp = (event: TouchEvent | MouseEvent) => {
688-
if (this._isSliding) {
691+
if (this._isSliding === 'pointer') {
689692
if (!isTouchEvent(event) || typeof this._touchId !== 'number' ||
690693
// Note that we use `changedTouches`, rather than `touches` because it
691694
// seems like in most cases `touches` is empty for `touchend` events.
692695
findMatchingTouch(event.changedTouches, this._touchId)) {
693696
event.preventDefault();
694697
this._removeGlobalEvents();
695-
this._isSliding = false;
698+
this._isSliding = null;
696699
this._touchId = undefined;
697700

698701
if (this._valueOnSlideStart != this.value && !this.disabled) {

tools/public_api_guard/material/slider.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export declare class MatSlider extends _MatSliderBase implements ControlValueAcc
44
_animationMode?: string | undefined;
55
protected _document: Document;
66
_isActive: boolean;
7-
_isSliding: boolean;
7+
_isSliding: 'keyboard' | 'pointer' | null;
88
readonly change: EventEmitter<MatSliderChange>;
99
get displayValue(): string | number;
1010
displayWith: (value: number) => string | number;

0 commit comments

Comments
 (0)