Skip to content

Commit

Permalink
fix(material-experimental/mdc-slider): thumb incorrectly positioned w…
Browse files Browse the repository at this point in the history
…hen inside an overlay (#25288)

Fixes an issue where the thumb of an MDC slider wasn't positioned correctly when it has an initial value inside an overlay that is being animated.

There are multiple ways to resolve this, but I ended up doing it by removing our logic that skips the first `ResizeObserver` emission since we can get around the performance issues with the `layout` call by reusing the dimensions provided in the callback.

Fixes #25286.
  • Loading branch information
crisbeto authored Jul 15, 2022
1 parent 2bdcd92 commit fb4d7a0
Showing 1 changed file with 20 additions and 12 deletions.
32 changes: 20 additions & 12 deletions src/material-experimental/mdc-slider/slider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,9 @@ export class MatSlider
/** Timeout used to debounce resize listeners. */
private _resizeTimer: number;

/** Cached dimensions of the host element. */
private _cachedHostRect: DOMRect | null;

constructor(
readonly _ngZone: NgZone,
readonly _cdr: ChangeDetectorRef,
Expand Down Expand Up @@ -941,6 +944,11 @@ export class MatSlider
return this.disabled || this.disableRipple || !!this._globalRippleOptions?.disabled;
}

/** Gets the dimensions of the host element. */
_getHostDimensions() {
return this._cachedHostRect || this._elementRef.nativeElement.getBoundingClientRect();
}

/** Starts observing and updating the slider if the host changes its size. */
private _observeHostResize() {
if (typeof ResizeObserver === 'undefined' || !ResizeObserver) {
Expand All @@ -949,18 +957,18 @@ export class MatSlider

// MDC only updates the slider when the window is resized which
// doesn't capture changes of the container itself. We use a resize
// observer to ensure that the layout is correct (see #24590).
// observer to ensure that the layout is correct (see #24590 and #25286).
this._ngZone.runOutsideAngular(() => {
// The callback will fire as soon as an element is observed and
// we only want to know after the initial layout.
let hasResized = false;
this._resizeObserver = new ResizeObserver(() => {
if (hasResized) {
// Debounce the layouts since they can happen frequently.
clearTimeout(this._resizeTimer);
this._resizeTimer = setTimeout(this._layout, 50);
}
hasResized = true;
this._resizeObserver = new ResizeObserver(entries => {
clearTimeout(this._resizeTimer);
this._resizeTimer = setTimeout(() => {
// The `layout` call is going to call `getBoundingClientRect` to update the dimensions
// of the host. Since the `ResizeObserver` already calculated them, we can save some
// work by returning them instead of having to check the DOM again.
this._cachedHostRect = entries[0]?.contentRect;
this._layout();
this._cachedHostRect = null;
}, 50);
});
this._resizeObserver.observe(this._elementRef.nativeElement);
});
Expand Down Expand Up @@ -1130,7 +1138,7 @@ class SliderAdapter implements MDCSliderAdapter {
return this._delegate._getThumbElement(thumbPosition).getBoundingClientRect();
};
getBoundingClientRect = (): DOMRect => {
return this._delegate._elementRef.nativeElement.getBoundingClientRect();
return this._delegate._getHostDimensions();
};
getValueIndicatorContainerWidth = (thumbPosition: Thumb): number => {
return this._delegate._getValueIndicatorContainerElement(thumbPosition).getBoundingClientRect()
Expand Down

0 comments on commit fb4d7a0

Please sign in to comment.