diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 5b39a0f8e8..38ea992b8e 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -99,6 +99,10 @@ class HUIRoot extends LitElement { private _viewCache?: Record; + private _viewScrollPositions: Record = {}; + + 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.