Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion goldens/material/slider/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { NgZone } from '@angular/core';
import { OnDestroy } from '@angular/core';
import { OnInit } from '@angular/core';
import { QueryList } from '@angular/core';
import { Signal } from '@angular/core';
import { Subject } from 'rxjs';
import { WritableSignal } from '@angular/core';

Expand Down Expand Up @@ -56,7 +57,7 @@ export class MatSlider implements AfterViewInit, OnDestroy, _MatSlider {
_isCursorOnSliderThumb(event: PointerEvent, rect: DOMRect): boolean;
// (undocumented)
_isRange: boolean;
_isRtl: boolean;
_isRtl: i0.Signal<boolean>;
_knobRadius: number;
get max(): number;
set max(v: number);
Expand Down
10 changes: 5 additions & 5 deletions src/material/slider/slider-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,15 @@ export class MatSliderThumb implements _MatSliderThumb, OnDestroy, ControlValueA
/** The percentage of the slider that coincides with the value. */
get percentage(): number {
if (this._slider.min >= this._slider.max) {
return this._slider._isRtl ? 1 : 0;
return this._slider._isRtl() ? 1 : 0;
}
return (this.value - this._slider.min) / (this._slider.max - this._slider.min);
}

/** @docs-private */
get fillPercentage(): number {
if (!this._slider._cachedWidth) {
return this._slider._isRtl ? 1 : 0;
return this._slider._isRtl() ? 1 : 0;
}
if (this._translateX === 0) {
return 0;
Expand Down Expand Up @@ -446,7 +446,7 @@ export class MatSliderThumb implements _MatSliderThumb, OnDestroy, ControlValueA
const width = this._slider._cachedWidth;
const step = this._slider.step === 0 ? 1 : this._slider.step;
const numSteps = Math.floor((this._slider.max - this._slider.min) / step);
const percentage = this._slider._isRtl ? 1 - xPos / width : xPos / width;
const percentage = this._slider._isRtl() ? 1 - xPos / width : xPos / width;

// To ensure the percentage is rounded to the necessary number of decimals.
const fixedPercentage = Math.round(percentage * numSteps) / numSteps;
Expand Down Expand Up @@ -507,7 +507,7 @@ export class MatSliderThumb implements _MatSliderThumb, OnDestroy, ControlValueA
}

_calcTranslateXByValue(): number {
if (this._slider._isRtl) {
if (this._slider._isRtl()) {
return (
(1 - this.percentage) * (this._slider._cachedWidth - this._tickMarkOffset * 2) +
this._tickMarkOffset
Expand Down Expand Up @@ -652,7 +652,7 @@ export class MatSliderRangeThumb extends MatSliderThumb implements _MatSliderRan

_setIsLeftThumb(): void {
this._isLeftThumb =
(this._isEndThumb && this._slider._isRtl) || (!this._isEndThumb && !this._slider._isRtl);
(this._isEndThumb && this._slider._isRtl()) || (!this._isEndThumb && !this._slider._isRtl());
}

/** Whether this slider corresponds to the input on the left hand side. */
Expand Down
4 changes: 2 additions & 2 deletions src/material/slider/slider-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {InjectionToken, ChangeDetectorRef, WritableSignal} from '@angular/core';
import {InjectionToken, ChangeDetectorRef, WritableSignal, Signal} from '@angular/core';
import {MatRipple, RippleGlobalOptions} from '../core';

/**
Expand Down Expand Up @@ -107,7 +107,7 @@ export interface _MatSlider {
_isRange: boolean;

/** Whether the slider is rtl. */
_isRtl: boolean;
_isRtl: Signal<boolean>;

/** The stored width of the host element's bounding client rect. */
_cachedWidth: number;
Expand Down
39 changes: 19 additions & 20 deletions src/material/slider/slider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
import {Directionality} from '@angular/cdk/bidi';
import {Platform} from '@angular/cdk/platform';
import {
afterRenderEffect,
AfterViewInit,
booleanAttribute,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
computed,
ContentChild,
ContentChildren,
ElementRef,
Expand All @@ -34,7 +36,6 @@ import {
RippleGlobalOptions,
ThemePalette,
} from '../core';
import {Subscription} from 'rxjs';
import {
_MatThumb,
_MatTickMark,
Expand Down Expand Up @@ -372,9 +373,6 @@ export class MatSlider implements AfterViewInit, OnDestroy, _MatSlider {
/** Whether animations have been disabled. */
_noopAnimations = _animationsDisabled();

/** Subscription to changes to the directionality (LTR / RTL) context for the application. */
private _dirChangeSubscription: Subscription | undefined;

/** Observer used to monitor size changes in the slider. */
private _resizeObserver: ResizeObserver | null = null;

Expand All @@ -401,7 +399,7 @@ export class MatSlider implements AfterViewInit, OnDestroy, _MatSlider {
_isRange: boolean = false;

/** Whether the slider is rtl. */
_isRtl: boolean = false;
_isRtl = computed(() => this._dir?.valueSignal() === 'rtl');

private _hasViewInitialized: boolean = false;

Expand All @@ -422,10 +420,19 @@ export class MatSlider implements AfterViewInit, OnDestroy, _MatSlider {
constructor() {
inject(_CdkPrivateStyleLoader).load(_StructuralStylesLoader);

if (this._dir) {
this._dirChangeSubscription = this._dir.change.subscribe(() => this._onDirChange());
this._isRtl = this._dir.value === 'rtl';
}
let prevIsRtl = this._isRtl();

afterRenderEffect(() => {
const isRtl = this._isRtl();

// The diffing is normally handled by the signal, but we don't want to
// fire on the first run, because it'll trigger unnecessary measurements.
if (isRtl !== prevIsRtl) {
prevIsRtl = isRtl;
this._isRange ? this._onDirChangeRange() : this._onDirChangeNonRange();
this._updateTickMarkUI();
}
});
}

/** The radius of the native slider's knob. AFAIK there is no way to avoid hardcoding this. */
Expand Down Expand Up @@ -499,18 +506,10 @@ export class MatSlider implements AfterViewInit, OnDestroy, _MatSlider {
}

ngOnDestroy(): void {
this._dirChangeSubscription?.unsubscribe();
this._resizeObserver?.disconnect();
this._resizeObserver = null;
}

/** Handles updating the slider ui after a dir change. */
private _onDirChange(): void {
this._isRtl = this._dir?.value === 'rtl';
this._isRange ? this._onDirChangeRange() : this._onDirChangeNonRange();
this._updateTickMarkUI();
}

private _onDirChangeRange(): void {
const endInput = this._getInput(_MatThumb.END) as _MatSliderRangeThumb;
const startInput = this._getInput(_MatThumb.START) as _MatSliderRangeThumb;
Expand Down Expand Up @@ -600,7 +599,7 @@ export class MatSlider implements AfterViewInit, OnDestroy, _MatSlider {
_calcTickMarkTransform(index: number): string {
// TODO(wagnermaciel): See if we can avoid doing this and just using flex to position these.
const offset = index * (this._tickMarkTrackWidth / (this._tickMarks.length - 1));
const translateX = this._isRtl ? this._cachedWidth - 6 - offset : offset;
const translateX = this._isRtl() ? this._cachedWidth - 6 - offset : offset;
return `translateX(${translateX}px)`;
}

Expand Down Expand Up @@ -852,7 +851,7 @@ export class MatSlider implements AfterViewInit, OnDestroy, _MatSlider {
}

private _updateTrackUINonRange(source: _MatSliderThumb): void {
this._isRtl
this._isRtl()
? this._setTrackActiveStyles({
left: 'auto',
right: '0px',
Expand Down Expand Up @@ -893,7 +892,7 @@ export class MatSlider implements AfterViewInit, OnDestroy, _MatSlider {
const value = this._getValue();
let numActive = Math.max(Math.round((value - this.min) / step), 0) + 1;
let numInactive = Math.max(Math.round((this.max - value) / step), 0) - 1;
this._isRtl ? numActive++ : numInactive++;
this._isRtl() ? numActive++ : numInactive++;

this._tickMarks = Array(numActive)
.fill(_MatTickMark.ACTIVE)
Expand Down
Loading