Add scroll restoration when using back navigation in dashboard (#24822)

Add scroll restoration when using back navigation with subviews
This commit is contained in:
Paul Bottein 2025-03-28 12:07:42 +01:00 committed by Bram Kragten
parent 8751dc46f4
commit 909fc119b7

View File

@ -99,6 +99,10 @@ class HUIRoot extends LitElement {
private _viewCache?: Record<string, HUIView>;
private _viewScrollPositions: Record<string, number> = {};
private _restoreScroll = false;
private _debouncedConfigChanged: () => void;
private _conversation = memoizeOne((_components) =>
@ -485,6 +489,10 @@ class HUIRoot extends LitElement {
this.toggleAttribute("scrolled", window.scrollY !== 0);
};
private _handlePopState = () => {
this._restoreScroll = true;
};
private _isVisible = (view: LovelaceViewConfig) =>
Boolean(
this._editMode ||
@ -525,11 +533,18 @@ class HUIRoot extends LitElement {
window.addEventListener("scroll", this._handleWindowScroll, {
passive: true,
});
window.addEventListener("popstate", this._handlePopState);
// Disable history scroll restoration because it is managed manually here
window.history.scrollRestoration = "manual";
}
public disconnectedCallback(): void {
super.disconnectedCallback();
window.removeEventListener("scroll", this._handleWindowScroll);
window.removeEventListener("popstate", this._handlePopState);
this.toggleAttribute("scrolled", window.scrollY !== 0);
// Re-enable history scroll restoration when leaving the page
window.history.scrollRestoration = "auto";
}
protected updated(changedProperties: PropertyValues): void {
@ -572,9 +587,6 @@ class HUIRoot extends LitElement {
}
newSelectView = index;
}
// Will allow to override history scroll restoration when using back button
setTimeout(() => scrollTo({ behavior: "auto", top: 0 }), 1);
}
if (changedProperties.has("lovelace")) {
@ -613,7 +625,18 @@ class HUIRoot extends LitElement {
newSelectView = this._curView;
}
// Will allow for ripples to start rendering
afterNextRender(() => this._selectView(newSelectView, force));
afterNextRender(() => {
if (changedProperties.has("route")) {
const position =
(this._restoreScroll && this._viewScrollPositions[newSelectView]) ||
0;
this._restoreScroll = false;
requestAnimationFrame(() =>
scrollTo({ behavior: "auto", top: position })
);
}
this._selectView(newSelectView, force);
});
}
}
@ -926,12 +949,18 @@ class HUIRoot extends LitElement {
return;
}
// Save scroll position of current view
if (this._curView != null) {
this._viewScrollPositions[this._curView] = window.scrollY;
}
viewIndex = viewIndex === undefined ? 0 : viewIndex;
this._curView = viewIndex;
if (force) {
this._viewCache = {};
this._viewScrollPositions = {};
}
// Recreate a new element to clear the applied themes.