UNPKG

59.8 kBJavaScriptView Raw
1import * as i3 from '@angular/common';
2import { DOCUMENT, CommonModule } from '@angular/common';
3import * as i0 from '@angular/core';
4import { forwardRef, EventEmitter, Component, ViewEncapsulation, ChangeDetectionStrategy, Optional, Attribute, Inject, Input, Output, ViewChild, NgModule } from '@angular/core';
5import { mixinTabIndex, mixinColor, mixinDisabled, MatCommonModule } from '@angular/material/core';
6import * as i1 from '@angular/cdk/a11y';
7import * as i2 from '@angular/cdk/bidi';
8import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
9import { hasModifierKey, DOWN_ARROW, RIGHT_ARROW, UP_ARROW, LEFT_ARROW, HOME, END, PAGE_DOWN, PAGE_UP } from '@angular/cdk/keycodes';
10import { NG_VALUE_ACCESSOR } from '@angular/forms';
11import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations';
12import { normalizePassiveListenerOptions } from '@angular/cdk/platform';
13import { Subscription } from 'rxjs';
14
15/**
16 * @license
17 * Copyright Google LLC All Rights Reserved.
18 *
19 * Use of this source code is governed by an MIT-style license that can be
20 * found in the LICENSE file at https://angular.io/license
21 */
22const activeEventOptions = normalizePassiveListenerOptions({ passive: false });
23/**
24 * Visually, a 30px separation between tick marks looks best. This is very subjective but it is
25 * the default separation we chose.
26 */
27const MIN_AUTO_TICK_SEPARATION = 30;
28/** The thumb gap size for a disabled slider. */
29const DISABLED_THUMB_GAP = 7;
30/** The thumb gap size for a non-active slider at its minimum value. */
31const MIN_VALUE_NONACTIVE_THUMB_GAP = 7;
32/** The thumb gap size for an active slider at its minimum value. */
33const MIN_VALUE_ACTIVE_THUMB_GAP = 10;
34/**
35 * Provider Expression that allows mat-slider to register as a ControlValueAccessor.
36 * This allows it to support [(ngModel)] and [formControl].
37 * @docs-private
38 */
39const MAT_SLIDER_VALUE_ACCESSOR = {
40 provide: NG_VALUE_ACCESSOR,
41 useExisting: forwardRef(() => MatSlider),
42 multi: true,
43};
44/** A simple change event emitted by the MatSlider component. */
45class MatSliderChange {
46}
47// Boilerplate for applying mixins to MatSlider.
48/** @docs-private */
49const _MatSliderBase = mixinTabIndex(mixinColor(mixinDisabled(class {
50 constructor(_elementRef) {
51 this._elementRef = _elementRef;
52 }
53}), 'accent'));
54/**
55 * Allows users to select from a range of values by moving the slider thumb. It is similar in
56 * behavior to the native `<input type="range">` element.
57 */
58class MatSlider extends _MatSliderBase {
59 constructor(elementRef, _focusMonitor, _changeDetectorRef, _dir, tabIndex, _ngZone, _document, _animationMode) {
60 super(elementRef);
61 this._focusMonitor = _focusMonitor;
62 this._changeDetectorRef = _changeDetectorRef;
63 this._dir = _dir;
64 this._ngZone = _ngZone;
65 this._animationMode = _animationMode;
66 this._invert = false;
67 this._max = 100;
68 this._min = 0;
69 this._step = 1;
70 this._thumbLabel = false;
71 this._tickInterval = 0;
72 this._value = null;
73 this._vertical = false;
74 /** Event emitted when the slider value has changed. */
75 this.change = new EventEmitter();
76 /** Event emitted when the slider thumb moves. */
77 this.input = new EventEmitter();
78 /**
79 * Emits when the raw value of the slider changes. This is here primarily
80 * to facilitate the two-way binding for the `value` input.
81 * @docs-private
82 */
83 this.valueChange = new EventEmitter();
84 /** onTouch function registered via registerOnTouch (ControlValueAccessor). */
85 this.onTouched = () => { };
86 this._percent = 0;
87 /**
88 * Whether or not the thumb is sliding and what the user is using to slide it with.
89 * Used to determine if there should be a transition for the thumb and fill track.
90 */
91 this._isSliding = null;
92 /**
93 * Whether or not the slider is active (clicked or sliding).
94 * Used to shrink and grow the thumb as according to the Material Design spec.
95 */
96 this._isActive = false;
97 /** The size of a tick interval as a percentage of the size of the track. */
98 this._tickIntervalPercent = 0;
99 /** The dimensions of the slider. */
100 this._sliderDimensions = null;
101 this._controlValueAccessorChangeFn = () => { };
102 /** Subscription to the Directionality change EventEmitter. */
103 this._dirChangeSubscription = Subscription.EMPTY;
104 /** Called when the user has put their pointer down on the slider. */
105 this._pointerDown = (event) => {
106 // Don't do anything if the slider is disabled or the
107 // user is using anything other than the main mouse button.
108 if (this.disabled || this._isSliding || (!isTouchEvent(event) && event.button !== 0)) {
109 return;
110 }
111 this._ngZone.run(() => {
112 this._touchId = isTouchEvent(event)
113 ? getTouchIdForSlider(event, this._elementRef.nativeElement)
114 : undefined;
115 const pointerPosition = getPointerPositionOnPage(event, this._touchId);
116 if (pointerPosition) {
117 const oldValue = this.value;
118 this._isSliding = 'pointer';
119 this._lastPointerEvent = event;
120 this._focusHostElement();
121 this._onMouseenter(); // Simulate mouseenter in case this is a mobile device.
122 this._bindGlobalEvents(event);
123 this._focusHostElement();
124 this._updateValueFromPosition(pointerPosition);
125 this._valueOnSlideStart = oldValue;
126 // Despite the fact that we explicitly bind active events, in some cases the browser
127 // still dispatches non-cancelable events which cause this call to throw an error.
128 // There doesn't appear to be a good way of avoiding them. See #23820.
129 if (event.cancelable) {
130 event.preventDefault();
131 }
132 // Emit a change and input event if the value changed.
133 if (oldValue != this.value) {
134 this._emitInputEvent();
135 }
136 }
137 });
138 };
139 /**
140 * Called when the user has moved their pointer after
141 * starting to drag. Bound on the document level.
142 */
143 this._pointerMove = (event) => {
144 if (this._isSliding === 'pointer') {
145 const pointerPosition = getPointerPositionOnPage(event, this._touchId);
146 if (pointerPosition) {
147 // Prevent the slide from selecting anything else.
148 event.preventDefault();
149 const oldValue = this.value;
150 this._lastPointerEvent = event;
151 this._updateValueFromPosition(pointerPosition);
152 // Native range elements always emit `input` events when the value changed while sliding.
153 if (oldValue != this.value) {
154 this._emitInputEvent();
155 }
156 }
157 }
158 };
159 /** Called when the user has lifted their pointer. Bound on the document level. */
160 this._pointerUp = (event) => {
161 if (this._isSliding === 'pointer') {
162 if (!isTouchEvent(event) ||
163 typeof this._touchId !== 'number' ||
164 // Note that we use `changedTouches`, rather than `touches` because it
165 // seems like in most cases `touches` is empty for `touchend` events.
166 findMatchingTouch(event.changedTouches, this._touchId)) {
167 event.preventDefault();
168 this._removeGlobalEvents();
169 this._isSliding = null;
170 this._touchId = undefined;
171 if (this._valueOnSlideStart != this.value && !this.disabled) {
172 this._emitChangeEvent();
173 }
174 this._valueOnSlideStart = this._lastPointerEvent = null;
175 }
176 }
177 };
178 /** Called when the window has lost focus. */
179 this._windowBlur = () => {
180 // If the window is blurred while dragging we need to stop dragging because the
181 // browser won't dispatch the `mouseup` and `touchend` events anymore.
182 if (this._lastPointerEvent) {
183 this._pointerUp(this._lastPointerEvent);
184 }
185 };
186 this._document = _document;
187 this.tabIndex = parseInt(tabIndex) || 0;
188 _ngZone.runOutsideAngular(() => {
189 const element = elementRef.nativeElement;
190 element.addEventListener('mousedown', this._pointerDown, activeEventOptions);
191 element.addEventListener('touchstart', this._pointerDown, activeEventOptions);
192 });
193 }
194 /** Whether the slider is inverted. */
195 get invert() {
196 return this._invert;
197 }
198 set invert(value) {
199 this._invert = coerceBooleanProperty(value);
200 }
201 /** The maximum value that the slider can have. */
202 get max() {
203 return this._max;
204 }
205 set max(v) {
206 this._max = coerceNumberProperty(v, this._max);
207 this._percent = this._calculatePercentage(this._value);
208 // Since this also modifies the percentage, we need to let the change detection know.
209 this._changeDetectorRef.markForCheck();
210 }
211 /** The minimum value that the slider can have. */
212 get min() {
213 return this._min;
214 }
215 set min(v) {
216 this._min = coerceNumberProperty(v, this._min);
217 this._percent = this._calculatePercentage(this._value);
218 // Since this also modifies the percentage, we need to let the change detection know.
219 this._changeDetectorRef.markForCheck();
220 }
221 /** The values at which the thumb will snap. */
222 get step() {
223 return this._step;
224 }
225 set step(v) {
226 this._step = coerceNumberProperty(v, this._step);
227 if (this._step % 1 !== 0) {
228 this._roundToDecimal = this._step.toString().split('.').pop().length;
229 }
230 // Since this could modify the label, we need to notify the change detection.
231 this._changeDetectorRef.markForCheck();
232 }
233 /** Whether or not to show the thumb label. */
234 get thumbLabel() {
235 return this._thumbLabel;
236 }
237 set thumbLabel(value) {
238 this._thumbLabel = coerceBooleanProperty(value);
239 }
240 /**
241 * How often to show ticks. Relative to the step so that a tick always appears on a step.
242 * Ex: Tick interval of 4 with a step of 3 will draw a tick every 4 steps (every 12 values).
243 */
244 get tickInterval() {
245 return this._tickInterval;
246 }
247 set tickInterval(value) {
248 if (value === 'auto') {
249 this._tickInterval = 'auto';
250 }
251 else if (typeof value === 'number' || typeof value === 'string') {
252 this._tickInterval = coerceNumberProperty(value, this._tickInterval);
253 }
254 else {
255 this._tickInterval = 0;
256 }
257 }
258 /** Value of the slider. */
259 get value() {
260 // If the value needs to be read and it is still uninitialized, initialize it to the min.
261 if (this._value === null) {
262 this.value = this._min;
263 }
264 return this._value;
265 }
266 set value(v) {
267 if (v !== this._value) {
268 let value = coerceNumberProperty(v, 0);
269 // While incrementing by a decimal we can end up with values like 33.300000000000004.
270 // Truncate it to ensure that it matches the label and to make it easier to work with.
271 if (this._roundToDecimal && value !== this.min && value !== this.max) {
272 value = parseFloat(value.toFixed(this._roundToDecimal));
273 }
274 this._value = value;
275 this._percent = this._calculatePercentage(this._value);
276 // Since this also modifies the percentage, we need to let the change detection know.
277 this._changeDetectorRef.markForCheck();
278 }
279 }
280 /** Whether the slider is vertical. */
281 get vertical() {
282 return this._vertical;
283 }
284 set vertical(value) {
285 this._vertical = coerceBooleanProperty(value);
286 }
287 /** The value to be used for display purposes. */
288 get displayValue() {
289 if (this.displayWith) {
290 // Value is never null but since setters and getters cannot have
291 // different types, the value getter is also typed to return null.
292 return this.displayWith(this.value);
293 }
294 // Note that this could be improved further by rounding something like 0.999 to 1 or
295 // 0.899 to 0.9, however it is very performance sensitive, because it gets called on
296 // every change detection cycle.
297 if (this._roundToDecimal && this.value && this.value % 1 !== 0) {
298 return this.value.toFixed(this._roundToDecimal);
299 }
300 return this.value || 0;
301 }
302 /** set focus to the host element */
303 focus(options) {
304 this._focusHostElement(options);
305 }
306 /** blur the host element */
307 blur() {
308 this._blurHostElement();
309 }
310 /** The percentage of the slider that coincides with the value. */
311 get percent() {
312 return this._clamp(this._percent);
313 }
314 /**
315 * Whether the axis of the slider is inverted.
316 * (i.e. whether moving the thumb in the positive x or y direction decreases the slider's value).
317 */
318 _shouldInvertAxis() {
319 // Standard non-inverted mode for a vertical slider should be dragging the thumb from bottom to
320 // top. However from a y-axis standpoint this is inverted.
321 return this.vertical ? !this.invert : this.invert;
322 }
323 /** Whether the slider is at its minimum value. */
324 _isMinValue() {
325 return this.percent === 0;
326 }
327 /**
328 * The amount of space to leave between the slider thumb and the track fill & track background
329 * elements.
330 */
331 _getThumbGap() {
332 if (this.disabled) {
333 return DISABLED_THUMB_GAP;
334 }
335 if (this._isMinValue() && !this.thumbLabel) {
336 return this._isActive ? MIN_VALUE_ACTIVE_THUMB_GAP : MIN_VALUE_NONACTIVE_THUMB_GAP;
337 }
338 return 0;
339 }
340 /** CSS styles for the track background element. */
341 _getTrackBackgroundStyles() {
342 const axis = this.vertical ? 'Y' : 'X';
343 const scale = this.vertical ? `1, ${1 - this.percent}, 1` : `${1 - this.percent}, 1, 1`;
344 const sign = this._shouldInvertMouseCoords() ? '-' : '';
345 return {
346 // scale3d avoids some rendering issues in Chrome. See #12071.
347 transform: `translate${axis}(${sign}${this._getThumbGap()}px) scale3d(${scale})`,
348 };
349 }
350 /** CSS styles for the track fill element. */
351 _getTrackFillStyles() {
352 const percent = this.percent;
353 const axis = this.vertical ? 'Y' : 'X';
354 const scale = this.vertical ? `1, ${percent}, 1` : `${percent}, 1, 1`;
355 const sign = this._shouldInvertMouseCoords() ? '' : '-';
356 return {
357 // scale3d avoids some rendering issues in Chrome. See #12071.
358 transform: `translate${axis}(${sign}${this._getThumbGap()}px) scale3d(${scale})`,
359 // iOS Safari has a bug where it won't re-render elements which start of as `scale(0)` until
360 // something forces a style recalculation on it. Since we'll end up with `scale(0)` when
361 // the value of the slider is 0, we can easily get into this situation. We force a
362 // recalculation by changing the element's `display` when it goes from 0 to any other value.
363 display: percent === 0 ? 'none' : '',
364 };
365 }
366 /** CSS styles for the ticks container element. */
367 _getTicksContainerStyles() {
368 let axis = this.vertical ? 'Y' : 'X';
369 // For a horizontal slider in RTL languages we push the ticks container off the left edge
370 // instead of the right edge to avoid causing a horizontal scrollbar to appear.
371 let sign = !this.vertical && this._getDirection() == 'rtl' ? '' : '-';
372 let offset = (this._tickIntervalPercent / 2) * 100;
373 return {
374 'transform': `translate${axis}(${sign}${offset}%)`,
375 };
376 }
377 /** CSS styles for the ticks element. */
378 _getTicksStyles() {
379 let tickSize = this._tickIntervalPercent * 100;
380 let backgroundSize = this.vertical ? `2px ${tickSize}%` : `${tickSize}% 2px`;
381 let axis = this.vertical ? 'Y' : 'X';
382 // Depending on the direction we pushed the ticks container, push the ticks the opposite
383 // direction to re-center them but clip off the end edge. In RTL languages we need to flip the
384 // ticks 180 degrees so we're really cutting off the end edge abd not the start.
385 let sign = !this.vertical && this._getDirection() == 'rtl' ? '-' : '';
386 let rotate = !this.vertical && this._getDirection() == 'rtl' ? ' rotate(180deg)' : '';
387 let styles = {
388 'backgroundSize': backgroundSize,
389 // Without translateZ ticks sometimes jitter as the slider moves on Chrome & Firefox.
390 'transform': `translateZ(0) translate${axis}(${sign}${tickSize / 2}%)${rotate}`,
391 };
392 if (this._isMinValue() && this._getThumbGap()) {
393 const shouldInvertAxis = this._shouldInvertAxis();
394 let side;
395 if (this.vertical) {
396 side = shouldInvertAxis ? 'Bottom' : 'Top';
397 }
398 else {
399 side = shouldInvertAxis ? 'Right' : 'Left';
400 }
401 styles[`padding${side}`] = `${this._getThumbGap()}px`;
402 }
403 return styles;
404 }
405 _getThumbContainerStyles() {
406 const shouldInvertAxis = this._shouldInvertAxis();
407 let axis = this.vertical ? 'Y' : 'X';
408 // For a horizontal slider in RTL languages we push the thumb container off the left edge
409 // instead of the right edge to avoid causing a horizontal scrollbar to appear.
410 let invertOffset = this._getDirection() == 'rtl' && !this.vertical ? !shouldInvertAxis : shouldInvertAxis;
411 let offset = (invertOffset ? this.percent : 1 - this.percent) * 100;
412 return {
413 'transform': `translate${axis}(-${offset}%)`,
414 };
415 }
416 /**
417 * Whether mouse events should be converted to a slider position by calculating their distance
418 * from the right or bottom edge of the slider as opposed to the top or left.
419 */
420 _shouldInvertMouseCoords() {
421 const shouldInvertAxis = this._shouldInvertAxis();
422 return this._getDirection() == 'rtl' && !this.vertical ? !shouldInvertAxis : shouldInvertAxis;
423 }
424 /** The language direction for this slider element. */
425 _getDirection() {
426 return this._dir && this._dir.value == 'rtl' ? 'rtl' : 'ltr';
427 }
428 ngAfterViewInit() {
429 this._focusMonitor.monitor(this._elementRef, true).subscribe((origin) => {
430 this._isActive = !!origin && origin !== 'keyboard';
431 this._changeDetectorRef.detectChanges();
432 });
433 if (this._dir) {
434 this._dirChangeSubscription = this._dir.change.subscribe(() => {
435 this._changeDetectorRef.markForCheck();
436 });
437 }
438 }
439 ngOnDestroy() {
440 const element = this._elementRef.nativeElement;
441 element.removeEventListener('mousedown', this._pointerDown, activeEventOptions);
442 element.removeEventListener('touchstart', this._pointerDown, activeEventOptions);
443 this._lastPointerEvent = null;
444 this._removeGlobalEvents();
445 this._focusMonitor.stopMonitoring(this._elementRef);
446 this._dirChangeSubscription.unsubscribe();
447 }
448 _onMouseenter() {
449 if (this.disabled) {
450 return;
451 }
452 // We save the dimensions of the slider here so we can use them to update the spacing of the
453 // ticks and determine where on the slider click and slide events happen.
454 this._sliderDimensions = this._getSliderDimensions();
455 this._updateTickIntervalPercent();
456 }
457 _onFocus() {
458 // We save the dimensions of the slider here so we can use them to update the spacing of the
459 // ticks and determine where on the slider click and slide events happen.
460 this._sliderDimensions = this._getSliderDimensions();
461 this._updateTickIntervalPercent();
462 }
463 _onBlur() {
464 this.onTouched();
465 }
466 _onKeydown(event) {
467 if (this.disabled ||
468 hasModifierKey(event) ||
469 (this._isSliding && this._isSliding !== 'keyboard')) {
470 return;
471 }
472 const oldValue = this.value;
473 switch (event.keyCode) {
474 case PAGE_UP:
475 this._increment(10);
476 break;
477 case PAGE_DOWN:
478 this._increment(-10);
479 break;
480 case END:
481 this.value = this.max;
482 break;
483 case HOME:
484 this.value = this.min;
485 break;
486 case LEFT_ARROW:
487 // NOTE: For a sighted user it would make more sense that when they press an arrow key on an
488 // inverted slider the thumb moves in that direction. However for a blind user, nothing
489 // about the slider indicates that it is inverted. They will expect left to be decrement,
490 // regardless of how it appears on the screen. For speakers ofRTL languages, they probably
491 // expect left to mean increment. Therefore we flip the meaning of the side arrow keys for
492 // RTL. For inverted sliders we prefer a good a11y experience to having it "look right" for
493 // sighted users, therefore we do not swap the meaning.
494 this._increment(this._getDirection() == 'rtl' ? 1 : -1);
495 break;
496 case UP_ARROW:
497 this._increment(1);
498 break;
499 case RIGHT_ARROW:
500 // See comment on LEFT_ARROW about the conditions under which we flip the meaning.
501 this._increment(this._getDirection() == 'rtl' ? -1 : 1);
502 break;
503 case DOWN_ARROW:
504 this._increment(-1);
505 break;
506 default:
507 // Return if the key is not one that we explicitly handle to avoid calling preventDefault on
508 // it.
509 return;
510 }
511 if (oldValue != this.value) {
512 this._emitInputEvent();
513 this._emitChangeEvent();
514 }
515 this._isSliding = 'keyboard';
516 event.preventDefault();
517 }
518 _onKeyup() {
519 if (this._isSliding === 'keyboard') {
520 this._isSliding = null;
521 }
522 }
523 /** Use defaultView of injected document if available or fallback to global window reference */
524 _getWindow() {
525 return this._document.defaultView || window;
526 }
527 /**
528 * Binds our global move and end events. They're bound at the document level and only while
529 * dragging so that the user doesn't have to keep their pointer exactly over the slider
530 * as they're swiping across the screen.
531 */
532 _bindGlobalEvents(triggerEvent) {
533 // Note that we bind the events to the `document`, because it allows us to capture
534 // drag cancel events where the user's pointer is outside the browser window.
535 const document = this._document;
536 const isTouch = isTouchEvent(triggerEvent);
537 const moveEventName = isTouch ? 'touchmove' : 'mousemove';
538 const endEventName = isTouch ? 'touchend' : 'mouseup';
539 document.addEventListener(moveEventName, this._pointerMove, activeEventOptions);
540 document.addEventListener(endEventName, this._pointerUp, activeEventOptions);
541 if (isTouch) {
542 document.addEventListener('touchcancel', this._pointerUp, activeEventOptions);
543 }
544 const window = this._getWindow();
545 if (typeof window !== 'undefined' && window) {
546 window.addEventListener('blur', this._windowBlur);
547 }
548 }
549 /** Removes any global event listeners that we may have added. */
550 _removeGlobalEvents() {
551 const document = this._document;
552 document.removeEventListener('mousemove', this._pointerMove, activeEventOptions);
553 document.removeEventListener('mouseup', this._pointerUp, activeEventOptions);
554 document.removeEventListener('touchmove', this._pointerMove, activeEventOptions);
555 document.removeEventListener('touchend', this._pointerUp, activeEventOptions);
556 document.removeEventListener('touchcancel', this._pointerUp, activeEventOptions);
557 const window = this._getWindow();
558 if (typeof window !== 'undefined' && window) {
559 window.removeEventListener('blur', this._windowBlur);
560 }
561 }
562 /** Increments the slider by the given number of steps (negative number decrements). */
563 _increment(numSteps) {
564 // Pre-clamp the current value since it's allowed to be
565 // out of bounds when assigned programmatically.
566 const clampedValue = this._clamp(this.value || 0, this.min, this.max);
567 this.value = this._clamp(clampedValue + this.step * numSteps, this.min, this.max);
568 }
569 /** Calculate the new value from the new physical location. The value will always be snapped. */
570 _updateValueFromPosition(pos) {
571 if (!this._sliderDimensions) {
572 return;
573 }
574 let offset = this.vertical ? this._sliderDimensions.top : this._sliderDimensions.left;
575 let size = this.vertical ? this._sliderDimensions.height : this._sliderDimensions.width;
576 let posComponent = this.vertical ? pos.y : pos.x;
577 // The exact value is calculated from the event and used to find the closest snap value.
578 let percent = this._clamp((posComponent - offset) / size);
579 if (this._shouldInvertMouseCoords()) {
580 percent = 1 - percent;
581 }
582 // Since the steps may not divide cleanly into the max value, if the user
583 // slid to 0 or 100 percent, we jump to the min/max value. This approach
584 // is slightly more intuitive than using `Math.ceil` below, because it
585 // follows the user's pointer closer.
586 if (percent === 0) {
587 this.value = this.min;
588 }
589 else if (percent === 1) {
590 this.value = this.max;
591 }
592 else {
593 const exactValue = this._calculateValue(percent);
594 // This calculation finds the closest step by finding the closest
595 // whole number divisible by the step relative to the min.
596 const closestValue = Math.round((exactValue - this.min) / this.step) * this.step + this.min;
597 // The value needs to snap to the min and max.
598 this.value = this._clamp(closestValue, this.min, this.max);
599 }
600 }
601 /** Emits a change event if the current value is different from the last emitted value. */
602 _emitChangeEvent() {
603 this._controlValueAccessorChangeFn(this.value);
604 this.valueChange.emit(this.value);
605 this.change.emit(this._createChangeEvent());
606 }
607 /** Emits an input event when the current value is different from the last emitted value. */
608 _emitInputEvent() {
609 this.input.emit(this._createChangeEvent());
610 }
611 /** Updates the amount of space between ticks as a percentage of the width of the slider. */
612 _updateTickIntervalPercent() {
613 if (!this.tickInterval || !this._sliderDimensions) {
614 return;
615 }
616 let tickIntervalPercent;
617 if (this.tickInterval == 'auto') {
618 let trackSize = this.vertical ? this._sliderDimensions.height : this._sliderDimensions.width;
619 let pixelsPerStep = (trackSize * this.step) / (this.max - this.min);
620 let stepsPerTick = Math.ceil(MIN_AUTO_TICK_SEPARATION / pixelsPerStep);
621 let pixelsPerTick = stepsPerTick * this.step;
622 tickIntervalPercent = pixelsPerTick / trackSize;
623 }
624 else {
625 tickIntervalPercent = (this.tickInterval * this.step) / (this.max - this.min);
626 }
627 this._tickIntervalPercent = isSafeNumber(tickIntervalPercent) ? tickIntervalPercent : 0;
628 }
629 /** Creates a slider change object from the specified value. */
630 _createChangeEvent(value = this.value) {
631 let event = new MatSliderChange();
632 event.source = this;
633 event.value = value;
634 return event;
635 }
636 /** Calculates the percentage of the slider that a value is. */
637 _calculatePercentage(value) {
638 const percentage = ((value || 0) - this.min) / (this.max - this.min);
639 return isSafeNumber(percentage) ? percentage : 0;
640 }
641 /** Calculates the value a percentage of the slider corresponds to. */
642 _calculateValue(percentage) {
643 return this.min + percentage * (this.max - this.min);
644 }
645 /** Return a number between two numbers. */
646 _clamp(value, min = 0, max = 1) {
647 return Math.max(min, Math.min(value, max));
648 }
649 /**
650 * Get the bounding client rect of the slider track element.
651 * The track is used rather than the native element to ignore the extra space that the thumb can
652 * take up.
653 */
654 _getSliderDimensions() {
655 return this._sliderWrapper ? this._sliderWrapper.nativeElement.getBoundingClientRect() : null;
656 }
657 /**
658 * Focuses the native element.
659 * Currently only used to allow a blur event to fire but will be used with keyboard input later.
660 */
661 _focusHostElement(options) {
662 this._elementRef.nativeElement.focus(options);
663 }
664 /** Blurs the native element. */
665 _blurHostElement() {
666 this._elementRef.nativeElement.blur();
667 }
668 /**
669 * Sets the model value. Implemented as part of ControlValueAccessor.
670 * @param value
671 */
672 writeValue(value) {
673 this.value = value;
674 }
675 /**
676 * Registers a callback to be triggered when the value has changed.
677 * Implemented as part of ControlValueAccessor.
678 * @param fn Callback to be registered.
679 */
680 registerOnChange(fn) {
681 this._controlValueAccessorChangeFn = fn;
682 }
683 /**
684 * Registers a callback to be triggered when the component is touched.
685 * Implemented as part of ControlValueAccessor.
686 * @param fn Callback to be registered.
687 */
688 registerOnTouched(fn) {
689 this.onTouched = fn;
690 }
691 /**
692 * Sets whether the component should be disabled.
693 * Implemented as part of ControlValueAccessor.
694 * @param isDisabled
695 */
696 setDisabledState(isDisabled) {
697 this.disabled = isDisabled;
698 }
699}
700MatSlider.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatSlider, deps: [{ token: i0.ElementRef }, { token: i1.FocusMonitor }, { token: i0.ChangeDetectorRef }, { token: i2.Directionality, optional: true }, { token: 'tabindex', attribute: true }, { token: i0.NgZone }, { token: DOCUMENT }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
701MatSlider.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatSlider, selector: "mat-slider", inputs: { disabled: "disabled", color: "color", tabIndex: "tabIndex", invert: "invert", max: "max", min: "min", step: "step", thumbLabel: "thumbLabel", tickInterval: "tickInterval", value: "value", displayWith: "displayWith", valueText: "valueText", vertical: "vertical" }, outputs: { change: "change", input: "input", valueChange: "valueChange" }, host: { attributes: { "role": "slider" }, listeners: { "focus": "_onFocus()", "blur": "_onBlur()", "keydown": "_onKeydown($event)", "keyup": "_onKeyup()", "mouseenter": "_onMouseenter()", "selectstart": "$event.preventDefault()" }, properties: { "tabIndex": "tabIndex", "attr.aria-disabled": "disabled", "attr.aria-valuemax": "max", "attr.aria-valuemin": "min", "attr.aria-valuenow": "value", "attr.aria-valuetext": "valueText == null ? displayValue : valueText", "attr.aria-orientation": "vertical ? \"vertical\" : \"horizontal\"", "class.mat-slider-disabled": "disabled", "class.mat-slider-has-ticks": "tickInterval", "class.mat-slider-horizontal": "!vertical", "class.mat-slider-axis-inverted": "_shouldInvertAxis()", "class.mat-slider-invert-mouse-coords": "_shouldInvertMouseCoords()", "class.mat-slider-sliding": "_isSliding", "class.mat-slider-thumb-label-showing": "thumbLabel", "class.mat-slider-vertical": "vertical", "class.mat-slider-min-value": "_isMinValue()", "class.mat-slider-hide-last-tick": "disabled || _isMinValue() && _getThumbGap() && _shouldInvertAxis()", "class._mat-animation-noopable": "_animationMode === \"NoopAnimations\"" }, classAttribute: "mat-slider mat-focus-indicator" }, providers: [MAT_SLIDER_VALUE_ACCESSOR], viewQueries: [{ propertyName: "_sliderWrapper", first: true, predicate: ["sliderWrapper"], descendants: true }], exportAs: ["matSlider"], usesInheritance: true, ngImport: i0, template: "<div class=\"mat-slider-wrapper\" #sliderWrapper>\n <div class=\"mat-slider-track-wrapper\">\n <div class=\"mat-slider-track-background\" [ngStyle]=\"_getTrackBackgroundStyles()\"></div>\n <div class=\"mat-slider-track-fill\" [ngStyle]=\"_getTrackFillStyles()\"></div>\n </div>\n <div class=\"mat-slider-ticks-container\" [ngStyle]=\"_getTicksContainerStyles()\">\n <div class=\"mat-slider-ticks\" [ngStyle]=\"_getTicksStyles()\"></div>\n </div>\n <div class=\"mat-slider-thumb-container\" [ngStyle]=\"_getThumbContainerStyles()\">\n <div class=\"mat-slider-focus-ring\"></div>\n <div class=\"mat-slider-thumb\"></div>\n <div class=\"mat-slider-thumb-label\">\n <span class=\"mat-slider-thumb-label-text\">{{displayValue}}</span>\n </div>\n </div>\n</div>\n", styles: [".mat-slider{display:inline-block;position:relative;box-sizing:border-box;padding:8px;outline:none;vertical-align:middle}.mat-slider:not(.mat-slider-disabled):active,.mat-slider.mat-slider-sliding:not(.mat-slider-disabled){cursor:grabbing}.mat-slider-wrapper{-webkit-print-color-adjust:exact;color-adjust:exact;position:absolute}.mat-slider-track-wrapper{position:absolute;top:0;left:0;overflow:hidden}.mat-slider-track-fill{position:absolute;transform-origin:0 0;transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1),background-color 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-track-background{position:absolute;transform-origin:100% 100%;transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1),background-color 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-ticks-container{position:absolute;left:0;top:0;overflow:hidden}.mat-slider-ticks{-webkit-background-clip:content-box;background-clip:content-box;background-repeat:repeat;box-sizing:border-box;opacity:0;transition:opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-thumb-container{position:absolute;z-index:1;transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-focus-ring{position:absolute;width:30px;height:30px;border-radius:50%;transform:scale(0);opacity:0;transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1),background-color 400ms cubic-bezier(0.25, 0.8, 0.25, 1),opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider.cdk-keyboard-focused .mat-slider-focus-ring,.mat-slider.cdk-program-focused .mat-slider-focus-ring{transform:scale(1);opacity:1}.mat-slider:not(.mat-slider-disabled):not(.mat-slider-sliding) .mat-slider-thumb-label,.mat-slider:not(.mat-slider-disabled):not(.mat-slider-sliding) .mat-slider-thumb{cursor:grab}.mat-slider-thumb{position:absolute;right:-10px;bottom:-10px;box-sizing:border-box;width:20px;height:20px;border:3px solid rgba(0,0,0,0);border-radius:50%;transform:scale(0.7);transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1),background-color 400ms cubic-bezier(0.25, 0.8, 0.25, 1),border-color 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-thumb-label{display:none;align-items:center;justify-content:center;position:absolute;width:28px;height:28px;border-radius:50%;transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1),border-radius 400ms cubic-bezier(0.25, 0.8, 0.25, 1),background-color 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.cdk-high-contrast-active .mat-slider-thumb-label{outline:solid 1px}.mat-slider-thumb-label-text{z-index:1;opacity:0;transition:opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-sliding .mat-slider-track-fill,.mat-slider-sliding .mat-slider-track-background,.mat-slider-sliding .mat-slider-thumb-container{transition-duration:0ms}.mat-slider-has-ticks .mat-slider-wrapper::after{content:\"\";position:absolute;border-width:0;border-style:solid;opacity:0;transition:opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-has-ticks.cdk-focused:not(.mat-slider-hide-last-tick) .mat-slider-wrapper::after,.mat-slider-has-ticks:hover:not(.mat-slider-hide-last-tick) .mat-slider-wrapper::after{opacity:1}.mat-slider-has-ticks.cdk-focused:not(.mat-slider-disabled) .mat-slider-ticks,.mat-slider-has-ticks:hover:not(.mat-slider-disabled) .mat-slider-ticks{opacity:1}.mat-slider-thumb-label-showing .mat-slider-focus-ring{display:none}.mat-slider-thumb-label-showing .mat-slider-thumb-label{display:flex}.mat-slider-axis-inverted .mat-slider-track-fill{transform-origin:100% 100%}.mat-slider-axis-inverted .mat-slider-track-background{transform-origin:0 0}.mat-slider:not(.mat-slider-disabled).cdk-focused.mat-slider-thumb-label-showing .mat-slider-thumb{transform:scale(0)}.mat-slider:not(.mat-slider-disabled).cdk-focused .mat-slider-thumb-label{border-radius:50% 50% 0}.mat-slider:not(.mat-slider-disabled).cdk-focused .mat-slider-thumb-label-text{opacity:1}.mat-slider:not(.mat-slider-disabled).cdk-mouse-focused .mat-slider-thumb,.mat-slider:not(.mat-slider-disabled).cdk-touch-focused .mat-slider-thumb,.mat-slider:not(.mat-slider-disabled).cdk-program-focused .mat-slider-thumb{border-width:2px;transform:scale(1)}.mat-slider-disabled .mat-slider-focus-ring{transform:scale(0);opacity:0}.mat-slider-disabled .mat-slider-thumb{border-width:4px;transform:scale(0.5)}.mat-slider-disabled .mat-slider-thumb-label{display:none}.mat-slider-horizontal{height:48px;min-width:128px}.mat-slider-horizontal .mat-slider-wrapper{height:2px;top:23px;left:8px;right:8px}.mat-slider-horizontal .mat-slider-wrapper::after{height:2px;border-left-width:2px;right:0;top:0}.mat-slider-horizontal .mat-slider-track-wrapper{height:2px;width:100%}.mat-slider-horizontal .mat-slider-track-fill{height:2px;width:100%;transform:scaleX(0)}.mat-slider-horizontal .mat-slider-track-background{height:2px;width:100%;transform:scaleX(1)}.mat-slider-horizontal .mat-slider-ticks-container{height:2px;width:100%}.cdk-high-contrast-active .mat-slider-horizontal .mat-slider-ticks-container{height:0;outline:solid 2px;top:1px}.mat-slider-horizontal .mat-slider-ticks{height:2px;width:100%}.mat-slider-horizontal .mat-slider-thumb-container{width:100%;height:0;top:50%}.mat-slider-horizontal .mat-slider-focus-ring{top:-15px;right:-15px}.mat-slider-horizontal .mat-slider-thumb-label{right:-14px;top:-40px;transform:translateY(26px) scale(0.01) rotate(45deg)}.mat-slider-horizontal .mat-slider-thumb-label-text{transform:rotate(-45deg)}.mat-slider-horizontal.cdk-focused .mat-slider-thumb-label{transform:rotate(45deg)}.cdk-high-contrast-active .mat-slider-horizontal.cdk-focused .mat-slider-thumb-label,.cdk-high-contrast-active .mat-slider-horizontal.cdk-focused .mat-slider-thumb-label-text{transform:none}.mat-slider-vertical{width:48px;min-height:128px}.mat-slider-vertical .mat-slider-wrapper{width:2px;top:8px;bottom:8px;left:23px}.mat-slider-vertical .mat-slider-wrapper::after{width:2px;border-top-width:2px;bottom:0;left:0}.mat-slider-vertical .mat-slider-track-wrapper{height:100%;width:2px}.mat-slider-vertical .mat-slider-track-fill{height:100%;width:2px;transform:scaleY(0)}.mat-slider-vertical .mat-slider-track-background{height:100%;width:2px;transform:scaleY(1)}.mat-slider-vertical .mat-slider-ticks-container{width:2px;height:100%}.cdk-high-contrast-active .mat-slider-vertical .mat-slider-ticks-container{width:0;outline:solid 2px;left:1px}.mat-slider-vertical .mat-slider-focus-ring{bottom:-15px;left:-15px}.mat-slider-vertical .mat-slider-ticks{width:2px;height:100%}.mat-slider-vertical .mat-slider-thumb-container{height:100%;width:0;left:50%}.mat-slider-vertical .mat-slider-thumb{-webkit-backface-visibility:hidden;backface-visibility:hidden}.mat-slider-vertical .mat-slider-thumb-label{bottom:-14px;left:-40px;transform:translateX(26px) scale(0.01) rotate(-45deg)}.mat-slider-vertical .mat-slider-thumb-label-text{transform:rotate(45deg)}.mat-slider-vertical.cdk-focused .mat-slider-thumb-label{transform:rotate(-45deg)}[dir=rtl] .mat-slider-wrapper::after{left:0;right:auto}[dir=rtl] .mat-slider-horizontal .mat-slider-track-fill{transform-origin:100% 100%}[dir=rtl] .mat-slider-horizontal .mat-slider-track-background{transform-origin:0 0}[dir=rtl] .mat-slider-horizontal.mat-slider-axis-inverted .mat-slider-track-fill{transform-origin:0 0}[dir=rtl] .mat-slider-horizontal.mat-slider-axis-inverted .mat-slider-track-background{transform-origin:100% 100%}.mat-slider._mat-animation-noopable .mat-slider-track-fill,.mat-slider._mat-animation-noopable .mat-slider-track-background,.mat-slider._mat-animation-noopable .mat-slider-ticks,.mat-slider._mat-animation-noopable .mat-slider-thumb-container,.mat-slider._mat-animation-noopable .mat-slider-focus-ring,.mat-slider._mat-animation-noopable .mat-slider-thumb,.mat-slider._mat-animation-noopable .mat-slider-thumb-label,.mat-slider._mat-animation-noopable .mat-slider-thumb-label-text,.mat-slider._mat-animation-noopable .mat-slider-has-ticks .mat-slider-wrapper::after{transition:none}"], dependencies: [{ kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
702i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatSlider, decorators: [{
703 type: Component,
704 args: [{ selector: 'mat-slider', exportAs: 'matSlider', providers: [MAT_SLIDER_VALUE_ACCESSOR], host: {
705 '(focus)': '_onFocus()',
706 '(blur)': '_onBlur()',
707 '(keydown)': '_onKeydown($event)',
708 '(keyup)': '_onKeyup()',
709 '(mouseenter)': '_onMouseenter()',
710 // On Safari starting to slide temporarily triggers text selection mode which
711 // show the wrong cursor. We prevent it by stopping the `selectstart` event.
712 '(selectstart)': '$event.preventDefault()',
713 'class': 'mat-slider mat-focus-indicator',
714 'role': 'slider',
715 '[tabIndex]': 'tabIndex',
716 '[attr.aria-disabled]': 'disabled',
717 '[attr.aria-valuemax]': 'max',
718 '[attr.aria-valuemin]': 'min',
719 '[attr.aria-valuenow]': 'value',
720 // NVDA and Jaws appear to announce the `aria-valuenow` by calculating its percentage based
721 // on its value between `aria-valuemin` and `aria-valuemax`. Due to how decimals are handled,
722 // it can cause the slider to read out a very long value like 0.20000068 if the current value
723 // is 0.2 with a min of 0 and max of 1. We work around the issue by setting `aria-valuetext`
724 // to the same value that we set on the slider's thumb which will be truncated.
725 '[attr.aria-valuetext]': 'valueText == null ? displayValue : valueText',
726 '[attr.aria-orientation]': 'vertical ? "vertical" : "horizontal"',
727 '[class.mat-slider-disabled]': 'disabled',
728 '[class.mat-slider-has-ticks]': 'tickInterval',
729 '[class.mat-slider-horizontal]': '!vertical',
730 '[class.mat-slider-axis-inverted]': '_shouldInvertAxis()',
731 // Class binding which is only used by the test harness as there is no other
732 // way for the harness to detect if mouse coordinates need to be inverted.
733 '[class.mat-slider-invert-mouse-coords]': '_shouldInvertMouseCoords()',
734 '[class.mat-slider-sliding]': '_isSliding',
735 '[class.mat-slider-thumb-label-showing]': 'thumbLabel',
736 '[class.mat-slider-vertical]': 'vertical',
737 '[class.mat-slider-min-value]': '_isMinValue()',
738 '[class.mat-slider-hide-last-tick]': 'disabled || _isMinValue() && _getThumbGap() && _shouldInvertAxis()',
739 '[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"',
740 }, inputs: ['disabled', 'color', 'tabIndex'], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"mat-slider-wrapper\" #sliderWrapper>\n <div class=\"mat-slider-track-wrapper\">\n <div class=\"mat-slider-track-background\" [ngStyle]=\"_getTrackBackgroundStyles()\"></div>\n <div class=\"mat-slider-track-fill\" [ngStyle]=\"_getTrackFillStyles()\"></div>\n </div>\n <div class=\"mat-slider-ticks-container\" [ngStyle]=\"_getTicksContainerStyles()\">\n <div class=\"mat-slider-ticks\" [ngStyle]=\"_getTicksStyles()\"></div>\n </div>\n <div class=\"mat-slider-thumb-container\" [ngStyle]=\"_getThumbContainerStyles()\">\n <div class=\"mat-slider-focus-ring\"></div>\n <div class=\"mat-slider-thumb\"></div>\n <div class=\"mat-slider-thumb-label\">\n <span class=\"mat-slider-thumb-label-text\">{{displayValue}}</span>\n </div>\n </div>\n</div>\n", styles: [".mat-slider{display:inline-block;position:relative;box-sizing:border-box;padding:8px;outline:none;vertical-align:middle}.mat-slider:not(.mat-slider-disabled):active,.mat-slider.mat-slider-sliding:not(.mat-slider-disabled){cursor:grabbing}.mat-slider-wrapper{-webkit-print-color-adjust:exact;color-adjust:exact;position:absolute}.mat-slider-track-wrapper{position:absolute;top:0;left:0;overflow:hidden}.mat-slider-track-fill{position:absolute;transform-origin:0 0;transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1),background-color 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-track-background{position:absolute;transform-origin:100% 100%;transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1),background-color 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-ticks-container{position:absolute;left:0;top:0;overflow:hidden}.mat-slider-ticks{-webkit-background-clip:content-box;background-clip:content-box;background-repeat:repeat;box-sizing:border-box;opacity:0;transition:opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-thumb-container{position:absolute;z-index:1;transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-focus-ring{position:absolute;width:30px;height:30px;border-radius:50%;transform:scale(0);opacity:0;transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1),background-color 400ms cubic-bezier(0.25, 0.8, 0.25, 1),opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider.cdk-keyboard-focused .mat-slider-focus-ring,.mat-slider.cdk-program-focused .mat-slider-focus-ring{transform:scale(1);opacity:1}.mat-slider:not(.mat-slider-disabled):not(.mat-slider-sliding) .mat-slider-thumb-label,.mat-slider:not(.mat-slider-disabled):not(.mat-slider-sliding) .mat-slider-thumb{cursor:grab}.mat-slider-thumb{position:absolute;right:-10px;bottom:-10px;box-sizing:border-box;width:20px;height:20px;border:3px solid rgba(0,0,0,0);border-radius:50%;transform:scale(0.7);transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1),background-color 400ms cubic-bezier(0.25, 0.8, 0.25, 1),border-color 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-thumb-label{display:none;align-items:center;justify-content:center;position:absolute;width:28px;height:28px;border-radius:50%;transition:transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1),border-radius 400ms cubic-bezier(0.25, 0.8, 0.25, 1),background-color 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.cdk-high-contrast-active .mat-slider-thumb-label{outline:solid 1px}.mat-slider-thumb-label-text{z-index:1;opacity:0;transition:opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-sliding .mat-slider-track-fill,.mat-slider-sliding .mat-slider-track-background,.mat-slider-sliding .mat-slider-thumb-container{transition-duration:0ms}.mat-slider-has-ticks .mat-slider-wrapper::after{content:\"\";position:absolute;border-width:0;border-style:solid;opacity:0;transition:opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-slider-has-ticks.cdk-focused:not(.mat-slider-hide-last-tick) .mat-slider-wrapper::after,.mat-slider-has-ticks:hover:not(.mat-slider-hide-last-tick) .mat-slider-wrapper::after{opacity:1}.mat-slider-has-ticks.cdk-focused:not(.mat-slider-disabled) .mat-slider-ticks,.mat-slider-has-ticks:hover:not(.mat-slider-disabled) .mat-slider-ticks{opacity:1}.mat-slider-thumb-label-showing .mat-slider-focus-ring{display:none}.mat-slider-thumb-label-showing .mat-slider-thumb-label{display:flex}.mat-slider-axis-inverted .mat-slider-track-fill{transform-origin:100% 100%}.mat-slider-axis-inverted .mat-slider-track-background{transform-origin:0 0}.mat-slider:not(.mat-slider-disabled).cdk-focused.mat-slider-thumb-label-showing .mat-slider-thumb{transform:scale(0)}.mat-slider:not(.mat-slider-disabled).cdk-focused .mat-slider-thumb-label{border-radius:50% 50% 0}.mat-slider:not(.mat-slider-disabled).cdk-focused .mat-slider-thumb-label-text{opacity:1}.mat-slider:not(.mat-slider-disabled).cdk-mouse-focused .mat-slider-thumb,.mat-slider:not(.mat-slider-disabled).cdk-touch-focused .mat-slider-thumb,.mat-slider:not(.mat-slider-disabled).cdk-program-focused .mat-slider-thumb{border-width:2px;transform:scale(1)}.mat-slider-disabled .mat-slider-focus-ring{transform:scale(0);opacity:0}.mat-slider-disabled .mat-slider-thumb{border-width:4px;transform:scale(0.5)}.mat-slider-disabled .mat-slider-thumb-label{display:none}.mat-slider-horizontal{height:48px;min-width:128px}.mat-slider-horizontal .mat-slider-wrapper{height:2px;top:23px;left:8px;right:8px}.mat-slider-horizontal .mat-slider-wrapper::after{height:2px;border-left-width:2px;right:0;top:0}.mat-slider-horizontal .mat-slider-track-wrapper{height:2px;width:100%}.mat-slider-horizontal .mat-slider-track-fill{height:2px;width:100%;transform:scaleX(0)}.mat-slider-horizontal .mat-slider-track-background{height:2px;width:100%;transform:scaleX(1)}.mat-slider-horizontal .mat-slider-ticks-container{height:2px;width:100%}.cdk-high-contrast-active .mat-slider-horizontal .mat-slider-ticks-container{height:0;outline:solid 2px;top:1px}.mat-slider-horizontal .mat-slider-ticks{height:2px;width:100%}.mat-slider-horizontal .mat-slider-thumb-container{width:100%;height:0;top:50%}.mat-slider-horizontal .mat-slider-focus-ring{top:-15px;right:-15px}.mat-slider-horizontal .mat-slider-thumb-label{right:-14px;top:-40px;transform:translateY(26px) scale(0.01) rotate(45deg)}.mat-slider-horizontal .mat-slider-thumb-label-text{transform:rotate(-45deg)}.mat-slider-horizontal.cdk-focused .mat-slider-thumb-label{transform:rotate(45deg)}.cdk-high-contrast-active .mat-slider-horizontal.cdk-focused .mat-slider-thumb-label,.cdk-high-contrast-active .mat-slider-horizontal.cdk-focused .mat-slider-thumb-label-text{transform:none}.mat-slider-vertical{width:48px;min-height:128px}.mat-slider-vertical .mat-slider-wrapper{width:2px;top:8px;bottom:8px;left:23px}.mat-slider-vertical .mat-slider-wrapper::after{width:2px;border-top-width:2px;bottom:0;left:0}.mat-slider-vertical .mat-slider-track-wrapper{height:100%;width:2px}.mat-slider-vertical .mat-slider-track-fill{height:100%;width:2px;transform:scaleY(0)}.mat-slider-vertical .mat-slider-track-background{height:100%;width:2px;transform:scaleY(1)}.mat-slider-vertical .mat-slider-ticks-container{width:2px;height:100%}.cdk-high-contrast-active .mat-slider-vertical .mat-slider-ticks-container{width:0;outline:solid 2px;left:1px}.mat-slider-vertical .mat-slider-focus-ring{bottom:-15px;left:-15px}.mat-slider-vertical .mat-slider-ticks{width:2px;height:100%}.mat-slider-vertical .mat-slider-thumb-container{height:100%;width:0;left:50%}.mat-slider-vertical .mat-slider-thumb{-webkit-backface-visibility:hidden;backface-visibility:hidden}.mat-slider-vertical .mat-slider-thumb-label{bottom:-14px;left:-40px;transform:translateX(26px) scale(0.01) rotate(-45deg)}.mat-slider-vertical .mat-slider-thumb-label-text{transform:rotate(45deg)}.mat-slider-vertical.cdk-focused .mat-slider-thumb-label{transform:rotate(-45deg)}[dir=rtl] .mat-slider-wrapper::after{left:0;right:auto}[dir=rtl] .mat-slider-horizontal .mat-slider-track-fill{transform-origin:100% 100%}[dir=rtl] .mat-slider-horizontal .mat-slider-track-background{transform-origin:0 0}[dir=rtl] .mat-slider-horizontal.mat-slider-axis-inverted .mat-slider-track-fill{transform-origin:0 0}[dir=rtl] .mat-slider-horizontal.mat-slider-axis-inverted .mat-slider-track-background{transform-origin:100% 100%}.mat-slider._mat-animation-noopable .mat-slider-track-fill,.mat-slider._mat-animation-noopable .mat-slider-track-background,.mat-slider._mat-animation-noopable .mat-slider-ticks,.mat-slider._mat-animation-noopable .mat-slider-thumb-container,.mat-slider._mat-animation-noopable .mat-slider-focus-ring,.mat-slider._mat-animation-noopable .mat-slider-thumb,.mat-slider._mat-animation-noopable .mat-slider-thumb-label,.mat-slider._mat-animation-noopable .mat-slider-thumb-label-text,.mat-slider._mat-animation-noopable .mat-slider-has-ticks .mat-slider-wrapper::after{transition:none}"] }]
741 }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.FocusMonitor }, { type: i0.ChangeDetectorRef }, { type: i2.Directionality, decorators: [{
742 type: Optional
743 }] }, { type: undefined, decorators: [{
744 type: Attribute,
745 args: ['tabindex']
746 }] }, { type: i0.NgZone }, { type: undefined, decorators: [{
747 type: Inject,
748 args: [DOCUMENT]
749 }] }, { type: undefined, decorators: [{
750 type: Optional
751 }, {
752 type: Inject,
753 args: [ANIMATION_MODULE_TYPE]
754 }] }]; }, propDecorators: { invert: [{
755 type: Input
756 }], max: [{
757 type: Input
758 }], min: [{
759 type: Input
760 }], step: [{
761 type: Input
762 }], thumbLabel: [{
763 type: Input
764 }], tickInterval: [{
765 type: Input
766 }], value: [{
767 type: Input
768 }], displayWith: [{
769 type: Input
770 }], valueText: [{
771 type: Input
772 }], vertical: [{
773 type: Input
774 }], change: [{
775 type: Output
776 }], input: [{
777 type: Output
778 }], valueChange: [{
779 type: Output
780 }], _sliderWrapper: [{
781 type: ViewChild,
782 args: ['sliderWrapper']
783 }] } });
784/** Checks if number is safe for calculation */
785function isSafeNumber(value) {
786 return !isNaN(value) && isFinite(value);
787}
788/** Returns whether an event is a touch event. */
789function isTouchEvent(event) {
790 // This function is called for every pixel that the user has dragged so we need it to be
791 // as fast as possible. Since we only bind mouse events and touch events, we can assume
792 // that if the event's name starts with `t`, it's a touch event.
793 return event.type[0] === 't';
794}
795/** Gets the coordinates of a touch or mouse event relative to the viewport. */
796function getPointerPositionOnPage(event, id) {
797 let point;
798 if (isTouchEvent(event)) {
799 // The `identifier` could be undefined if the browser doesn't support `TouchEvent.identifier`.
800 // If that's the case, attribute the first touch to all active sliders. This should still cover
801 // the most common case while only breaking multi-touch.
802 if (typeof id === 'number') {
803 point = findMatchingTouch(event.touches, id) || findMatchingTouch(event.changedTouches, id);
804 }
805 else {
806 // `touches` will be empty for start/end events so we have to fall back to `changedTouches`.
807 point = event.touches[0] || event.changedTouches[0];
808 }
809 }
810 else {
811 point = event;
812 }
813 return point ? { x: point.clientX, y: point.clientY } : undefined;
814}
815/** Finds a `Touch` with a specific ID in a `TouchList`. */
816function findMatchingTouch(touches, id) {
817 for (let i = 0; i < touches.length; i++) {
818 if (touches[i].identifier === id) {
819 return touches[i];
820 }
821 }
822 return undefined;
823}
824/** Gets the unique ID of a touch that matches a specific slider. */
825function getTouchIdForSlider(event, sliderHost) {
826 for (let i = 0; i < event.touches.length; i++) {
827 const target = event.touches[i].target;
828 if (sliderHost === target || sliderHost.contains(target)) {
829 return event.touches[i].identifier;
830 }
831 }
832 return undefined;
833}
834
835/**
836 * @license
837 * Copyright Google LLC All Rights Reserved.
838 *
839 * Use of this source code is governed by an MIT-style license that can be
840 * found in the LICENSE file at https://angular.io/license
841 */
842class MatSliderModule {
843}
844MatSliderModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatSliderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
845MatSliderModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.1", ngImport: i0, type: MatSliderModule, declarations: [MatSlider], imports: [CommonModule, MatCommonModule], exports: [MatSlider, MatCommonModule] });
846MatSliderModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatSliderModule, imports: [CommonModule, MatCommonModule, MatCommonModule] });
847i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatSliderModule, decorators: [{
848 type: NgModule,
849 args: [{
850 imports: [CommonModule, MatCommonModule],
851 exports: [MatSlider, MatCommonModule],
852 declarations: [MatSlider],
853 }]
854 }] });
855
856/**
857 * @license
858 * Copyright Google LLC All Rights Reserved.
859 *
860 * Use of this source code is governed by an MIT-style license that can be
861 * found in the LICENSE file at https://angular.io/license
862 */
863
864/**
865 * @license
866 * Copyright Google LLC All Rights Reserved.
867 *
868 * Use of this source code is governed by an MIT-style license that can be
869 * found in the LICENSE file at https://angular.io/license
870 */
871
872/**
873 * Generated bundle index. Do not edit.
874 */
875
876export { MAT_SLIDER_VALUE_ACCESSOR, MatSlider, MatSliderChange, MatSliderModule };
877//# sourceMappingURL=slider.mjs.map