@@ -32,7 +32,14 @@ import {
32
32
ViewChildren ,
33
33
ViewEncapsulation ,
34
34
} from '@angular/core' ;
35
- import { CanColorCtor , mixinColor } from '@angular/material/core' ;
35
+ import {
36
+ CanColorCtor ,
37
+ MatRipple ,
38
+ mixinColor ,
39
+ RippleAnimationConfig ,
40
+ RippleRef ,
41
+ RippleState ,
42
+ } from '@angular/material/core' ;
36
43
import { SpecificEventListener , EventType } from '@material/base' ;
37
44
import { MDCSliderAdapter , MDCSliderFoundation , Thumb , TickMark } from '@material/slider' ;
38
45
@@ -48,6 +55,171 @@ export interface MatSliderDragEvent {
48
55
value : number ;
49
56
}
50
57
58
+ /**
59
+ * The visual slider thumb.
60
+ *
61
+ * Handles the slider thumb ripple states (hover, focus, and active),
62
+ * and displaying the value tooltip on discrete sliders.
63
+ */
64
+ @Component ( {
65
+ selector : 'mat-slider-visual-start-thumb, mat-slider-visual-end-thumb' ,
66
+ templateUrl : './slider-thumb.html' ,
67
+ host : {
68
+ 'class' : 'mdc-slider__thumb' ,
69
+ '(mouseenter)' : '_onMouseEnter()' ,
70
+ '(mouseleave)' : '_onMouseLeave()' ,
71
+ }
72
+ } )
73
+ export class MatSliderVisualThumb {
74
+ /** Whether the slider displays a numeric value label upon pressing the thumb. */
75
+ @Input ( ) _discrete : boolean ;
76
+
77
+ /** The display value of the slider thumb. */
78
+ @Input ( ) _valueIndicatorText : string ;
79
+
80
+ /** The MatRipple for this slider thumb. */
81
+ @ViewChild ( MatRipple ) private readonly _ripple : MatRipple ;
82
+
83
+ /** The slider thumb knob */
84
+ @ViewChild ( 'knob' ) _knob : ElementRef < HTMLElement > ;
85
+
86
+ /** Indicates which slider thumb this input corresponds to. */
87
+ _thumbPosition : Thumb =
88
+ this . _elementRef . nativeElement . tagName . toLowerCase ( )
89
+ === 'mat-slider-visual-start-thumb' . toLowerCase ( )
90
+ ? Thumb . START
91
+ : Thumb . END ;
92
+
93
+ /** The slider input corresponding to this slider thumb. */
94
+ private _sliderInput : MatSliderThumb ;
95
+
96
+ /** The RippleRef for the slider thumbs hover state. */
97
+ private _hoverRippleRef : RippleRef ;
98
+
99
+ /** The RippleRef for the slider thumbs focus state. */
100
+ private _focusRippleRef : RippleRef ;
101
+
102
+ /** The RippleRef for the slider thumbs active state. */
103
+ private _activeRippleRef : RippleRef ;
104
+
105
+ /** Whether the slider thumb is currently being pressed. */
106
+ private _isActive : boolean = false ;
107
+
108
+ /** Whether the slider thumb is currently being hovered. */
109
+ private _isHovered : boolean = false ;
110
+
111
+ constructor (
112
+ private readonly _slider : MatSlider ,
113
+ private readonly _elementRef : ElementRef < HTMLElement > ) { }
114
+
115
+ ngAfterViewInit ( ) {
116
+ this . _ripple . radius = 24 ;
117
+ this . _sliderInput = this . _slider . _getInput ( this . _thumbPosition ) ;
118
+
119
+ this . _sliderInput . dragStart . subscribe ( ( e : MatSliderDragEvent ) => this . _onDragStart ( e ) ) ;
120
+ this . _sliderInput . dragEnd . subscribe ( ( e : MatSliderDragEvent ) => this . _onDragEnd ( e ) ) ;
121
+
122
+ this . _sliderInput . _focus . subscribe ( ( ) => this . _onFocus ( ) ) ;
123
+ this . _sliderInput . _blur . subscribe ( ( ) => this . _onBlur ( ) ) ;
124
+ }
125
+
126
+ _onMouseEnter ( ) : void {
127
+ this . _isHovered = true ;
128
+ // We don't want to show the hover ripple on top of the focus ripple.
129
+ // This can happen if the user tabs to a thumb and then the user moves their cursor over it.
130
+ if ( ! this . _isShowingRipple ( this . _focusRippleRef ) ) {
131
+ this . _showHoverRipple ( ) ;
132
+ }
133
+ }
134
+
135
+ _onMouseLeave ( ) : void {
136
+ this . _isHovered = false ;
137
+ this . _hoverRippleRef ?. fadeOut ( ) ;
138
+ }
139
+
140
+ private _onFocus ( ) : void {
141
+ // We don't want to show the hover ripple on top of the focus ripple.
142
+ // Happen when the users cursor is over a thumb and then the user tabs to it.
143
+ this . _hoverRippleRef ?. fadeOut ( ) ;
144
+ this . _showFocusRipple ( ) ;
145
+ }
146
+
147
+ private _onBlur ( ) : void {
148
+ // Happens when the user tabs away while still dragging a thumb.
149
+ if ( ! this . _isActive ) {
150
+ this . _focusRippleRef ?. fadeOut ( ) ;
151
+ }
152
+ // Happens when the user tabs away from a thumb but their cursor is still over it.
153
+ if ( this . _isHovered ) {
154
+ this . _showHoverRipple ( ) ;
155
+ }
156
+ }
157
+
158
+ private _onDragStart ( event : MatSliderDragEvent ) : void {
159
+ if ( event . source . _thumbPosition === this . _thumbPosition ) {
160
+ this . _isActive = true ;
161
+ this . _showActiveRipple ( ) ;
162
+ }
163
+ }
164
+
165
+ private _onDragEnd ( event : MatSliderDragEvent ) : void {
166
+ if ( event . source . _thumbPosition === this . _thumbPosition ) {
167
+ this . _isActive = false ;
168
+ this . _activeRippleRef ?. fadeOut ( ) ;
169
+ // Happens when the user starts dragging a thumb, tabs away, and then stops dragging.
170
+ if ( ! this . _sliderInput . _isFocused ( ) ) {
171
+ this . _focusRippleRef ?. fadeOut ( ) ;
172
+ }
173
+ }
174
+ }
175
+
176
+ /** Handles displaying the hover ripple. */
177
+ private _showHoverRipple ( ) : void {
178
+ if ( ! this . _isShowingRipple ( this . _hoverRippleRef ) ) {
179
+ this . _hoverRippleRef = this . _showRipple ( { enterDuration : 0 , exitDuration : 0 } ) ;
180
+ this . _hoverRippleRef . element . classList . add ( 'mdc-slider-hover-ripple' ) ;
181
+ }
182
+ }
183
+
184
+ /** Handles displaying the focus ripple. */
185
+ private _showFocusRipple ( ) : void {
186
+ if ( ! this . _isShowingRipple ( this . _focusRippleRef ) ) {
187
+ this . _focusRippleRef = this . _showRipple ( { enterDuration : 0 , exitDuration : 0 } ) ;
188
+ this . _focusRippleRef . element . classList . add ( 'mdc-slider-focus-ripple' ) ;
189
+ }
190
+ }
191
+
192
+ /** Handles displaying the active ripple. */
193
+ private _showActiveRipple ( ) : void {
194
+ if ( ! this . _isShowingRipple ( this . _activeRippleRef ) ) {
195
+ this . _activeRippleRef = this . _showRipple ( { enterDuration : 225 , exitDuration : 400 } ) ;
196
+ this . _activeRippleRef . element . classList . add ( 'mdc-slider-active-ripple' ) ;
197
+ }
198
+ }
199
+
200
+ /** Whether the given rippleRef is currently fading in or visible. */
201
+ private _isShowingRipple ( rippleRef ?: RippleRef ) : boolean {
202
+ return rippleRef ?. state === RippleState . FADING_IN || rippleRef ?. state === RippleState . VISIBLE ;
203
+ }
204
+
205
+ /** Manually launches the slider thumb ripple using the specified ripple animation config. */
206
+ private _showRipple ( animation : RippleAnimationConfig ) : RippleRef {
207
+ return this . _ripple . launch (
208
+ { animation, centered : true , persistent : true } ,
209
+ ) ;
210
+ }
211
+
212
+ /** Gets the hosts native HTML element. */
213
+ _getHostElement ( ) : HTMLElement {
214
+ return this . _elementRef . nativeElement ;
215
+ }
216
+
217
+ /** Gets the native HTML element of the slider thumb knob. */
218
+ _getKnob ( ) : HTMLElement {
219
+ return this . _knob . nativeElement ;
220
+ }
221
+ }
222
+
51
223
/**
52
224
* Directive that adds slider-specific behaviors to an input element inside `<mat-slider>`.
53
225
* Up to two may be placed inside of a `<mat-slider>`.
@@ -111,7 +283,7 @@ export class MatSliderThumb implements AfterViewInit {
111
283
@Output ( ) readonly _focus : EventEmitter < void > = new EventEmitter < void > ( ) ;
112
284
113
285
/** Indicates which slider thumb this input corresponds to. */
114
- private _thumbPosition : Thumb = this . _elementRef . nativeElement . hasAttribute ( 'matSliderStartThumb' )
286
+ _thumbPosition : Thumb = this . _elementRef . nativeElement . hasAttribute ( 'matSliderStartThumb' )
115
287
? Thumb . START
116
288
: Thumb . END ;
117
289
@@ -235,14 +407,7 @@ const _MatSliderMixinBase:
235
407
} )
236
408
export class MatSlider extends _MatSliderMixinBase implements AfterViewInit , OnDestroy {
237
409
/** The slider thumb(s). */
238
- @ViewChildren ( 'thumb' ) _thumbs : QueryList < ElementRef < HTMLElement > > ;
239
-
240
- /** The slider thumb knob(s) */
241
- @ViewChildren ( 'knob' ) _knobs : QueryList < ElementRef < HTMLElement > > ;
242
-
243
- /** The span containing the slider thumb value indicator text */
244
- @ViewChildren ( 'valueIndicatorTextElement' )
245
- _valueIndicatorTextElements : QueryList < ElementRef < HTMLElement > > ;
410
+ @ViewChildren ( MatSliderVisualThumb ) _thumbs : QueryList < MatSliderVisualThumb > ;
246
411
247
412
/** The active section of the slider track. */
248
413
@ViewChild ( 'trackActive' ) _trackActive : ElementRef < HTMLElement > ;
@@ -322,10 +487,10 @@ export class MatSlider extends _MatSliderMixinBase implements AfterViewInit, OnD
322
487
_tickMarks : TickMark [ ] ;
323
488
324
489
/** The display value of the start thumb. */
325
- private _startValueIndicatorText : string ;
490
+ _startValueIndicatorText : string ;
326
491
327
492
/** The display value of the end thumb. */
328
- private _endValueIndicatorText : string ;
493
+ _endValueIndicatorText : string ;
329
494
330
495
constructor (
331
496
readonly _cdr : ChangeDetectorRef ,
@@ -383,30 +548,26 @@ export class MatSlider extends _MatSliderMixinBase implements AfterViewInit, OnD
383
548
384
549
/** Gets the slider thumb input of the given thumb position. */
385
550
_getInput ( thumbPosition : Thumb ) : MatSliderThumb {
386
- return thumbPosition === Thumb . END ? this . _inputs . last ! : this . _inputs . first ! ;
551
+ return thumbPosition === Thumb . END ? this . _inputs . last : this . _inputs . first ;
387
552
}
388
553
389
554
/** Gets the slider thumb HTML input element of the given thumb position. */
390
555
_getInputElement ( thumbPosition : Thumb ) : HTMLInputElement {
391
556
return this . _getInput ( thumbPosition ) . _hostElement ;
392
557
}
393
558
559
+ private _getThumb ( thumbPosition : Thumb ) : MatSliderVisualThumb {
560
+ return thumbPosition === Thumb . END ? this . _thumbs . last : this . _thumbs . first ;
561
+ }
562
+
394
563
/** Gets the slider thumb HTML element of the given thumb position. */
395
564
_getThumbElement ( thumbPosition : Thumb ) : HTMLElement {
396
- const thumbElementRef = thumbPosition === Thumb . END ? this . _thumbs . last : this . _thumbs . first ;
397
- return thumbElementRef . nativeElement ;
565
+ return this . _getThumb ( thumbPosition ) . _getHostElement ( ) ;
398
566
}
399
567
400
568
/** Gets the slider knob HTML element of the given thumb position. */
401
569
_getKnobElement ( thumbPosition : Thumb ) : HTMLElement {
402
- const knobElementRef = thumbPosition === Thumb . END ? this . _knobs . last : this . _knobs . first ;
403
- return knobElementRef . nativeElement ;
404
- }
405
-
406
- _getValueIndicatorText ( thumbPosition : Thumb ) {
407
- return thumbPosition === Thumb . START
408
- ? this . _startValueIndicatorText
409
- : this . _endValueIndicatorText ;
570
+ return this . _getThumb ( thumbPosition ) . _getKnob ( ) ;
410
571
}
411
572
412
573
/**
0 commit comments