Skip to content

fix(material-experimental/mdc-slider): thumb incorrectly positioned when inside an overlay #25288

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 15, 2022
Merged
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
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.
Copy link
Member

@devversion devversion Jul 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional nit:

Suggested change
// work by returning them instead of having to check the DOM again.
// work by caching them instead of having to check the DOM again.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caching isn't permanent though. It gets reset after the layout call.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I just wasn't sure where you "returned" it, but the comment makes sense regardless.

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