slider.mjs 94 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786
  1. import { Directionality } from '@angular/cdk/bidi';
  2. import { Platform } from '@angular/cdk/platform';
  3. import * as i0 from '@angular/core';
  4. import { InjectionToken, inject, ChangeDetectorRef, NgZone, Renderer2, ElementRef, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, ViewChild, ANIMATION_MODULE_TYPE, booleanAttribute, numberAttribute, ViewChildren, ContentChild, ContentChildren, forwardRef, EventEmitter, signal, Directive, Output, NgModule } from '@angular/core';
  5. import { b as RippleState, M as MatRipple, a as MAT_RIPPLE_GLOBAL_OPTIONS } from './ripple-BT3tzh6F.mjs';
  6. import { _CdkPrivateStyleLoader } from '@angular/cdk/private';
  7. import { _ as _StructuralStylesLoader } from './structural-styles-BQUT6wsL.mjs';
  8. import { NG_VALUE_ACCESSOR } from '@angular/forms';
  9. import { Subject } from 'rxjs';
  10. import { M as MatCommonModule } from './common-module-WayjW0Pb.mjs';
  11. import { M as MatRippleModule } from './index-SYVYjXwK.mjs';
  12. import '@angular/cdk/a11y';
  13. import '@angular/cdk/coercion';
  14. /**
  15. * Thumb types: range slider has two thumbs (START, END) whereas single point
  16. * slider only has one thumb (END).
  17. */
  18. var _MatThumb;
  19. (function (_MatThumb) {
  20. _MatThumb[_MatThumb["START"] = 1] = "START";
  21. _MatThumb[_MatThumb["END"] = 2] = "END";
  22. })(_MatThumb || (_MatThumb = {}));
  23. /** Tick mark enum, for discrete sliders. */
  24. var _MatTickMark;
  25. (function (_MatTickMark) {
  26. _MatTickMark[_MatTickMark["ACTIVE"] = 0] = "ACTIVE";
  27. _MatTickMark[_MatTickMark["INACTIVE"] = 1] = "INACTIVE";
  28. })(_MatTickMark || (_MatTickMark = {}));
  29. /**
  30. * Injection token that can be used for a `MatSlider` to provide itself as a
  31. * parent to the `MatSliderThumb` and `MatSliderRangeThumb`.
  32. * Used primarily to avoid circular imports.
  33. * @docs-private
  34. */
  35. const MAT_SLIDER = new InjectionToken('_MatSlider');
  36. /**
  37. * Injection token that can be used to query for a `MatSliderThumb`.
  38. * Used primarily to avoid circular imports.
  39. * @docs-private
  40. */
  41. const MAT_SLIDER_THUMB = new InjectionToken('_MatSliderThumb');
  42. /**
  43. * Injection token that can be used to query for a `MatSliderRangeThumb`.
  44. * Used primarily to avoid circular imports.
  45. * @docs-private
  46. */
  47. const MAT_SLIDER_RANGE_THUMB = new InjectionToken('_MatSliderRangeThumb');
  48. /**
  49. * Injection token that can be used to query for a `MatSliderVisualThumb`.
  50. * Used primarily to avoid circular imports.
  51. * @docs-private
  52. */
  53. const MAT_SLIDER_VISUAL_THUMB = new InjectionToken('_MatSliderVisualThumb');
  54. /**
  55. * A simple change event emitted by the MatSlider component.
  56. * @deprecated Use event bindings directly on the MatSliderThumbs for `change` and `input` events. See https://v17.material.angular.dev/guide/mdc-migration for information about migrating.
  57. * @breaking-change 17.0.0
  58. */
  59. class MatSliderChange {
  60. /** The MatSliderThumb that was interacted with. */
  61. source;
  62. /** The MatSlider that was interacted with. */
  63. parent;
  64. /** The new value of the source slider. */
  65. value;
  66. }
  67. /**
  68. * The visual slider thumb.
  69. *
  70. * Handles the slider thumb ripple states (hover, focus, and active),
  71. * and displaying the value tooltip on discrete sliders.
  72. * @docs-private
  73. */
  74. class MatSliderVisualThumb {
  75. _cdr = inject(ChangeDetectorRef);
  76. _ngZone = inject(NgZone);
  77. _slider = inject(MAT_SLIDER);
  78. _renderer = inject(Renderer2);
  79. _listenerCleanups;
  80. /** Whether the slider displays a numeric value label upon pressing the thumb. */
  81. discrete;
  82. /** Indicates which slider thumb this input corresponds to. */
  83. thumbPosition;
  84. /** The display value of the slider thumb. */
  85. valueIndicatorText;
  86. /** The MatRipple for this slider thumb. */
  87. _ripple;
  88. /** The slider thumb knob. */
  89. _knob;
  90. /** The slider thumb value indicator container. */
  91. _valueIndicatorContainer;
  92. /** The slider input corresponding to this slider thumb. */
  93. _sliderInput;
  94. /** The native html element of the slider input corresponding to this thumb. */
  95. _sliderInputEl;
  96. /** The RippleRef for the slider thumbs hover state. */
  97. _hoverRippleRef;
  98. /** The RippleRef for the slider thumbs focus state. */
  99. _focusRippleRef;
  100. /** The RippleRef for the slider thumbs active state. */
  101. _activeRippleRef;
  102. /** Whether the slider thumb is currently being hovered. */
  103. _isHovered = false;
  104. /** Whether the slider thumb is currently being pressed. */
  105. _isActive = false;
  106. /** Whether the value indicator tooltip is visible. */
  107. _isValueIndicatorVisible = false;
  108. /** The host native HTML input element. */
  109. _hostElement = inject(ElementRef).nativeElement;
  110. _platform = inject(Platform);
  111. constructor() { }
  112. ngAfterViewInit() {
  113. const sliderInput = this._slider._getInput(this.thumbPosition);
  114. // No-op if the slider isn't configured properly. `MatSlider` will
  115. // throw an error instructing the user how to set up the slider.
  116. if (!sliderInput) {
  117. return;
  118. }
  119. this._ripple.radius = 24;
  120. this._sliderInput = sliderInput;
  121. this._sliderInputEl = this._sliderInput._hostElement;
  122. // These listeners don't update any data bindings so we bind them outside
  123. // of the NgZone to prevent Angular from needlessly running change detection.
  124. this._ngZone.runOutsideAngular(() => {
  125. const input = this._sliderInputEl;
  126. const renderer = this._renderer;
  127. this._listenerCleanups = [
  128. renderer.listen(input, 'pointermove', this._onPointerMove),
  129. renderer.listen(input, 'pointerdown', this._onDragStart),
  130. renderer.listen(input, 'pointerup', this._onDragEnd),
  131. renderer.listen(input, 'pointerleave', this._onMouseLeave),
  132. renderer.listen(input, 'focus', this._onFocus),
  133. renderer.listen(input, 'blur', this._onBlur),
  134. ];
  135. });
  136. }
  137. ngOnDestroy() {
  138. this._listenerCleanups?.forEach(cleanup => cleanup());
  139. }
  140. _onPointerMove = (event) => {
  141. if (this._sliderInput._isFocused) {
  142. return;
  143. }
  144. const rect = this._hostElement.getBoundingClientRect();
  145. const isHovered = this._slider._isCursorOnSliderThumb(event, rect);
  146. this._isHovered = isHovered;
  147. if (isHovered) {
  148. this._showHoverRipple();
  149. }
  150. else {
  151. this._hideRipple(this._hoverRippleRef);
  152. }
  153. };
  154. _onMouseLeave = () => {
  155. this._isHovered = false;
  156. this._hideRipple(this._hoverRippleRef);
  157. };
  158. _onFocus = () => {
  159. // We don't want to show the hover ripple on top of the focus ripple.
  160. // Happen when the users cursor is over a thumb and then the user tabs to it.
  161. this._hideRipple(this._hoverRippleRef);
  162. this._showFocusRipple();
  163. this._hostElement.classList.add('mdc-slider__thumb--focused');
  164. };
  165. _onBlur = () => {
  166. // Happens when the user tabs away while still dragging a thumb.
  167. if (!this._isActive) {
  168. this._hideRipple(this._focusRippleRef);
  169. }
  170. // Happens when the user tabs away from a thumb but their cursor is still over it.
  171. if (this._isHovered) {
  172. this._showHoverRipple();
  173. }
  174. this._hostElement.classList.remove('mdc-slider__thumb--focused');
  175. };
  176. _onDragStart = (event) => {
  177. if (event.button !== 0) {
  178. return;
  179. }
  180. this._isActive = true;
  181. this._showActiveRipple();
  182. };
  183. _onDragEnd = () => {
  184. this._isActive = false;
  185. this._hideRipple(this._activeRippleRef);
  186. // Happens when the user starts dragging a thumb, tabs away, and then stops dragging.
  187. if (!this._sliderInput._isFocused) {
  188. this._hideRipple(this._focusRippleRef);
  189. }
  190. // On Safari we need to immediately re-show the hover ripple because
  191. // sliders do not retain focus from pointer events on that platform.
  192. if (this._platform.SAFARI) {
  193. this._showHoverRipple();
  194. }
  195. };
  196. /** Handles displaying the hover ripple. */
  197. _showHoverRipple() {
  198. if (!this._isShowingRipple(this._hoverRippleRef)) {
  199. this._hoverRippleRef = this._showRipple({ enterDuration: 0, exitDuration: 0 });
  200. this._hoverRippleRef?.element.classList.add('mat-mdc-slider-hover-ripple');
  201. }
  202. }
  203. /** Handles displaying the focus ripple. */
  204. _showFocusRipple() {
  205. // Show the focus ripple event if noop animations are enabled.
  206. if (!this._isShowingRipple(this._focusRippleRef)) {
  207. this._focusRippleRef = this._showRipple({ enterDuration: 0, exitDuration: 0 }, true);
  208. this._focusRippleRef?.element.classList.add('mat-mdc-slider-focus-ripple');
  209. }
  210. }
  211. /** Handles displaying the active ripple. */
  212. _showActiveRipple() {
  213. if (!this._isShowingRipple(this._activeRippleRef)) {
  214. this._activeRippleRef = this._showRipple({ enterDuration: 225, exitDuration: 400 });
  215. this._activeRippleRef?.element.classList.add('mat-mdc-slider-active-ripple');
  216. }
  217. }
  218. /** Whether the given rippleRef is currently fading in or visible. */
  219. _isShowingRipple(rippleRef) {
  220. return rippleRef?.state === RippleState.FADING_IN || rippleRef?.state === RippleState.VISIBLE;
  221. }
  222. /** Manually launches the slider thumb ripple using the specified ripple animation config. */
  223. _showRipple(animation, ignoreGlobalRippleConfig) {
  224. if (this._slider.disabled) {
  225. return;
  226. }
  227. this._showValueIndicator();
  228. if (this._slider._isRange) {
  229. const sibling = this._slider._getThumb(this.thumbPosition === _MatThumb.START ? _MatThumb.END : _MatThumb.START);
  230. sibling._showValueIndicator();
  231. }
  232. if (this._slider._globalRippleOptions?.disabled && !ignoreGlobalRippleConfig) {
  233. return;
  234. }
  235. return this._ripple.launch({
  236. animation: this._slider._noopAnimations ? { enterDuration: 0, exitDuration: 0 } : animation,
  237. centered: true,
  238. persistent: true,
  239. });
  240. }
  241. /**
  242. * Fades out the given ripple.
  243. * Also hides the value indicator if no ripple is showing.
  244. */
  245. _hideRipple(rippleRef) {
  246. rippleRef?.fadeOut();
  247. if (this._isShowingAnyRipple()) {
  248. return;
  249. }
  250. if (!this._slider._isRange) {
  251. this._hideValueIndicator();
  252. }
  253. const sibling = this._getSibling();
  254. if (!sibling._isShowingAnyRipple()) {
  255. this._hideValueIndicator();
  256. sibling._hideValueIndicator();
  257. }
  258. }
  259. /** Shows the value indicator ui. */
  260. _showValueIndicator() {
  261. this._hostElement.classList.add('mdc-slider__thumb--with-indicator');
  262. }
  263. /** Hides the value indicator ui. */
  264. _hideValueIndicator() {
  265. this._hostElement.classList.remove('mdc-slider__thumb--with-indicator');
  266. }
  267. _getSibling() {
  268. return this._slider._getThumb(this.thumbPosition === _MatThumb.START ? _MatThumb.END : _MatThumb.START);
  269. }
  270. /** Gets the value indicator container's native HTML element. */
  271. _getValueIndicatorContainer() {
  272. return this._valueIndicatorContainer?.nativeElement;
  273. }
  274. /** Gets the native HTML element of the slider thumb knob. */
  275. _getKnob() {
  276. return this._knob.nativeElement;
  277. }
  278. _isShowingAnyRipple() {
  279. return (this._isShowingRipple(this._hoverRippleRef) ||
  280. this._isShowingRipple(this._focusRippleRef) ||
  281. this._isShowingRipple(this._activeRippleRef));
  282. }
  283. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatSliderVisualThumb, deps: [], target: i0.ɵɵFactoryTarget.Component });
  284. static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: MatSliderVisualThumb, isStandalone: true, selector: "mat-slider-visual-thumb", inputs: { discrete: "discrete", thumbPosition: "thumbPosition", valueIndicatorText: "valueIndicatorText" }, host: { classAttribute: "mdc-slider__thumb mat-mdc-slider-visual-thumb" }, providers: [{ provide: MAT_SLIDER_VISUAL_THUMB, useExisting: MatSliderVisualThumb }], viewQueries: [{ propertyName: "_ripple", first: true, predicate: MatRipple, descendants: true }, { propertyName: "_knob", first: true, predicate: ["knob"], descendants: true }, { propertyName: "_valueIndicatorContainer", first: true, predicate: ["valueIndicatorContainer"], descendants: true }], ngImport: i0, template: "@if (discrete) {\n <div class=\"mdc-slider__value-indicator-container\" #valueIndicatorContainer>\n <div class=\"mdc-slider__value-indicator\">\n <span class=\"mdc-slider__value-indicator-text\">{{valueIndicatorText}}</span>\n </div>\n </div>\n}\n<div class=\"mdc-slider__thumb-knob\" #knob></div>\n<div matRipple class=\"mat-focus-indicator\" [matRippleDisabled]=\"true\"></div>\n", styles: [".mat-mdc-slider-visual-thumb .mat-ripple{height:100%;width:100%}.mat-mdc-slider .mdc-slider__tick-marks{justify-content:start}.mat-mdc-slider .mdc-slider__tick-marks .mdc-slider__tick-mark--active,.mat-mdc-slider .mdc-slider__tick-marks .mdc-slider__tick-mark--inactive{position:absolute;left:2px}\n"], dependencies: [{ kind: "directive", type: MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
  285. }
  286. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatSliderVisualThumb, decorators: [{
  287. type: Component,
  288. args: [{ selector: 'mat-slider-visual-thumb', host: {
  289. 'class': 'mdc-slider__thumb mat-mdc-slider-visual-thumb',
  290. }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [{ provide: MAT_SLIDER_VISUAL_THUMB, useExisting: MatSliderVisualThumb }], imports: [MatRipple], template: "@if (discrete) {\n <div class=\"mdc-slider__value-indicator-container\" #valueIndicatorContainer>\n <div class=\"mdc-slider__value-indicator\">\n <span class=\"mdc-slider__value-indicator-text\">{{valueIndicatorText}}</span>\n </div>\n </div>\n}\n<div class=\"mdc-slider__thumb-knob\" #knob></div>\n<div matRipple class=\"mat-focus-indicator\" [matRippleDisabled]=\"true\"></div>\n", styles: [".mat-mdc-slider-visual-thumb .mat-ripple{height:100%;width:100%}.mat-mdc-slider .mdc-slider__tick-marks{justify-content:start}.mat-mdc-slider .mdc-slider__tick-marks .mdc-slider__tick-mark--active,.mat-mdc-slider .mdc-slider__tick-marks .mdc-slider__tick-mark--inactive{position:absolute;left:2px}\n"] }]
  291. }], ctorParameters: () => [], propDecorators: { discrete: [{
  292. type: Input
  293. }], thumbPosition: [{
  294. type: Input
  295. }], valueIndicatorText: [{
  296. type: Input
  297. }], _ripple: [{
  298. type: ViewChild,
  299. args: [MatRipple]
  300. }], _knob: [{
  301. type: ViewChild,
  302. args: ['knob']
  303. }], _valueIndicatorContainer: [{
  304. type: ViewChild,
  305. args: ['valueIndicatorContainer']
  306. }] } });
  307. // TODO(wagnermaciel): maybe handle the following edge case:
  308. // 1. start dragging discrete slider
  309. // 2. tab to disable checkbox
  310. // 3. without ending drag, disable the slider
  311. /**
  312. * Allows users to select from a range of values by moving the slider thumb. It is similar in
  313. * behavior to the native `<input type="range">` element.
  314. */
  315. class MatSlider {
  316. _ngZone = inject(NgZone);
  317. _cdr = inject(ChangeDetectorRef);
  318. _elementRef = inject(ElementRef);
  319. _dir = inject(Directionality, { optional: true });
  320. _globalRippleOptions = inject(MAT_RIPPLE_GLOBAL_OPTIONS, {
  321. optional: true,
  322. });
  323. /** The active portion of the slider track. */
  324. _trackActive;
  325. /** The slider thumb(s). */
  326. _thumbs;
  327. /** The sliders hidden range input(s). */
  328. _input;
  329. /** The sliders hidden range input(s). */
  330. _inputs;
  331. /** Whether the slider is disabled. */
  332. get disabled() {
  333. return this._disabled;
  334. }
  335. set disabled(v) {
  336. this._disabled = v;
  337. const endInput = this._getInput(_MatThumb.END);
  338. const startInput = this._getInput(_MatThumb.START);
  339. if (endInput) {
  340. endInput.disabled = this._disabled;
  341. }
  342. if (startInput) {
  343. startInput.disabled = this._disabled;
  344. }
  345. }
  346. _disabled = false;
  347. /** Whether the slider displays a numeric value label upon pressing the thumb. */
  348. get discrete() {
  349. return this._discrete;
  350. }
  351. set discrete(v) {
  352. this._discrete = v;
  353. this._updateValueIndicatorUIs();
  354. }
  355. _discrete = false;
  356. /** Whether the slider displays tick marks along the slider track. */
  357. showTickMarks = false;
  358. /** The minimum value that the slider can have. */
  359. get min() {
  360. return this._min;
  361. }
  362. set min(v) {
  363. const min = isNaN(v) ? this._min : v;
  364. if (this._min !== min) {
  365. this._updateMin(min);
  366. }
  367. }
  368. _min = 0;
  369. /**
  370. * Theme color of the slider. This API is supported in M2 themes only, it
  371. * has no effect in M3 themes. For color customization in M3, see https://material.angular.dev/components/slider/styling.
  372. *
  373. * For information on applying color variants in M3, see
  374. * https://material.angular.dev/guide/material-2-theming#optional-add-backwards-compatibility-styles-for-color-variants
  375. */
  376. color;
  377. /** Whether ripples are disabled in the slider. */
  378. disableRipple = false;
  379. _updateMin(min) {
  380. const prevMin = this._min;
  381. this._min = min;
  382. this._isRange ? this._updateMinRange({ old: prevMin, new: min }) : this._updateMinNonRange(min);
  383. this._onMinMaxOrStepChange();
  384. }
  385. _updateMinRange(min) {
  386. const endInput = this._getInput(_MatThumb.END);
  387. const startInput = this._getInput(_MatThumb.START);
  388. const oldEndValue = endInput.value;
  389. const oldStartValue = startInput.value;
  390. startInput.min = min.new;
  391. endInput.min = Math.max(min.new, startInput.value);
  392. startInput.max = Math.min(endInput.max, endInput.value);
  393. startInput._updateWidthInactive();
  394. endInput._updateWidthInactive();
  395. min.new < min.old
  396. ? this._onTranslateXChangeBySideEffect(endInput, startInput)
  397. : this._onTranslateXChangeBySideEffect(startInput, endInput);
  398. if (oldEndValue !== endInput.value) {
  399. this._onValueChange(endInput);
  400. }
  401. if (oldStartValue !== startInput.value) {
  402. this._onValueChange(startInput);
  403. }
  404. }
  405. _updateMinNonRange(min) {
  406. const input = this._getInput(_MatThumb.END);
  407. if (input) {
  408. const oldValue = input.value;
  409. input.min = min;
  410. input._updateThumbUIByValue();
  411. this._updateTrackUI(input);
  412. if (oldValue !== input.value) {
  413. this._onValueChange(input);
  414. }
  415. }
  416. }
  417. /** The maximum value that the slider can have. */
  418. get max() {
  419. return this._max;
  420. }
  421. set max(v) {
  422. const max = isNaN(v) ? this._max : v;
  423. if (this._max !== max) {
  424. this._updateMax(max);
  425. }
  426. }
  427. _max = 100;
  428. _updateMax(max) {
  429. const prevMax = this._max;
  430. this._max = max;
  431. this._isRange ? this._updateMaxRange({ old: prevMax, new: max }) : this._updateMaxNonRange(max);
  432. this._onMinMaxOrStepChange();
  433. }
  434. _updateMaxRange(max) {
  435. const endInput = this._getInput(_MatThumb.END);
  436. const startInput = this._getInput(_MatThumb.START);
  437. const oldEndValue = endInput.value;
  438. const oldStartValue = startInput.value;
  439. endInput.max = max.new;
  440. startInput.max = Math.min(max.new, endInput.value);
  441. endInput.min = startInput.value;
  442. endInput._updateWidthInactive();
  443. startInput._updateWidthInactive();
  444. max.new > max.old
  445. ? this._onTranslateXChangeBySideEffect(startInput, endInput)
  446. : this._onTranslateXChangeBySideEffect(endInput, startInput);
  447. if (oldEndValue !== endInput.value) {
  448. this._onValueChange(endInput);
  449. }
  450. if (oldStartValue !== startInput.value) {
  451. this._onValueChange(startInput);
  452. }
  453. }
  454. _updateMaxNonRange(max) {
  455. const input = this._getInput(_MatThumb.END);
  456. if (input) {
  457. const oldValue = input.value;
  458. input.max = max;
  459. input._updateThumbUIByValue();
  460. this._updateTrackUI(input);
  461. if (oldValue !== input.value) {
  462. this._onValueChange(input);
  463. }
  464. }
  465. }
  466. /** The values at which the thumb will snap. */
  467. get step() {
  468. return this._step;
  469. }
  470. set step(v) {
  471. const step = isNaN(v) ? this._step : v;
  472. if (this._step !== step) {
  473. this._updateStep(step);
  474. }
  475. }
  476. _step = 1;
  477. _updateStep(step) {
  478. this._step = step;
  479. this._isRange ? this._updateStepRange() : this._updateStepNonRange();
  480. this._onMinMaxOrStepChange();
  481. }
  482. _updateStepRange() {
  483. const endInput = this._getInput(_MatThumb.END);
  484. const startInput = this._getInput(_MatThumb.START);
  485. const oldEndValue = endInput.value;
  486. const oldStartValue = startInput.value;
  487. const prevStartValue = startInput.value;
  488. endInput.min = this._min;
  489. startInput.max = this._max;
  490. endInput.step = this._step;
  491. startInput.step = this._step;
  492. if (this._platform.SAFARI) {
  493. endInput.value = endInput.value;
  494. startInput.value = startInput.value;
  495. }
  496. endInput.min = Math.max(this._min, startInput.value);
  497. startInput.max = Math.min(this._max, endInput.value);
  498. startInput._updateWidthInactive();
  499. endInput._updateWidthInactive();
  500. endInput.value < prevStartValue
  501. ? this._onTranslateXChangeBySideEffect(startInput, endInput)
  502. : this._onTranslateXChangeBySideEffect(endInput, startInput);
  503. if (oldEndValue !== endInput.value) {
  504. this._onValueChange(endInput);
  505. }
  506. if (oldStartValue !== startInput.value) {
  507. this._onValueChange(startInput);
  508. }
  509. }
  510. _updateStepNonRange() {
  511. const input = this._getInput(_MatThumb.END);
  512. if (input) {
  513. const oldValue = input.value;
  514. input.step = this._step;
  515. if (this._platform.SAFARI) {
  516. input.value = input.value;
  517. }
  518. input._updateThumbUIByValue();
  519. if (oldValue !== input.value) {
  520. this._onValueChange(input);
  521. }
  522. }
  523. }
  524. /**
  525. * Function that will be used to format the value before it is displayed
  526. * in the thumb label. Can be used to format very large number in order
  527. * for them to fit into the slider thumb.
  528. */
  529. displayWith = (value) => `${value}`;
  530. /** Used to keep track of & render the active & inactive tick marks on the slider track. */
  531. _tickMarks;
  532. /** Whether animations have been disabled. */
  533. _noopAnimations;
  534. /** Subscription to changes to the directionality (LTR / RTL) context for the application. */
  535. _dirChangeSubscription;
  536. /** Observer used to monitor size changes in the slider. */
  537. _resizeObserver;
  538. // Stored dimensions to avoid calling getBoundingClientRect redundantly.
  539. _cachedWidth;
  540. _cachedLeft;
  541. _rippleRadius = 24;
  542. // The value indicator tooltip text for the visual slider thumb(s).
  543. /** @docs-private */
  544. startValueIndicatorText = '';
  545. /** @docs-private */
  546. endValueIndicatorText = '';
  547. // Used to control the translateX of the visual slider thumb(s).
  548. _endThumbTransform;
  549. _startThumbTransform;
  550. _isRange = false;
  551. /** Whether the slider is rtl. */
  552. _isRtl = false;
  553. _hasViewInitialized = false;
  554. /**
  555. * The width of the tick mark track.
  556. * The tick mark track width is different from full track width
  557. */
  558. _tickMarkTrackWidth = 0;
  559. _hasAnimation = false;
  560. _resizeTimer = null;
  561. _platform = inject(Platform);
  562. constructor() {
  563. inject(_CdkPrivateStyleLoader).load(_StructuralStylesLoader);
  564. const animationMode = inject(ANIMATION_MODULE_TYPE, { optional: true });
  565. this._noopAnimations = animationMode === 'NoopAnimations';
  566. if (this._dir) {
  567. this._dirChangeSubscription = this._dir.change.subscribe(() => this._onDirChange());
  568. this._isRtl = this._dir.value === 'rtl';
  569. }
  570. }
  571. /** The radius of the native slider's knob. AFAIK there is no way to avoid hardcoding this. */
  572. _knobRadius = 8;
  573. _inputPadding;
  574. ngAfterViewInit() {
  575. if (this._platform.isBrowser) {
  576. this._updateDimensions();
  577. }
  578. const eInput = this._getInput(_MatThumb.END);
  579. const sInput = this._getInput(_MatThumb.START);
  580. this._isRange = !!eInput && !!sInput;
  581. this._cdr.detectChanges();
  582. if (typeof ngDevMode === 'undefined' || ngDevMode) {
  583. _validateInputs(this._isRange, this._getInput(_MatThumb.END), this._getInput(_MatThumb.START));
  584. }
  585. const thumb = this._getThumb(_MatThumb.END);
  586. this._rippleRadius = thumb._ripple.radius;
  587. this._inputPadding = this._rippleRadius - this._knobRadius;
  588. this._isRange
  589. ? this._initUIRange(eInput, sInput)
  590. : this._initUINonRange(eInput);
  591. this._updateTrackUI(eInput);
  592. this._updateTickMarkUI();
  593. this._updateTickMarkTrackUI();
  594. this._observeHostResize();
  595. this._cdr.detectChanges();
  596. }
  597. _initUINonRange(eInput) {
  598. eInput.initProps();
  599. eInput.initUI();
  600. this._updateValueIndicatorUI(eInput);
  601. this._hasViewInitialized = true;
  602. eInput._updateThumbUIByValue();
  603. }
  604. _initUIRange(eInput, sInput) {
  605. eInput.initProps();
  606. eInput.initUI();
  607. sInput.initProps();
  608. sInput.initUI();
  609. eInput._updateMinMax();
  610. sInput._updateMinMax();
  611. eInput._updateStaticStyles();
  612. sInput._updateStaticStyles();
  613. this._updateValueIndicatorUIs();
  614. this._hasViewInitialized = true;
  615. eInput._updateThumbUIByValue();
  616. sInput._updateThumbUIByValue();
  617. }
  618. ngOnDestroy() {
  619. this._dirChangeSubscription.unsubscribe();
  620. this._resizeObserver?.disconnect();
  621. this._resizeObserver = null;
  622. }
  623. /** Handles updating the slider ui after a dir change. */
  624. _onDirChange() {
  625. this._isRtl = this._dir?.value === 'rtl';
  626. this._isRange ? this._onDirChangeRange() : this._onDirChangeNonRange();
  627. this._updateTickMarkUI();
  628. }
  629. _onDirChangeRange() {
  630. const endInput = this._getInput(_MatThumb.END);
  631. const startInput = this._getInput(_MatThumb.START);
  632. endInput._setIsLeftThumb();
  633. startInput._setIsLeftThumb();
  634. endInput.translateX = endInput._calcTranslateXByValue();
  635. startInput.translateX = startInput._calcTranslateXByValue();
  636. endInput._updateStaticStyles();
  637. startInput._updateStaticStyles();
  638. endInput._updateWidthInactive();
  639. startInput._updateWidthInactive();
  640. endInput._updateThumbUIByValue();
  641. startInput._updateThumbUIByValue();
  642. }
  643. _onDirChangeNonRange() {
  644. const input = this._getInput(_MatThumb.END);
  645. input._updateThumbUIByValue();
  646. }
  647. /** Starts observing and updating the slider if the host changes its size. */
  648. _observeHostResize() {
  649. if (typeof ResizeObserver === 'undefined' || !ResizeObserver) {
  650. return;
  651. }
  652. this._ngZone.runOutsideAngular(() => {
  653. this._resizeObserver = new ResizeObserver(() => {
  654. if (this._isActive()) {
  655. return;
  656. }
  657. if (this._resizeTimer) {
  658. clearTimeout(this._resizeTimer);
  659. }
  660. this._onResize();
  661. });
  662. this._resizeObserver.observe(this._elementRef.nativeElement);
  663. });
  664. }
  665. /** Whether any of the thumbs are currently active. */
  666. _isActive() {
  667. return this._getThumb(_MatThumb.START)._isActive || this._getThumb(_MatThumb.END)._isActive;
  668. }
  669. _getValue(thumbPosition = _MatThumb.END) {
  670. const input = this._getInput(thumbPosition);
  671. if (!input) {
  672. return this.min;
  673. }
  674. return input.value;
  675. }
  676. _skipUpdate() {
  677. return !!(this._getInput(_MatThumb.START)?._skipUIUpdate || this._getInput(_MatThumb.END)?._skipUIUpdate);
  678. }
  679. /** Stores the slider dimensions. */
  680. _updateDimensions() {
  681. this._cachedWidth = this._elementRef.nativeElement.offsetWidth;
  682. this._cachedLeft = this._elementRef.nativeElement.getBoundingClientRect().left;
  683. }
  684. /** Sets the styles for the active portion of the track. */
  685. _setTrackActiveStyles(styles) {
  686. const trackStyle = this._trackActive.nativeElement.style;
  687. trackStyle.left = styles.left;
  688. trackStyle.right = styles.right;
  689. trackStyle.transformOrigin = styles.transformOrigin;
  690. trackStyle.transform = styles.transform;
  691. }
  692. /** Returns the translateX positioning for a tick mark based on it's index. */
  693. _calcTickMarkTransform(index) {
  694. // TODO(wagnermaciel): See if we can avoid doing this and just using flex to position these.
  695. const offset = index * (this._tickMarkTrackWidth / (this._tickMarks.length - 1));
  696. const translateX = this._isRtl ? this._cachedWidth - 6 - offset : offset;
  697. return `translateX(${translateX}px`;
  698. }
  699. // Handlers for updating the slider ui.
  700. _onTranslateXChange(source) {
  701. if (!this._hasViewInitialized) {
  702. return;
  703. }
  704. this._updateThumbUI(source);
  705. this._updateTrackUI(source);
  706. this._updateOverlappingThumbUI(source);
  707. }
  708. _onTranslateXChangeBySideEffect(input1, input2) {
  709. if (!this._hasViewInitialized) {
  710. return;
  711. }
  712. input1._updateThumbUIByValue();
  713. input2._updateThumbUIByValue();
  714. }
  715. _onValueChange(source) {
  716. if (!this._hasViewInitialized) {
  717. return;
  718. }
  719. this._updateValueIndicatorUI(source);
  720. this._updateTickMarkUI();
  721. this._cdr.detectChanges();
  722. }
  723. _onMinMaxOrStepChange() {
  724. if (!this._hasViewInitialized) {
  725. return;
  726. }
  727. this._updateTickMarkUI();
  728. this._updateTickMarkTrackUI();
  729. this._cdr.markForCheck();
  730. }
  731. _onResize() {
  732. if (!this._hasViewInitialized) {
  733. return;
  734. }
  735. this._updateDimensions();
  736. if (this._isRange) {
  737. const eInput = this._getInput(_MatThumb.END);
  738. const sInput = this._getInput(_MatThumb.START);
  739. eInput._updateThumbUIByValue();
  740. sInput._updateThumbUIByValue();
  741. eInput._updateStaticStyles();
  742. sInput._updateStaticStyles();
  743. eInput._updateMinMax();
  744. sInput._updateMinMax();
  745. eInput._updateWidthInactive();
  746. sInput._updateWidthInactive();
  747. }
  748. else {
  749. const eInput = this._getInput(_MatThumb.END);
  750. if (eInput) {
  751. eInput._updateThumbUIByValue();
  752. }
  753. }
  754. this._updateTickMarkUI();
  755. this._updateTickMarkTrackUI();
  756. this._cdr.detectChanges();
  757. }
  758. /** Whether or not the slider thumbs overlap. */
  759. _thumbsOverlap = false;
  760. /** Returns true if the slider knobs are overlapping one another. */
  761. _areThumbsOverlapping() {
  762. const startInput = this._getInput(_MatThumb.START);
  763. const endInput = this._getInput(_MatThumb.END);
  764. if (!startInput || !endInput) {
  765. return false;
  766. }
  767. return endInput.translateX - startInput.translateX < 20;
  768. }
  769. /**
  770. * Updates the class names of overlapping slider thumbs so
  771. * that the current active thumb is styled to be on "top".
  772. */
  773. _updateOverlappingThumbClassNames(source) {
  774. const sibling = source.getSibling();
  775. const sourceThumb = this._getThumb(source.thumbPosition);
  776. const siblingThumb = this._getThumb(sibling.thumbPosition);
  777. siblingThumb._hostElement.classList.remove('mdc-slider__thumb--top');
  778. sourceThumb._hostElement.classList.toggle('mdc-slider__thumb--top', this._thumbsOverlap);
  779. }
  780. /** Updates the UI of slider thumbs when they begin or stop overlapping. */
  781. _updateOverlappingThumbUI(source) {
  782. if (!this._isRange || this._skipUpdate()) {
  783. return;
  784. }
  785. if (this._thumbsOverlap !== this._areThumbsOverlapping()) {
  786. this._thumbsOverlap = !this._thumbsOverlap;
  787. this._updateOverlappingThumbClassNames(source);
  788. }
  789. }
  790. // _MatThumb styles update conditions
  791. //
  792. // 1. TranslateX, resize, or dir change
  793. // - Reason: The thumb styles need to be updated according to the new translateX.
  794. // 2. Min, max, or step
  795. // - Reason: The value may have silently changed.
  796. /** Updates the translateX of the given thumb. */
  797. _updateThumbUI(source) {
  798. if (this._skipUpdate()) {
  799. return;
  800. }
  801. const thumb = this._getThumb(source.thumbPosition === _MatThumb.END ? _MatThumb.END : _MatThumb.START);
  802. thumb._hostElement.style.transform = `translateX(${source.translateX}px)`;
  803. }
  804. // Value indicator text update conditions
  805. //
  806. // 1. Value
  807. // - Reason: The value displayed needs to be updated.
  808. // 2. Min, max, or step
  809. // - Reason: The value may have silently changed.
  810. /** Updates the value indicator tooltip ui for the given thumb. */
  811. _updateValueIndicatorUI(source) {
  812. if (this._skipUpdate()) {
  813. return;
  814. }
  815. const valuetext = this.displayWith(source.value);
  816. this._hasViewInitialized
  817. ? source._valuetext.set(valuetext)
  818. : source._hostElement.setAttribute('aria-valuetext', valuetext);
  819. if (this.discrete) {
  820. source.thumbPosition === _MatThumb.START
  821. ? (this.startValueIndicatorText = valuetext)
  822. : (this.endValueIndicatorText = valuetext);
  823. const visualThumb = this._getThumb(source.thumbPosition);
  824. valuetext.length < 3
  825. ? visualThumb._hostElement.classList.add('mdc-slider__thumb--short-value')
  826. : visualThumb._hostElement.classList.remove('mdc-slider__thumb--short-value');
  827. }
  828. }
  829. /** Updates all value indicator UIs in the slider. */
  830. _updateValueIndicatorUIs() {
  831. const eInput = this._getInput(_MatThumb.END);
  832. const sInput = this._getInput(_MatThumb.START);
  833. if (eInput) {
  834. this._updateValueIndicatorUI(eInput);
  835. }
  836. if (sInput) {
  837. this._updateValueIndicatorUI(sInput);
  838. }
  839. }
  840. // Update Tick Mark Track Width
  841. //
  842. // 1. Min, max, or step
  843. // - Reason: The maximum reachable value may have changed.
  844. // - Side note: The maximum reachable value is different from the maximum value set by the
  845. // user. For example, a slider with [min: 5, max: 100, step: 10] would have a maximum
  846. // reachable value of 95.
  847. // 2. Resize
  848. // - Reason: The position for the maximum reachable value needs to be recalculated.
  849. /** Updates the width of the tick mark track. */
  850. _updateTickMarkTrackUI() {
  851. if (!this.showTickMarks || this._skipUpdate()) {
  852. return;
  853. }
  854. const step = this._step && this._step > 0 ? this._step : 1;
  855. const maxValue = Math.floor(this.max / step) * step;
  856. const percentage = (maxValue - this.min) / (this.max - this.min);
  857. this._tickMarkTrackWidth = (this._cachedWidth - 6) * percentage;
  858. }
  859. // Track active update conditions
  860. //
  861. // 1. TranslateX
  862. // - Reason: The track active should line up with the new thumb position.
  863. // 2. Min or max
  864. // - Reason #1: The 'active' percentage needs to be recalculated.
  865. // - Reason #2: The value may have silently changed.
  866. // 3. Step
  867. // - Reason: The value may have silently changed causing the thumb(s) to shift.
  868. // 4. Dir change
  869. // - Reason: The track active will need to be updated according to the new thumb position(s).
  870. // 5. Resize
  871. // - Reason: The total width the 'active' tracks translateX is based on has changed.
  872. /** Updates the scale on the active portion of the track. */
  873. _updateTrackUI(source) {
  874. if (this._skipUpdate()) {
  875. return;
  876. }
  877. this._isRange
  878. ? this._updateTrackUIRange(source)
  879. : this._updateTrackUINonRange(source);
  880. }
  881. _updateTrackUIRange(source) {
  882. const sibling = source.getSibling();
  883. if (!sibling || !this._cachedWidth) {
  884. return;
  885. }
  886. const activePercentage = Math.abs(sibling.translateX - source.translateX) / this._cachedWidth;
  887. if (source._isLeftThumb && this._cachedWidth) {
  888. this._setTrackActiveStyles({
  889. left: 'auto',
  890. right: `${this._cachedWidth - sibling.translateX}px`,
  891. transformOrigin: 'right',
  892. transform: `scaleX(${activePercentage})`,
  893. });
  894. }
  895. else {
  896. this._setTrackActiveStyles({
  897. left: `${sibling.translateX}px`,
  898. right: 'auto',
  899. transformOrigin: 'left',
  900. transform: `scaleX(${activePercentage})`,
  901. });
  902. }
  903. }
  904. _updateTrackUINonRange(source) {
  905. this._isRtl
  906. ? this._setTrackActiveStyles({
  907. left: 'auto',
  908. right: '0px',
  909. transformOrigin: 'right',
  910. transform: `scaleX(${1 - source.fillPercentage})`,
  911. })
  912. : this._setTrackActiveStyles({
  913. left: '0px',
  914. right: 'auto',
  915. transformOrigin: 'left',
  916. transform: `scaleX(${source.fillPercentage})`,
  917. });
  918. }
  919. // Tick mark update conditions
  920. //
  921. // 1. Value
  922. // - Reason: a tick mark which was once active might now be inactive or vice versa.
  923. // 2. Min, max, or step
  924. // - Reason #1: the number of tick marks may have changed.
  925. // - Reason #2: The value may have silently changed.
  926. /** Updates the dots along the slider track. */
  927. _updateTickMarkUI() {
  928. if (!this.showTickMarks ||
  929. this.step === undefined ||
  930. this.min === undefined ||
  931. this.max === undefined) {
  932. return;
  933. }
  934. const step = this.step > 0 ? this.step : 1;
  935. this._isRange ? this._updateTickMarkUIRange(step) : this._updateTickMarkUINonRange(step);
  936. }
  937. _updateTickMarkUINonRange(step) {
  938. const value = this._getValue();
  939. let numActive = Math.max(Math.round((value - this.min) / step), 0) + 1;
  940. let numInactive = Math.max(Math.round((this.max - value) / step), 0) - 1;
  941. this._isRtl ? numActive++ : numInactive++;
  942. this._tickMarks = Array(numActive)
  943. .fill(_MatTickMark.ACTIVE)
  944. .concat(Array(numInactive).fill(_MatTickMark.INACTIVE));
  945. }
  946. _updateTickMarkUIRange(step) {
  947. const endValue = this._getValue();
  948. const startValue = this._getValue(_MatThumb.START);
  949. const numInactiveBeforeStartThumb = Math.max(Math.round((startValue - this.min) / step), 0);
  950. const numActive = Math.max(Math.round((endValue - startValue) / step) + 1, 0);
  951. const numInactiveAfterEndThumb = Math.max(Math.round((this.max - endValue) / step), 0);
  952. this._tickMarks = Array(numInactiveBeforeStartThumb)
  953. .fill(_MatTickMark.INACTIVE)
  954. .concat(Array(numActive).fill(_MatTickMark.ACTIVE), Array(numInactiveAfterEndThumb).fill(_MatTickMark.INACTIVE));
  955. }
  956. /** Gets the slider thumb input of the given thumb position. */
  957. _getInput(thumbPosition) {
  958. if (thumbPosition === _MatThumb.END && this._input) {
  959. return this._input;
  960. }
  961. if (this._inputs?.length) {
  962. return thumbPosition === _MatThumb.START ? this._inputs.first : this._inputs.last;
  963. }
  964. return;
  965. }
  966. /** Gets the slider thumb HTML input element of the given thumb position. */
  967. _getThumb(thumbPosition) {
  968. return thumbPosition === _MatThumb.END ? this._thumbs?.last : this._thumbs?.first;
  969. }
  970. _setTransition(withAnimation) {
  971. this._hasAnimation = !this._platform.IOS && withAnimation && !this._noopAnimations;
  972. this._elementRef.nativeElement.classList.toggle('mat-mdc-slider-with-animation', this._hasAnimation);
  973. }
  974. /** Whether the given pointer event occurred within the bounds of the slider pointer's DOM Rect. */
  975. _isCursorOnSliderThumb(event, rect) {
  976. const radius = rect.width / 2;
  977. const centerX = rect.x + radius;
  978. const centerY = rect.y + radius;
  979. const dx = event.clientX - centerX;
  980. const dy = event.clientY - centerY;
  981. return Math.pow(dx, 2) + Math.pow(dy, 2) < Math.pow(radius, 2);
  982. }
  983. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatSlider, deps: [], target: i0.ɵɵFactoryTarget.Component });
  984. static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: MatSlider, isStandalone: true, selector: "mat-slider", inputs: { disabled: ["disabled", "disabled", booleanAttribute], discrete: ["discrete", "discrete", booleanAttribute], showTickMarks: ["showTickMarks", "showTickMarks", booleanAttribute], min: ["min", "min", numberAttribute], color: "color", disableRipple: ["disableRipple", "disableRipple", booleanAttribute], max: ["max", "max", numberAttribute], step: ["step", "step", numberAttribute], displayWith: "displayWith" }, host: { properties: { "class": "\"mat-\" + (color || \"primary\")", "class.mdc-slider--range": "_isRange", "class.mdc-slider--disabled": "disabled", "class.mdc-slider--discrete": "discrete", "class.mdc-slider--tick-marks": "showTickMarks", "class._mat-animation-noopable": "_noopAnimations" }, classAttribute: "mat-mdc-slider mdc-slider" }, providers: [{ provide: MAT_SLIDER, useExisting: MatSlider }], queries: [{ propertyName: "_input", first: true, predicate: MAT_SLIDER_THUMB, descendants: true }, { propertyName: "_inputs", predicate: MAT_SLIDER_RANGE_THUMB }], viewQueries: [{ propertyName: "_trackActive", first: true, predicate: ["trackActive"], descendants: true }, { propertyName: "_thumbs", predicate: MAT_SLIDER_VISUAL_THUMB, descendants: true }], exportAs: ["matSlider"], ngImport: i0, template: "<!-- Inputs -->\n<ng-content></ng-content>\n\n<!-- Track -->\n<div class=\"mdc-slider__track\">\n <div class=\"mdc-slider__track--inactive\"></div>\n <div class=\"mdc-slider__track--active\">\n <div #trackActive class=\"mdc-slider__track--active_fill\"></div>\n </div>\n @if (showTickMarks) {\n <div class=\"mdc-slider__tick-marks\" #tickMarkContainer>\n @if (_cachedWidth) {\n @for (tickMark of _tickMarks; track i; let i = $index) {\n <div\n [class]=\"tickMark === 0 ? 'mdc-slider__tick-mark--active' : 'mdc-slider__tick-mark--inactive'\"\n [style.transform]=\"_calcTickMarkTransform(i)\"></div>\n }\n }\n </div>\n }\n</div>\n\n<!-- Thumbs -->\n@if (_isRange) {\n <mat-slider-visual-thumb\n [discrete]=\"discrete\"\n [thumbPosition]=\"1\"\n [valueIndicatorText]=\"startValueIndicatorText\">\n </mat-slider-visual-thumb>\n}\n\n<mat-slider-visual-thumb\n [discrete]=\"discrete\"\n [thumbPosition]=\"2\"\n [valueIndicatorText]=\"endValueIndicatorText\">\n</mat-slider-visual-thumb>\n", styles: [".mdc-slider__track{position:absolute;top:50%;transform:translateY(-50%);width:100%;pointer-events:none;height:var(--mdc-slider-inactive-track-height, 4px)}.mdc-slider__track--active,.mdc-slider__track--inactive{display:flex;height:100%;position:absolute;width:100%}.mdc-slider__track--active{overflow:hidden;border-radius:var(--mdc-slider-active-track-shape, var(--mat-sys-corner-full));height:var(--mdc-slider-active-track-height, 4px);top:calc((var(--mdc-slider-inactive-track-height, 4px) - var(--mdc-slider-active-track-height, 4px))/2)}.mdc-slider__track--active_fill{border-top-style:solid;box-sizing:border-box;height:100%;width:100%;position:relative;transform-origin:left;transition:transform 80ms ease;border-color:var(--mdc-slider-active-track-color, var(--mat-sys-primary));border-top-width:var(--mdc-slider-active-track-height, 4px)}.mdc-slider--disabled .mdc-slider__track--active_fill{border-color:var(--mdc-slider-disabled-active-track-color, var(--mat-sys-on-surface))}[dir=rtl] .mdc-slider__track--active_fill{-webkit-transform-origin:right;transform-origin:right}.mdc-slider__track--inactive{left:0;top:0;opacity:.24;background-color:var(--mdc-slider-inactive-track-color, var(--mat-sys-surface-variant));height:var(--mdc-slider-inactive-track-height, 4px);border-radius:var(--mdc-slider-inactive-track-shape, var(--mat-sys-corner-full))}.mdc-slider--disabled .mdc-slider__track--inactive{background-color:var(--mdc-slider-disabled-inactive-track-color, var(--mat-sys-on-surface));opacity:.24}.mdc-slider__track--inactive::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid rgba(0,0,0,0);border-radius:inherit;content:\"\";pointer-events:none}@media(forced-colors: active){.mdc-slider__track--inactive::before{border-color:CanvasText}}.mdc-slider__value-indicator-container{bottom:44px;left:50%;pointer-events:none;position:absolute;transform:translateX(-50%);transform:var(--mat-slider-value-indicator-container-transform, translateX(-50%) rotate(-45deg))}.mdc-slider__thumb--with-indicator .mdc-slider__value-indicator-container{pointer-events:auto}.mdc-slider__value-indicator{display:flex;align-items:center;border-radius:4px;height:32px;padding:0 12px;transform:scale(0);transform-origin:bottom;opacity:1;transition:transform 100ms cubic-bezier(0.4, 0, 1, 1);word-break:normal;background-color:var(--mdc-slider-label-container-color, var(--mat-sys-primary));color:var(--mdc-slider-label-label-text-color, var(--mat-sys-on-primary));width:var(--mat-slider-value-indicator-width, 28px);height:var(--mat-slider-value-indicator-height, 28px);padding:var(--mat-slider-value-indicator-padding, 0);opacity:var(--mat-slider-value-indicator-opacity, 1);border-radius:var(--mat-slider-value-indicator-border-radius, 50% 50% 50% 0)}.mdc-slider__thumb--with-indicator .mdc-slider__value-indicator{transition:transform 100ms cubic-bezier(0, 0, 0.2, 1);transform:scale(1)}.mdc-slider__value-indicator::before{border-left:6px solid rgba(0,0,0,0);border-right:6px solid rgba(0,0,0,0);border-top:6px solid;bottom:-5px;content:\"\";height:0;left:50%;position:absolute;transform:translateX(-50%);width:0;display:var(--mat-slider-value-indicator-caret-display, none);border-top-color:var(--mdc-slider-label-container-color, var(--mat-sys-primary))}.mdc-slider__value-indicator::after{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid rgba(0,0,0,0);border-radius:inherit;content:\"\";pointer-events:none}@media(forced-colors: active){.mdc-slider__value-indicator::after{border-color:CanvasText}}.mdc-slider__value-indicator-text{text-align:center;width:var(--mat-slider-value-indicator-width, 28px);transform:var(--mat-slider-value-indicator-text-transform, rotate(45deg));font-family:var(--mdc-slider-label-label-text-font, var(--mat-sys-label-medium-font));font-size:var(--mdc-slider-label-label-text-size, var(--mat-sys-label-medium-size));font-weight:var(--mdc-slider-label-label-text-weight, var(--mat-sys-label-medium-weight));line-height:var(--mdc-slider-label-label-text-line-height, var(--mat-sys-label-medium-line-height));letter-spacing:var(--mdc-slider-label-label-text-tracking, var(--mat-sys-label-medium-tracking))}.mdc-slider__thumb{-webkit-user-select:none;user-select:none;display:flex;left:-24px;outline:none;position:absolute;height:48px;width:48px;pointer-events:none}.mdc-slider--discrete .mdc-slider__thumb{transition:transform 80ms ease}.mdc-slider--disabled .mdc-slider__thumb{pointer-events:none}.mdc-slider__thumb--top{z-index:1}.mdc-slider__thumb-knob{position:absolute;box-sizing:border-box;left:50%;top:50%;transform:translate(-50%, -50%);border-style:solid;width:var(--mdc-slider-handle-width, 20px);height:var(--mdc-slider-handle-height, 20px);border-width:calc(var(--mdc-slider-handle-height, 20px)/2) calc(var(--mdc-slider-handle-width, 20px)/2);box-shadow:var(--mdc-slider-handle-elevation, var(--mat-sys-level1));background-color:var(--mdc-slider-handle-color, var(--mat-sys-primary));border-color:var(--mdc-slider-handle-color, var(--mat-sys-primary));border-radius:var(--mdc-slider-handle-shape, var(--mat-sys-corner-full))}.mdc-slider__thumb:hover .mdc-slider__thumb-knob{background-color:var(--mdc-slider-hover-handle-color, var(--mat-sys-primary));border-color:var(--mdc-slider-hover-handle-color, var(--mat-sys-primary))}.mdc-slider__thumb--focused .mdc-slider__thumb-knob{background-color:var(--mdc-slider-focus-handle-color, var(--mat-sys-primary));border-color:var(--mdc-slider-focus-handle-color, var(--mat-sys-primary))}.mdc-slider--disabled .mdc-slider__thumb-knob{background-color:var(--mdc-slider-disabled-handle-color, var(--mat-sys-on-surface));border-color:var(--mdc-slider-disabled-handle-color, var(--mat-sys-on-surface))}.mdc-slider__thumb--top .mdc-slider__thumb-knob,.mdc-slider__thumb--top.mdc-slider__thumb:hover .mdc-slider__thumb-knob,.mdc-slider__thumb--top.mdc-slider__thumb--focused .mdc-slider__thumb-knob{border:solid 1px #fff;box-sizing:content-box;border-color:var(--mdc-slider-with-overlap-handle-outline-color, var(--mat-sys-on-primary));border-width:var(--mdc-slider-with-overlap-handle-outline-width, 1px)}.mdc-slider__tick-marks{align-items:center;box-sizing:border-box;display:flex;height:100%;justify-content:space-between;padding:0 1px;position:absolute;width:100%}.mdc-slider__tick-mark--active,.mdc-slider__tick-mark--inactive{width:var(--mdc-slider-with-tick-marks-container-size, 2px);height:var(--mdc-slider-with-tick-marks-container-size, 2px);border-radius:var(--mdc-slider-with-tick-marks-container-shape, var(--mat-sys-corner-full))}.mdc-slider__tick-mark--inactive{opacity:var(--mdc-slider-with-tick-marks-inactive-container-opacity, 0.38);background-color:var(--mdc-slider-with-tick-marks-inactive-container-color, var(--mat-sys-on-surface-variant))}.mdc-slider--disabled .mdc-slider__tick-mark--inactive{opacity:var(--mdc-slider-with-tick-marks-inactive-container-opacity, 0.38);background-color:var(--mdc-slider-with-tick-marks-disabled-container-color, var(--mat-sys-on-surface))}.mdc-slider__tick-mark--active{opacity:var(--mdc-slider-with-tick-marks-active-container-opacity, 0.38);background-color:var(--mdc-slider-with-tick-marks-active-container-color, var(--mat-sys-on-primary))}.mdc-slider__input{cursor:pointer;left:2px;margin:0;height:44px;opacity:0;position:absolute;top:2px;width:44px;box-sizing:content-box}.mdc-slider__input.mat-mdc-slider-input-no-pointer-events{pointer-events:none}.mdc-slider__input.mat-slider__right-input{left:auto;right:0}.mat-mdc-slider{display:inline-block;box-sizing:border-box;outline:none;vertical-align:middle;cursor:pointer;height:48px;margin:0 8px;position:relative;touch-action:pan-y;width:auto;min-width:112px;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mat-mdc-slider.mdc-slider--disabled{cursor:auto;opacity:.38}.mat-mdc-slider .mdc-slider__thumb,.mat-mdc-slider .mdc-slider__track--active_fill{transition-duration:0ms}.mat-mdc-slider.mat-mdc-slider-with-animation .mdc-slider__thumb,.mat-mdc-slider.mat-mdc-slider-with-animation .mdc-slider__track--active_fill{transition-duration:80ms}.mat-mdc-slider.mdc-slider--discrete .mdc-slider__thumb,.mat-mdc-slider.mdc-slider--discrete .mdc-slider__track--active_fill{transition-duration:0ms}.mat-mdc-slider.mat-mdc-slider-with-animation .mdc-slider__thumb,.mat-mdc-slider.mat-mdc-slider-with-animation .mdc-slider__track--active_fill{transition-duration:80ms}.mat-mdc-slider .mat-ripple .mat-ripple-element{background-color:var(--mat-slider-ripple-color, var(--mat-sys-primary))}.mat-mdc-slider .mat-ripple .mat-mdc-slider-hover-ripple{background-color:var(--mat-slider-hover-state-layer-color, color-mix(in srgb, var(--mat-sys-primary) 5%, transparent))}.mat-mdc-slider .mat-ripple .mat-mdc-slider-focus-ripple,.mat-mdc-slider .mat-ripple .mat-mdc-slider-active-ripple{background-color:var(--mat-slider-focus-state-layer-color, color-mix(in srgb, var(--mat-sys-primary) 20%, transparent))}.mat-mdc-slider._mat-animation-noopable.mdc-slider--discrete .mdc-slider__thumb,.mat-mdc-slider._mat-animation-noopable.mdc-slider--discrete .mdc-slider__track--active_fill,.mat-mdc-slider._mat-animation-noopable .mdc-slider__value-indicator{transition:none}.mat-mdc-slider .mat-focus-indicator::before{border-radius:50%}.mdc-slider__thumb--focused .mat-focus-indicator::before{content:\"\"}\n"], dependencies: [{ kind: "component", type: MatSliderVisualThumb, selector: "mat-slider-visual-thumb", inputs: ["discrete", "thumbPosition", "valueIndicatorText"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
  985. }
  986. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatSlider, decorators: [{
  987. type: Component,
  988. args: [{ selector: 'mat-slider', host: {
  989. 'class': 'mat-mdc-slider mdc-slider',
  990. '[class]': '"mat-" + (color || "primary")',
  991. '[class.mdc-slider--range]': '_isRange',
  992. '[class.mdc-slider--disabled]': 'disabled',
  993. '[class.mdc-slider--discrete]': 'discrete',
  994. '[class.mdc-slider--tick-marks]': 'showTickMarks',
  995. '[class._mat-animation-noopable]': '_noopAnimations',
  996. }, exportAs: 'matSlider', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [{ provide: MAT_SLIDER, useExisting: MatSlider }], imports: [MatSliderVisualThumb], template: "<!-- Inputs -->\n<ng-content></ng-content>\n\n<!-- Track -->\n<div class=\"mdc-slider__track\">\n <div class=\"mdc-slider__track--inactive\"></div>\n <div class=\"mdc-slider__track--active\">\n <div #trackActive class=\"mdc-slider__track--active_fill\"></div>\n </div>\n @if (showTickMarks) {\n <div class=\"mdc-slider__tick-marks\" #tickMarkContainer>\n @if (_cachedWidth) {\n @for (tickMark of _tickMarks; track i; let i = $index) {\n <div\n [class]=\"tickMark === 0 ? 'mdc-slider__tick-mark--active' : 'mdc-slider__tick-mark--inactive'\"\n [style.transform]=\"_calcTickMarkTransform(i)\"></div>\n }\n }\n </div>\n }\n</div>\n\n<!-- Thumbs -->\n@if (_isRange) {\n <mat-slider-visual-thumb\n [discrete]=\"discrete\"\n [thumbPosition]=\"1\"\n [valueIndicatorText]=\"startValueIndicatorText\">\n </mat-slider-visual-thumb>\n}\n\n<mat-slider-visual-thumb\n [discrete]=\"discrete\"\n [thumbPosition]=\"2\"\n [valueIndicatorText]=\"endValueIndicatorText\">\n</mat-slider-visual-thumb>\n", styles: [".mdc-slider__track{position:absolute;top:50%;transform:translateY(-50%);width:100%;pointer-events:none;height:var(--mdc-slider-inactive-track-height, 4px)}.mdc-slider__track--active,.mdc-slider__track--inactive{display:flex;height:100%;position:absolute;width:100%}.mdc-slider__track--active{overflow:hidden;border-radius:var(--mdc-slider-active-track-shape, var(--mat-sys-corner-full));height:var(--mdc-slider-active-track-height, 4px);top:calc((var(--mdc-slider-inactive-track-height, 4px) - var(--mdc-slider-active-track-height, 4px))/2)}.mdc-slider__track--active_fill{border-top-style:solid;box-sizing:border-box;height:100%;width:100%;position:relative;transform-origin:left;transition:transform 80ms ease;border-color:var(--mdc-slider-active-track-color, var(--mat-sys-primary));border-top-width:var(--mdc-slider-active-track-height, 4px)}.mdc-slider--disabled .mdc-slider__track--active_fill{border-color:var(--mdc-slider-disabled-active-track-color, var(--mat-sys-on-surface))}[dir=rtl] .mdc-slider__track--active_fill{-webkit-transform-origin:right;transform-origin:right}.mdc-slider__track--inactive{left:0;top:0;opacity:.24;background-color:var(--mdc-slider-inactive-track-color, var(--mat-sys-surface-variant));height:var(--mdc-slider-inactive-track-height, 4px);border-radius:var(--mdc-slider-inactive-track-shape, var(--mat-sys-corner-full))}.mdc-slider--disabled .mdc-slider__track--inactive{background-color:var(--mdc-slider-disabled-inactive-track-color, var(--mat-sys-on-surface));opacity:.24}.mdc-slider__track--inactive::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid rgba(0,0,0,0);border-radius:inherit;content:\"\";pointer-events:none}@media(forced-colors: active){.mdc-slider__track--inactive::before{border-color:CanvasText}}.mdc-slider__value-indicator-container{bottom:44px;left:50%;pointer-events:none;position:absolute;transform:translateX(-50%);transform:var(--mat-slider-value-indicator-container-transform, translateX(-50%) rotate(-45deg))}.mdc-slider__thumb--with-indicator .mdc-slider__value-indicator-container{pointer-events:auto}.mdc-slider__value-indicator{display:flex;align-items:center;border-radius:4px;height:32px;padding:0 12px;transform:scale(0);transform-origin:bottom;opacity:1;transition:transform 100ms cubic-bezier(0.4, 0, 1, 1);word-break:normal;background-color:var(--mdc-slider-label-container-color, var(--mat-sys-primary));color:var(--mdc-slider-label-label-text-color, var(--mat-sys-on-primary));width:var(--mat-slider-value-indicator-width, 28px);height:var(--mat-slider-value-indicator-height, 28px);padding:var(--mat-slider-value-indicator-padding, 0);opacity:var(--mat-slider-value-indicator-opacity, 1);border-radius:var(--mat-slider-value-indicator-border-radius, 50% 50% 50% 0)}.mdc-slider__thumb--with-indicator .mdc-slider__value-indicator{transition:transform 100ms cubic-bezier(0, 0, 0.2, 1);transform:scale(1)}.mdc-slider__value-indicator::before{border-left:6px solid rgba(0,0,0,0);border-right:6px solid rgba(0,0,0,0);border-top:6px solid;bottom:-5px;content:\"\";height:0;left:50%;position:absolute;transform:translateX(-50%);width:0;display:var(--mat-slider-value-indicator-caret-display, none);border-top-color:var(--mdc-slider-label-container-color, var(--mat-sys-primary))}.mdc-slider__value-indicator::after{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid rgba(0,0,0,0);border-radius:inherit;content:\"\";pointer-events:none}@media(forced-colors: active){.mdc-slider__value-indicator::after{border-color:CanvasText}}.mdc-slider__value-indicator-text{text-align:center;width:var(--mat-slider-value-indicator-width, 28px);transform:var(--mat-slider-value-indicator-text-transform, rotate(45deg));font-family:var(--mdc-slider-label-label-text-font, var(--mat-sys-label-medium-font));font-size:var(--mdc-slider-label-label-text-size, var(--mat-sys-label-medium-size));font-weight:var(--mdc-slider-label-label-text-weight, var(--mat-sys-label-medium-weight));line-height:var(--mdc-slider-label-label-text-line-height, var(--mat-sys-label-medium-line-height));letter-spacing:var(--mdc-slider-label-label-text-tracking, var(--mat-sys-label-medium-tracking))}.mdc-slider__thumb{-webkit-user-select:none;user-select:none;display:flex;left:-24px;outline:none;position:absolute;height:48px;width:48px;pointer-events:none}.mdc-slider--discrete .mdc-slider__thumb{transition:transform 80ms ease}.mdc-slider--disabled .mdc-slider__thumb{pointer-events:none}.mdc-slider__thumb--top{z-index:1}.mdc-slider__thumb-knob{position:absolute;box-sizing:border-box;left:50%;top:50%;transform:translate(-50%, -50%);border-style:solid;width:var(--mdc-slider-handle-width, 20px);height:var(--mdc-slider-handle-height, 20px);border-width:calc(var(--mdc-slider-handle-height, 20px)/2) calc(var(--mdc-slider-handle-width, 20px)/2);box-shadow:var(--mdc-slider-handle-elevation, var(--mat-sys-level1));background-color:var(--mdc-slider-handle-color, var(--mat-sys-primary));border-color:var(--mdc-slider-handle-color, var(--mat-sys-primary));border-radius:var(--mdc-slider-handle-shape, var(--mat-sys-corner-full))}.mdc-slider__thumb:hover .mdc-slider__thumb-knob{background-color:var(--mdc-slider-hover-handle-color, var(--mat-sys-primary));border-color:var(--mdc-slider-hover-handle-color, var(--mat-sys-primary))}.mdc-slider__thumb--focused .mdc-slider__thumb-knob{background-color:var(--mdc-slider-focus-handle-color, var(--mat-sys-primary));border-color:var(--mdc-slider-focus-handle-color, var(--mat-sys-primary))}.mdc-slider--disabled .mdc-slider__thumb-knob{background-color:var(--mdc-slider-disabled-handle-color, var(--mat-sys-on-surface));border-color:var(--mdc-slider-disabled-handle-color, var(--mat-sys-on-surface))}.mdc-slider__thumb--top .mdc-slider__thumb-knob,.mdc-slider__thumb--top.mdc-slider__thumb:hover .mdc-slider__thumb-knob,.mdc-slider__thumb--top.mdc-slider__thumb--focused .mdc-slider__thumb-knob{border:solid 1px #fff;box-sizing:content-box;border-color:var(--mdc-slider-with-overlap-handle-outline-color, var(--mat-sys-on-primary));border-width:var(--mdc-slider-with-overlap-handle-outline-width, 1px)}.mdc-slider__tick-marks{align-items:center;box-sizing:border-box;display:flex;height:100%;justify-content:space-between;padding:0 1px;position:absolute;width:100%}.mdc-slider__tick-mark--active,.mdc-slider__tick-mark--inactive{width:var(--mdc-slider-with-tick-marks-container-size, 2px);height:var(--mdc-slider-with-tick-marks-container-size, 2px);border-radius:var(--mdc-slider-with-tick-marks-container-shape, var(--mat-sys-corner-full))}.mdc-slider__tick-mark--inactive{opacity:var(--mdc-slider-with-tick-marks-inactive-container-opacity, 0.38);background-color:var(--mdc-slider-with-tick-marks-inactive-container-color, var(--mat-sys-on-surface-variant))}.mdc-slider--disabled .mdc-slider__tick-mark--inactive{opacity:var(--mdc-slider-with-tick-marks-inactive-container-opacity, 0.38);background-color:var(--mdc-slider-with-tick-marks-disabled-container-color, var(--mat-sys-on-surface))}.mdc-slider__tick-mark--active{opacity:var(--mdc-slider-with-tick-marks-active-container-opacity, 0.38);background-color:var(--mdc-slider-with-tick-marks-active-container-color, var(--mat-sys-on-primary))}.mdc-slider__input{cursor:pointer;left:2px;margin:0;height:44px;opacity:0;position:absolute;top:2px;width:44px;box-sizing:content-box}.mdc-slider__input.mat-mdc-slider-input-no-pointer-events{pointer-events:none}.mdc-slider__input.mat-slider__right-input{left:auto;right:0}.mat-mdc-slider{display:inline-block;box-sizing:border-box;outline:none;vertical-align:middle;cursor:pointer;height:48px;margin:0 8px;position:relative;touch-action:pan-y;width:auto;min-width:112px;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mat-mdc-slider.mdc-slider--disabled{cursor:auto;opacity:.38}.mat-mdc-slider .mdc-slider__thumb,.mat-mdc-slider .mdc-slider__track--active_fill{transition-duration:0ms}.mat-mdc-slider.mat-mdc-slider-with-animation .mdc-slider__thumb,.mat-mdc-slider.mat-mdc-slider-with-animation .mdc-slider__track--active_fill{transition-duration:80ms}.mat-mdc-slider.mdc-slider--discrete .mdc-slider__thumb,.mat-mdc-slider.mdc-slider--discrete .mdc-slider__track--active_fill{transition-duration:0ms}.mat-mdc-slider.mat-mdc-slider-with-animation .mdc-slider__thumb,.mat-mdc-slider.mat-mdc-slider-with-animation .mdc-slider__track--active_fill{transition-duration:80ms}.mat-mdc-slider .mat-ripple .mat-ripple-element{background-color:var(--mat-slider-ripple-color, var(--mat-sys-primary))}.mat-mdc-slider .mat-ripple .mat-mdc-slider-hover-ripple{background-color:var(--mat-slider-hover-state-layer-color, color-mix(in srgb, var(--mat-sys-primary) 5%, transparent))}.mat-mdc-slider .mat-ripple .mat-mdc-slider-focus-ripple,.mat-mdc-slider .mat-ripple .mat-mdc-slider-active-ripple{background-color:var(--mat-slider-focus-state-layer-color, color-mix(in srgb, var(--mat-sys-primary) 20%, transparent))}.mat-mdc-slider._mat-animation-noopable.mdc-slider--discrete .mdc-slider__thumb,.mat-mdc-slider._mat-animation-noopable.mdc-slider--discrete .mdc-slider__track--active_fill,.mat-mdc-slider._mat-animation-noopable .mdc-slider__value-indicator{transition:none}.mat-mdc-slider .mat-focus-indicator::before{border-radius:50%}.mdc-slider__thumb--focused .mat-focus-indicator::before{content:\"\"}\n"] }]
  997. }], ctorParameters: () => [], propDecorators: { _trackActive: [{
  998. type: ViewChild,
  999. args: ['trackActive']
  1000. }], _thumbs: [{
  1001. type: ViewChildren,
  1002. args: [MAT_SLIDER_VISUAL_THUMB]
  1003. }], _input: [{
  1004. type: ContentChild,
  1005. args: [MAT_SLIDER_THUMB]
  1006. }], _inputs: [{
  1007. type: ContentChildren,
  1008. args: [MAT_SLIDER_RANGE_THUMB, { descendants: false }]
  1009. }], disabled: [{
  1010. type: Input,
  1011. args: [{ transform: booleanAttribute }]
  1012. }], discrete: [{
  1013. type: Input,
  1014. args: [{ transform: booleanAttribute }]
  1015. }], showTickMarks: [{
  1016. type: Input,
  1017. args: [{ transform: booleanAttribute }]
  1018. }], min: [{
  1019. type: Input,
  1020. args: [{ transform: numberAttribute }]
  1021. }], color: [{
  1022. type: Input
  1023. }], disableRipple: [{
  1024. type: Input,
  1025. args: [{ transform: booleanAttribute }]
  1026. }], max: [{
  1027. type: Input,
  1028. args: [{ transform: numberAttribute }]
  1029. }], step: [{
  1030. type: Input,
  1031. args: [{ transform: numberAttribute }]
  1032. }], displayWith: [{
  1033. type: Input
  1034. }] } });
  1035. /** Ensures that there is not an invalid configuration for the slider thumb inputs. */
  1036. function _validateInputs(isRange, endInputElement, startInputElement) {
  1037. const startValid = !isRange || startInputElement?._hostElement.hasAttribute('matSliderStartThumb');
  1038. const endValid = endInputElement?._hostElement.hasAttribute(isRange ? 'matSliderEndThumb' : 'matSliderThumb');
  1039. if (!startValid || !endValid) {
  1040. _throwInvalidInputConfigurationError();
  1041. }
  1042. }
  1043. function _throwInvalidInputConfigurationError() {
  1044. throw Error(`Invalid slider thumb input configuration!
  1045. Valid configurations are as follows:
  1046. <mat-slider>
  1047. <input matSliderThumb>
  1048. </mat-slider>
  1049. or
  1050. <mat-slider>
  1051. <input matSliderStartThumb>
  1052. <input matSliderEndThumb>
  1053. </mat-slider>
  1054. `);
  1055. }
  1056. /**
  1057. * Provider that allows the slider thumb to register as a ControlValueAccessor.
  1058. * @docs-private
  1059. */
  1060. const MAT_SLIDER_THUMB_VALUE_ACCESSOR = {
  1061. provide: NG_VALUE_ACCESSOR,
  1062. useExisting: forwardRef(() => MatSliderThumb),
  1063. multi: true,
  1064. };
  1065. /**
  1066. * Provider that allows the range slider thumb to register as a ControlValueAccessor.
  1067. * @docs-private
  1068. */
  1069. const MAT_SLIDER_RANGE_THUMB_VALUE_ACCESSOR = {
  1070. provide: NG_VALUE_ACCESSOR,
  1071. useExisting: forwardRef(() => MatSliderRangeThumb),
  1072. multi: true,
  1073. };
  1074. /**
  1075. * Directive that adds slider-specific behaviors to an input element inside `<mat-slider>`.
  1076. * Up to two may be placed inside of a `<mat-slider>`.
  1077. *
  1078. * If one is used, the selector `matSliderThumb` must be used, and the outcome will be a normal
  1079. * slider. If two are used, the selectors `matSliderStartThumb` and `matSliderEndThumb` must be
  1080. * used, and the outcome will be a range slider with two slider thumbs.
  1081. */
  1082. class MatSliderThumb {
  1083. _ngZone = inject(NgZone);
  1084. _elementRef = inject(ElementRef);
  1085. _cdr = inject(ChangeDetectorRef);
  1086. _slider = inject(MAT_SLIDER);
  1087. _platform = inject(Platform);
  1088. _listenerCleanups;
  1089. get value() {
  1090. return numberAttribute(this._hostElement.value, 0);
  1091. }
  1092. set value(value) {
  1093. value = isNaN(value) ? 0 : value;
  1094. const stringValue = value + '';
  1095. if (!this._hasSetInitialValue) {
  1096. this._initialValue = stringValue;
  1097. return;
  1098. }
  1099. if (this._isActive) {
  1100. return;
  1101. }
  1102. this._setValue(stringValue);
  1103. }
  1104. /**
  1105. * Handles programmatic value setting. This has been split out to
  1106. * allow the range thumb to override it and add additional necessary logic.
  1107. */
  1108. _setValue(value) {
  1109. this._hostElement.value = value;
  1110. this._updateThumbUIByValue();
  1111. this._slider._onValueChange(this);
  1112. this._cdr.detectChanges();
  1113. this._slider._cdr.markForCheck();
  1114. }
  1115. /** Event emitted when the `value` is changed. */
  1116. valueChange = new EventEmitter();
  1117. /** Event emitted when the slider thumb starts being dragged. */
  1118. dragStart = new EventEmitter();
  1119. /** Event emitted when the slider thumb stops being dragged. */
  1120. dragEnd = new EventEmitter();
  1121. /**
  1122. * The current translateX in px of the slider visual thumb.
  1123. * @docs-private
  1124. */
  1125. get translateX() {
  1126. if (this._slider.min >= this._slider.max) {
  1127. this._translateX = this._tickMarkOffset;
  1128. return this._translateX;
  1129. }
  1130. if (this._translateX === undefined) {
  1131. this._translateX = this._calcTranslateXByValue();
  1132. }
  1133. return this._translateX;
  1134. }
  1135. set translateX(v) {
  1136. this._translateX = v;
  1137. }
  1138. _translateX;
  1139. /**
  1140. * Indicates whether this thumb is the start or end thumb.
  1141. * @docs-private
  1142. */
  1143. thumbPosition = _MatThumb.END;
  1144. /** @docs-private */
  1145. get min() {
  1146. return numberAttribute(this._hostElement.min, 0);
  1147. }
  1148. set min(v) {
  1149. this._hostElement.min = v + '';
  1150. this._cdr.detectChanges();
  1151. }
  1152. /** @docs-private */
  1153. get max() {
  1154. return numberAttribute(this._hostElement.max, 0);
  1155. }
  1156. set max(v) {
  1157. this._hostElement.max = v + '';
  1158. this._cdr.detectChanges();
  1159. }
  1160. get step() {
  1161. return numberAttribute(this._hostElement.step, 0);
  1162. }
  1163. set step(v) {
  1164. this._hostElement.step = v + '';
  1165. this._cdr.detectChanges();
  1166. }
  1167. /** @docs-private */
  1168. get disabled() {
  1169. return booleanAttribute(this._hostElement.disabled);
  1170. }
  1171. set disabled(v) {
  1172. this._hostElement.disabled = v;
  1173. this._cdr.detectChanges();
  1174. if (this._slider.disabled !== this.disabled) {
  1175. this._slider.disabled = this.disabled;
  1176. }
  1177. }
  1178. /** The percentage of the slider that coincides with the value. */
  1179. get percentage() {
  1180. if (this._slider.min >= this._slider.max) {
  1181. return this._slider._isRtl ? 1 : 0;
  1182. }
  1183. return (this.value - this._slider.min) / (this._slider.max - this._slider.min);
  1184. }
  1185. /** @docs-private */
  1186. get fillPercentage() {
  1187. if (!this._slider._cachedWidth) {
  1188. return this._slider._isRtl ? 1 : 0;
  1189. }
  1190. if (this._translateX === 0) {
  1191. return 0;
  1192. }
  1193. return this.translateX / this._slider._cachedWidth;
  1194. }
  1195. /** The host native HTML input element. */
  1196. _hostElement = this._elementRef.nativeElement;
  1197. /** The aria-valuetext string representation of the input's value. */
  1198. _valuetext = signal('');
  1199. /** The radius of a native html slider's knob. */
  1200. _knobRadius = 8;
  1201. /** The distance in px from the start of the slider track to the first tick mark. */
  1202. _tickMarkOffset = 3;
  1203. /** Whether user's cursor is currently in a mouse down state on the input. */
  1204. _isActive = false;
  1205. /** Whether the input is currently focused (either by tab or after clicking). */
  1206. _isFocused = false;
  1207. /** Used to relay updates to _isFocused to the slider visual thumbs. */
  1208. _setIsFocused(v) {
  1209. this._isFocused = v;
  1210. }
  1211. /**
  1212. * Whether the initial value has been set.
  1213. * This exists because the initial value cannot be immediately set because the min and max
  1214. * must first be relayed from the parent MatSlider component, which can only happen later
  1215. * in the component lifecycle.
  1216. */
  1217. _hasSetInitialValue = false;
  1218. /** The stored initial value. */
  1219. _initialValue;
  1220. /** Defined when a user is using a form control to manage slider value & validation. */
  1221. _formControl;
  1222. /** Emits when the component is destroyed. */
  1223. _destroyed = new Subject();
  1224. /**
  1225. * Indicates whether UI updates should be skipped.
  1226. *
  1227. * This flag is used to avoid flickering
  1228. * when correcting values on pointer up/down.
  1229. */
  1230. _skipUIUpdate = false;
  1231. /** Callback called when the slider input value changes. */
  1232. _onChangeFn;
  1233. /** Callback called when the slider input has been touched. */
  1234. _onTouchedFn = () => { };
  1235. /**
  1236. * Whether the NgModel has been initialized.
  1237. *
  1238. * This flag is used to ignore ghost null calls to
  1239. * writeValue which can break slider initialization.
  1240. *
  1241. * See https://github.com/angular/angular/issues/14988.
  1242. */
  1243. _isControlInitialized = false;
  1244. constructor() {
  1245. const renderer = inject(Renderer2);
  1246. this._ngZone.runOutsideAngular(() => {
  1247. this._listenerCleanups = [
  1248. renderer.listen(this._hostElement, 'pointerdown', this._onPointerDown.bind(this)),
  1249. renderer.listen(this._hostElement, 'pointermove', this._onPointerMove.bind(this)),
  1250. renderer.listen(this._hostElement, 'pointerup', this._onPointerUp.bind(this)),
  1251. ];
  1252. });
  1253. }
  1254. ngOnDestroy() {
  1255. this._listenerCleanups.forEach(cleanup => cleanup());
  1256. this._destroyed.next();
  1257. this._destroyed.complete();
  1258. this.dragStart.complete();
  1259. this.dragEnd.complete();
  1260. }
  1261. /** @docs-private */
  1262. initProps() {
  1263. this._updateWidthInactive();
  1264. // If this or the parent slider is disabled, just make everything disabled.
  1265. if (this.disabled !== this._slider.disabled) {
  1266. // The MatSlider setter for disabled will relay this and disable both inputs.
  1267. this._slider.disabled = true;
  1268. }
  1269. this.step = this._slider.step;
  1270. this.min = this._slider.min;
  1271. this.max = this._slider.max;
  1272. this._initValue();
  1273. }
  1274. /** @docs-private */
  1275. initUI() {
  1276. this._updateThumbUIByValue();
  1277. }
  1278. _initValue() {
  1279. this._hasSetInitialValue = true;
  1280. if (this._initialValue === undefined) {
  1281. this.value = this._getDefaultValue();
  1282. }
  1283. else {
  1284. this._hostElement.value = this._initialValue;
  1285. this._updateThumbUIByValue();
  1286. this._slider._onValueChange(this);
  1287. this._cdr.detectChanges();
  1288. }
  1289. }
  1290. _getDefaultValue() {
  1291. return this.min;
  1292. }
  1293. _onBlur() {
  1294. this._setIsFocused(false);
  1295. this._onTouchedFn();
  1296. }
  1297. _onFocus() {
  1298. this._slider._setTransition(false);
  1299. this._slider._updateTrackUI(this);
  1300. this._setIsFocused(true);
  1301. }
  1302. _onChange() {
  1303. this.valueChange.emit(this.value);
  1304. // only used to handle the edge case where user
  1305. // mousedown on the slider then uses arrow keys.
  1306. if (this._isActive) {
  1307. this._updateThumbUIByValue({ withAnimation: true });
  1308. }
  1309. }
  1310. _onInput() {
  1311. this._onChangeFn?.(this.value);
  1312. // handles arrowing and updating the value when
  1313. // a step is defined.
  1314. if (this._slider.step || !this._isActive) {
  1315. this._updateThumbUIByValue({ withAnimation: true });
  1316. }
  1317. this._slider._onValueChange(this);
  1318. }
  1319. _onNgControlValueChange() {
  1320. // only used to handle when the value change
  1321. // originates outside of the slider.
  1322. if (!this._isActive || !this._isFocused) {
  1323. this._slider._onValueChange(this);
  1324. this._updateThumbUIByValue();
  1325. }
  1326. this._slider.disabled = this._formControl.disabled;
  1327. }
  1328. _onPointerDown(event) {
  1329. if (this.disabled || event.button !== 0) {
  1330. return;
  1331. }
  1332. // On IOS, dragging only works if the pointer down happens on the
  1333. // slider thumb and the slider does not receive focus from pointer events.
  1334. if (this._platform.IOS) {
  1335. const isCursorOnSliderThumb = this._slider._isCursorOnSliderThumb(event, this._slider._getThumb(this.thumbPosition)._hostElement.getBoundingClientRect());
  1336. this._isActive = isCursorOnSliderThumb;
  1337. this._updateWidthActive();
  1338. this._slider._updateDimensions();
  1339. return;
  1340. }
  1341. this._isActive = true;
  1342. this._setIsFocused(true);
  1343. this._updateWidthActive();
  1344. this._slider._updateDimensions();
  1345. // Does nothing if a step is defined because we
  1346. // want the value to snap to the values on input.
  1347. if (!this._slider.step) {
  1348. this._updateThumbUIByPointerEvent(event, { withAnimation: true });
  1349. }
  1350. if (!this.disabled) {
  1351. this._handleValueCorrection(event);
  1352. this.dragStart.emit({ source: this, parent: this._slider, value: this.value });
  1353. }
  1354. }
  1355. /**
  1356. * Corrects the value of the slider on pointer up/down.
  1357. *
  1358. * Called on pointer down and up because the value is set based
  1359. * on the inactive width instead of the active width.
  1360. */
  1361. _handleValueCorrection(event) {
  1362. // Don't update the UI with the current value! The value on pointerdown
  1363. // and pointerup is calculated in the split second before the input(s)
  1364. // resize. See _updateWidthInactive() and _updateWidthActive() for more
  1365. // details.
  1366. this._skipUIUpdate = true;
  1367. // Note that this function gets triggered before the actual value of the
  1368. // slider is updated. This means if we were to set the value here, it
  1369. // would immediately be overwritten. Using setTimeout ensures the setting
  1370. // of the value happens after the value has been updated by the
  1371. // pointerdown event.
  1372. setTimeout(() => {
  1373. this._skipUIUpdate = false;
  1374. this._fixValue(event);
  1375. }, 0);
  1376. }
  1377. /** Corrects the value of the slider based on the pointer event's position. */
  1378. _fixValue(event) {
  1379. const xPos = event.clientX - this._slider._cachedLeft;
  1380. const width = this._slider._cachedWidth;
  1381. const step = this._slider.step === 0 ? 1 : this._slider.step;
  1382. const numSteps = Math.floor((this._slider.max - this._slider.min) / step);
  1383. const percentage = this._slider._isRtl ? 1 - xPos / width : xPos / width;
  1384. // To ensure the percentage is rounded to the necessary number of decimals.
  1385. const fixedPercentage = Math.round(percentage * numSteps) / numSteps;
  1386. const impreciseValue = fixedPercentage * (this._slider.max - this._slider.min) + this._slider.min;
  1387. const value = Math.round(impreciseValue / step) * step;
  1388. const prevValue = this.value;
  1389. if (value === prevValue) {
  1390. // Because we prevented UI updates, if it turns out that the race
  1391. // condition didn't happen and the value is already correct, we
  1392. // have to apply the ui updates now.
  1393. this._slider._onValueChange(this);
  1394. this._slider.step > 0
  1395. ? this._updateThumbUIByValue()
  1396. : this._updateThumbUIByPointerEvent(event, { withAnimation: this._slider._hasAnimation });
  1397. return;
  1398. }
  1399. this.value = value;
  1400. this.valueChange.emit(this.value);
  1401. this._onChangeFn?.(this.value);
  1402. this._slider._onValueChange(this);
  1403. this._slider.step > 0
  1404. ? this._updateThumbUIByValue()
  1405. : this._updateThumbUIByPointerEvent(event, { withAnimation: this._slider._hasAnimation });
  1406. }
  1407. _onPointerMove(event) {
  1408. // Again, does nothing if a step is defined because
  1409. // we want the value to snap to the values on input.
  1410. if (!this._slider.step && this._isActive) {
  1411. this._updateThumbUIByPointerEvent(event);
  1412. }
  1413. }
  1414. _onPointerUp() {
  1415. if (this._isActive) {
  1416. this._isActive = false;
  1417. if (this._platform.SAFARI) {
  1418. this._setIsFocused(false);
  1419. }
  1420. this.dragEnd.emit({ source: this, parent: this._slider, value: this.value });
  1421. // This setTimeout is to prevent the pointerup from triggering a value
  1422. // change on the input based on the inactive width. It's not clear why
  1423. // but for some reason on IOS this race condition is even more common so
  1424. // the timeout needs to be increased.
  1425. setTimeout(() => this._updateWidthInactive(), this._platform.IOS ? 10 : 0);
  1426. }
  1427. }
  1428. _clamp(v) {
  1429. const min = this._tickMarkOffset;
  1430. const max = this._slider._cachedWidth - this._tickMarkOffset;
  1431. return Math.max(Math.min(v, max), min);
  1432. }
  1433. _calcTranslateXByValue() {
  1434. if (this._slider._isRtl) {
  1435. return ((1 - this.percentage) * (this._slider._cachedWidth - this._tickMarkOffset * 2) +
  1436. this._tickMarkOffset);
  1437. }
  1438. return (this.percentage * (this._slider._cachedWidth - this._tickMarkOffset * 2) +
  1439. this._tickMarkOffset);
  1440. }
  1441. _calcTranslateXByPointerEvent(event) {
  1442. return event.clientX - this._slider._cachedLeft;
  1443. }
  1444. /**
  1445. * Used to set the slider width to the correct
  1446. * dimensions while the user is dragging.
  1447. */
  1448. _updateWidthActive() { }
  1449. /**
  1450. * Sets the slider input to disproportionate dimensions to allow for touch
  1451. * events to be captured on touch devices.
  1452. */
  1453. _updateWidthInactive() {
  1454. this._hostElement.style.padding = `0 ${this._slider._inputPadding}px`;
  1455. this._hostElement.style.width = `calc(100% + ${this._slider._inputPadding - this._tickMarkOffset * 2}px)`;
  1456. this._hostElement.style.left = `-${this._slider._rippleRadius - this._tickMarkOffset}px`;
  1457. }
  1458. _updateThumbUIByValue(options) {
  1459. this.translateX = this._clamp(this._calcTranslateXByValue());
  1460. this._updateThumbUI(options);
  1461. }
  1462. _updateThumbUIByPointerEvent(event, options) {
  1463. this.translateX = this._clamp(this._calcTranslateXByPointerEvent(event));
  1464. this._updateThumbUI(options);
  1465. }
  1466. _updateThumbUI(options) {
  1467. this._slider._setTransition(!!options?.withAnimation);
  1468. this._slider._onTranslateXChange(this);
  1469. }
  1470. /**
  1471. * Sets the input's value.
  1472. * @param value The new value of the input
  1473. * @docs-private
  1474. */
  1475. writeValue(value) {
  1476. if (this._isControlInitialized || value !== null) {
  1477. this.value = value;
  1478. }
  1479. }
  1480. /**
  1481. * Registers a callback to be invoked when the input's value changes from user input.
  1482. * @param fn The callback to register
  1483. * @docs-private
  1484. */
  1485. registerOnChange(fn) {
  1486. this._onChangeFn = fn;
  1487. this._isControlInitialized = true;
  1488. }
  1489. /**
  1490. * Registers a callback to be invoked when the input is blurred by the user.
  1491. * @param fn The callback to register
  1492. * @docs-private
  1493. */
  1494. registerOnTouched(fn) {
  1495. this._onTouchedFn = fn;
  1496. }
  1497. /**
  1498. * Sets the disabled state of the slider.
  1499. * @param isDisabled The new disabled state
  1500. * @docs-private
  1501. */
  1502. setDisabledState(isDisabled) {
  1503. this.disabled = isDisabled;
  1504. }
  1505. focus() {
  1506. this._hostElement.focus();
  1507. }
  1508. blur() {
  1509. this._hostElement.blur();
  1510. }
  1511. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatSliderThumb, deps: [], target: i0.ɵɵFactoryTarget.Directive });
  1512. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "19.2.6", type: MatSliderThumb, isStandalone: true, selector: "input[matSliderThumb]", inputs: { value: ["value", "value", numberAttribute] }, outputs: { valueChange: "valueChange", dragStart: "dragStart", dragEnd: "dragEnd" }, host: { attributes: { "type": "range" }, listeners: { "change": "_onChange()", "input": "_onInput()", "blur": "_onBlur()", "focus": "_onFocus()" }, properties: { "attr.aria-valuetext": "_valuetext()" }, classAttribute: "mdc-slider__input" }, providers: [
  1513. MAT_SLIDER_THUMB_VALUE_ACCESSOR,
  1514. { provide: MAT_SLIDER_THUMB, useExisting: MatSliderThumb },
  1515. ], exportAs: ["matSliderThumb"], ngImport: i0 });
  1516. }
  1517. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatSliderThumb, decorators: [{
  1518. type: Directive,
  1519. args: [{
  1520. selector: 'input[matSliderThumb]',
  1521. exportAs: 'matSliderThumb',
  1522. host: {
  1523. 'class': 'mdc-slider__input',
  1524. 'type': 'range',
  1525. '[attr.aria-valuetext]': '_valuetext()',
  1526. '(change)': '_onChange()',
  1527. '(input)': '_onInput()',
  1528. // TODO(wagnermaciel): Consider using a global event listener instead.
  1529. // Reason: I have found a semi-consistent way to mouse up without triggering this event.
  1530. '(blur)': '_onBlur()',
  1531. '(focus)': '_onFocus()',
  1532. },
  1533. providers: [
  1534. MAT_SLIDER_THUMB_VALUE_ACCESSOR,
  1535. { provide: MAT_SLIDER_THUMB, useExisting: MatSliderThumb },
  1536. ],
  1537. }]
  1538. }], ctorParameters: () => [], propDecorators: { value: [{
  1539. type: Input,
  1540. args: [{ transform: numberAttribute }]
  1541. }], valueChange: [{
  1542. type: Output
  1543. }], dragStart: [{
  1544. type: Output
  1545. }], dragEnd: [{
  1546. type: Output
  1547. }] } });
  1548. class MatSliderRangeThumb extends MatSliderThumb {
  1549. _cdr = inject(ChangeDetectorRef);
  1550. /** @docs-private */
  1551. getSibling() {
  1552. if (!this._sibling) {
  1553. this._sibling = this._slider._getInput(this._isEndThumb ? _MatThumb.START : _MatThumb.END);
  1554. }
  1555. return this._sibling;
  1556. }
  1557. _sibling;
  1558. /**
  1559. * Returns the minimum translateX position allowed for this slider input's visual thumb.
  1560. * @docs-private
  1561. */
  1562. getMinPos() {
  1563. const sibling = this.getSibling();
  1564. if (!this._isLeftThumb && sibling) {
  1565. return sibling.translateX;
  1566. }
  1567. return this._tickMarkOffset;
  1568. }
  1569. /**
  1570. * Returns the maximum translateX position allowed for this slider input's visual thumb.
  1571. * @docs-private
  1572. */
  1573. getMaxPos() {
  1574. const sibling = this.getSibling();
  1575. if (this._isLeftThumb && sibling) {
  1576. return sibling.translateX;
  1577. }
  1578. return this._slider._cachedWidth - this._tickMarkOffset;
  1579. }
  1580. _setIsLeftThumb() {
  1581. this._isLeftThumb =
  1582. (this._isEndThumb && this._slider._isRtl) || (!this._isEndThumb && !this._slider._isRtl);
  1583. }
  1584. /** Whether this slider corresponds to the input on the left hand side. */
  1585. _isLeftThumb;
  1586. /** Whether this slider corresponds to the input with greater value. */
  1587. _isEndThumb;
  1588. constructor() {
  1589. super();
  1590. this._isEndThumb = this._hostElement.hasAttribute('matSliderEndThumb');
  1591. this._setIsLeftThumb();
  1592. this.thumbPosition = this._isEndThumb ? _MatThumb.END : _MatThumb.START;
  1593. }
  1594. _getDefaultValue() {
  1595. return this._isEndThumb && this._slider._isRange ? this.max : this.min;
  1596. }
  1597. _onInput() {
  1598. super._onInput();
  1599. this._updateSibling();
  1600. if (!this._isActive) {
  1601. this._updateWidthInactive();
  1602. }
  1603. }
  1604. _onNgControlValueChange() {
  1605. super._onNgControlValueChange();
  1606. this.getSibling()?._updateMinMax();
  1607. }
  1608. _onPointerDown(event) {
  1609. if (this.disabled || event.button !== 0) {
  1610. return;
  1611. }
  1612. if (this._sibling) {
  1613. this._sibling._updateWidthActive();
  1614. this._sibling._hostElement.classList.add('mat-mdc-slider-input-no-pointer-events');
  1615. }
  1616. super._onPointerDown(event);
  1617. }
  1618. _onPointerUp() {
  1619. super._onPointerUp();
  1620. if (this._sibling) {
  1621. setTimeout(() => {
  1622. this._sibling._updateWidthInactive();
  1623. this._sibling._hostElement.classList.remove('mat-mdc-slider-input-no-pointer-events');
  1624. });
  1625. }
  1626. }
  1627. _onPointerMove(event) {
  1628. super._onPointerMove(event);
  1629. if (!this._slider.step && this._isActive) {
  1630. this._updateSibling();
  1631. }
  1632. }
  1633. _fixValue(event) {
  1634. super._fixValue(event);
  1635. this._sibling?._updateMinMax();
  1636. }
  1637. _clamp(v) {
  1638. return Math.max(Math.min(v, this.getMaxPos()), this.getMinPos());
  1639. }
  1640. _updateMinMax() {
  1641. const sibling = this.getSibling();
  1642. if (!sibling) {
  1643. return;
  1644. }
  1645. if (this._isEndThumb) {
  1646. this.min = Math.max(this._slider.min, sibling.value);
  1647. this.max = this._slider.max;
  1648. }
  1649. else {
  1650. this.min = this._slider.min;
  1651. this.max = Math.min(this._slider.max, sibling.value);
  1652. }
  1653. }
  1654. _updateWidthActive() {
  1655. const minWidth = this._slider._rippleRadius * 2 - this._slider._inputPadding * 2;
  1656. const maxWidth = this._slider._cachedWidth + this._slider._inputPadding - minWidth - this._tickMarkOffset * 2;
  1657. const percentage = this._slider.min < this._slider.max
  1658. ? (this.max - this.min) / (this._slider.max - this._slider.min)
  1659. : 1;
  1660. const width = maxWidth * percentage + minWidth;
  1661. this._hostElement.style.width = `${width}px`;
  1662. this._hostElement.style.padding = `0 ${this._slider._inputPadding}px`;
  1663. }
  1664. _updateWidthInactive() {
  1665. const sibling = this.getSibling();
  1666. if (!sibling) {
  1667. return;
  1668. }
  1669. const maxWidth = this._slider._cachedWidth - this._tickMarkOffset * 2;
  1670. const midValue = this._isEndThumb
  1671. ? this.value - (this.value - sibling.value) / 2
  1672. : this.value + (sibling.value - this.value) / 2;
  1673. const _percentage = this._isEndThumb
  1674. ? (this.max - midValue) / (this._slider.max - this._slider.min)
  1675. : (midValue - this.min) / (this._slider.max - this._slider.min);
  1676. const percentage = this._slider.min < this._slider.max ? _percentage : 1;
  1677. // Extend the native input width by the radius of the ripple
  1678. let ripplePadding = this._slider._rippleRadius;
  1679. // If one of the inputs is maximally sized (the value of both thumbs is
  1680. // equal to the min or max), make that input take up all of the width and
  1681. // make the other unselectable.
  1682. if (percentage === 1) {
  1683. ripplePadding = 48;
  1684. }
  1685. else if (percentage === 0) {
  1686. ripplePadding = 0;
  1687. }
  1688. const width = maxWidth * percentage + ripplePadding;
  1689. this._hostElement.style.width = `${width}px`;
  1690. this._hostElement.style.padding = '0px';
  1691. if (this._isLeftThumb) {
  1692. this._hostElement.style.left = `-${this._slider._rippleRadius - this._tickMarkOffset}px`;
  1693. this._hostElement.style.right = 'auto';
  1694. }
  1695. else {
  1696. this._hostElement.style.left = 'auto';
  1697. this._hostElement.style.right = `-${this._slider._rippleRadius - this._tickMarkOffset}px`;
  1698. }
  1699. }
  1700. _updateStaticStyles() {
  1701. this._hostElement.classList.toggle('mat-slider__right-input', !this._isLeftThumb);
  1702. }
  1703. _updateSibling() {
  1704. const sibling = this.getSibling();
  1705. if (!sibling) {
  1706. return;
  1707. }
  1708. sibling._updateMinMax();
  1709. if (this._isActive) {
  1710. sibling._updateWidthActive();
  1711. }
  1712. else {
  1713. sibling._updateWidthInactive();
  1714. }
  1715. }
  1716. /**
  1717. * Sets the input's value.
  1718. * @param value The new value of the input
  1719. * @docs-private
  1720. */
  1721. writeValue(value) {
  1722. if (this._isControlInitialized || value !== null) {
  1723. this.value = value;
  1724. this._updateWidthInactive();
  1725. this._updateSibling();
  1726. }
  1727. }
  1728. _setValue(value) {
  1729. super._setValue(value);
  1730. this._updateWidthInactive();
  1731. this._updateSibling();
  1732. }
  1733. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatSliderRangeThumb, deps: [], target: i0.ɵɵFactoryTarget.Directive });
  1734. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.6", type: MatSliderRangeThumb, isStandalone: true, selector: "input[matSliderStartThumb], input[matSliderEndThumb]", providers: [
  1735. MAT_SLIDER_RANGE_THUMB_VALUE_ACCESSOR,
  1736. { provide: MAT_SLIDER_RANGE_THUMB, useExisting: MatSliderRangeThumb },
  1737. ], exportAs: ["matSliderRangeThumb"], usesInheritance: true, ngImport: i0 });
  1738. }
  1739. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatSliderRangeThumb, decorators: [{
  1740. type: Directive,
  1741. args: [{
  1742. selector: 'input[matSliderStartThumb], input[matSliderEndThumb]',
  1743. exportAs: 'matSliderRangeThumb',
  1744. providers: [
  1745. MAT_SLIDER_RANGE_THUMB_VALUE_ACCESSOR,
  1746. { provide: MAT_SLIDER_RANGE_THUMB, useExisting: MatSliderRangeThumb },
  1747. ],
  1748. }]
  1749. }], ctorParameters: () => [] });
  1750. class MatSliderModule {
  1751. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatSliderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
  1752. static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.6", ngImport: i0, type: MatSliderModule, imports: [MatCommonModule,
  1753. MatRippleModule,
  1754. MatSlider,
  1755. MatSliderThumb,
  1756. MatSliderRangeThumb,
  1757. MatSliderVisualThumb], exports: [MatSlider, MatSliderThumb, MatSliderRangeThumb] });
  1758. static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatSliderModule, imports: [MatCommonModule,
  1759. MatRippleModule] });
  1760. }
  1761. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatSliderModule, decorators: [{
  1762. type: NgModule,
  1763. args: [{
  1764. imports: [
  1765. MatCommonModule,
  1766. MatRippleModule,
  1767. MatSlider,
  1768. MatSliderThumb,
  1769. MatSliderRangeThumb,
  1770. MatSliderVisualThumb,
  1771. ],
  1772. exports: [MatSlider, MatSliderThumb, MatSliderRangeThumb],
  1773. }]
  1774. }] });
  1775. export { MatSlider, MatSliderChange, MatSliderModule, MatSliderRangeThumb, MatSliderThumb, MatSliderVisualThumb };
  1776. //# sourceMappingURL=slider.mjs.map