mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 11:16:35 +00:00
Add restoreScroll decorator (#6289)
This commit is contained in:
parent
4bfc3a5629
commit
b881adb853
33
src/common/decorators/restore-scroll.ts
Normal file
33
src/common/decorators/restore-scroll.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import type { LitElement } from "lit-element";
|
||||
import type { ClassElement } from "../../types";
|
||||
|
||||
export const restoreScroll = (selector: string): any => {
|
||||
return (element: ClassElement) => ({
|
||||
kind: "method",
|
||||
placement: "prototype",
|
||||
key: element.key,
|
||||
descriptor: {
|
||||
set(this: LitElement, value: number) {
|
||||
this[`__${String(element.key)}`] = value;
|
||||
},
|
||||
get(this: LitElement) {
|
||||
return this[`__${String(element.key)}`];
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
},
|
||||
finisher(cls: typeof LitElement) {
|
||||
const connectedCallback = cls.prototype.connectedCallback;
|
||||
cls.prototype.connectedCallback = function () {
|
||||
connectedCallback.call(this);
|
||||
if (this[element.key]) {
|
||||
const target = this.renderRoot.querySelector(selector);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
target.scrollTop = this[element.key];
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
@ -9,6 +9,8 @@ import {
|
||||
PropertyValues,
|
||||
query,
|
||||
TemplateResult,
|
||||
eventOptions,
|
||||
internalProperty,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
@ -23,6 +25,7 @@ import type { HaCheckbox } from "../ha-checkbox";
|
||||
import "../ha-icon";
|
||||
import { filterData, sortData } from "./sort-filter";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { restoreScroll } from "../../common/decorators/restore-scroll";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
@ -96,15 +99,15 @@ export class HaDataTable extends LitElement {
|
||||
|
||||
@property({ type: String }) public filter = "";
|
||||
|
||||
@property({ type: Boolean }) private _filterable = false;
|
||||
@internalProperty() private _filterable = false;
|
||||
|
||||
@property({ type: String }) private _filter = "";
|
||||
@internalProperty() private _filter = "";
|
||||
|
||||
@property({ type: String }) private _sortColumn?: string;
|
||||
@internalProperty() private _sortColumn?: string;
|
||||
|
||||
@property({ type: String }) private _sortDirection: SortingDirection = null;
|
||||
@internalProperty() private _sortDirection: SortingDirection = null;
|
||||
|
||||
@property({ type: Array }) private _filteredData: DataTableRowData[] = [];
|
||||
@internalProperty() private _filteredData: DataTableRowData[] = [];
|
||||
|
||||
@query("slot[name='header']") private _header!: HTMLSlotElement;
|
||||
|
||||
@ -118,6 +121,9 @@ export class HaDataTable extends LitElement {
|
||||
|
||||
private curRequest = 0;
|
||||
|
||||
// @ts-ignore
|
||||
@restoreScroll(".scroller") private _savedScrollPos?: number;
|
||||
|
||||
private _debounceSearch = debounce(
|
||||
(value: string) => {
|
||||
this._filter = value;
|
||||
@ -286,7 +292,10 @@ export class HaDataTable extends LitElement {
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="mdc-data-table__content scroller">
|
||||
<div
|
||||
class="mdc-data-table__content scroller"
|
||||
@scroll=${this._saveScrollPos}
|
||||
>
|
||||
${scroll({
|
||||
items: !this.hasFab
|
||||
? this._filteredData
|
||||
@ -499,6 +508,11 @@ export class HaDataTable extends LitElement {
|
||||
this._table.style.height = `calc(100% - ${this._header.clientHeight}px)`;
|
||||
}
|
||||
|
||||
@eventOptions({ passive: true })
|
||||
private _saveScrollPos(e: Event) {
|
||||
this._savedScrollPos = (e.target as HTMLDivElement).scrollTop;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
/* default mdc styles, colors changed, without checkbox styles */
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import "../components/ha-menu-button";
|
||||
import "../components/ha-icon-button-arrow-prev";
|
||||
import { restoreScroll } from "../common/decorators/restore-scroll";
|
||||
|
||||
@customElement("hass-subpage")
|
||||
class HassSubpage extends LitElement {
|
||||
@ -23,16 +24,8 @@ class HassSubpage extends LitElement {
|
||||
@property({ type: Boolean })
|
||||
public hassio = false;
|
||||
|
||||
@property() private _savedScrollPos?: number;
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
if (this._savedScrollPos) {
|
||||
(this.shadowRoot!.querySelector(
|
||||
".content"
|
||||
) as HTMLDivElement).scrollTop = this._savedScrollPos;
|
||||
}
|
||||
}
|
||||
// @ts-ignore
|
||||
@restoreScroll(".content") private _savedScrollPos?: number;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
|
@ -20,6 +20,7 @@ import { HomeAssistant, Route } from "../types";
|
||||
import "../components/ha-svg-icon";
|
||||
import "../components/ha-icon";
|
||||
import "../components/ha-tab";
|
||||
import { restoreScroll } from "../common/decorators/restore-scroll";
|
||||
|
||||
export interface PageNavigation {
|
||||
path: string;
|
||||
@ -53,16 +54,8 @@ class HassTabsSubpage extends LitElement {
|
||||
|
||||
@property() private _activeTab?: PageNavigation;
|
||||
|
||||
@property() private _savedScrollPos?: number;
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
if (this._savedScrollPos) {
|
||||
(this.shadowRoot!.querySelector(
|
||||
".content"
|
||||
) as HTMLDivElement).scrollTop = this._savedScrollPos;
|
||||
}
|
||||
}
|
||||
// @ts-ignore
|
||||
@restoreScroll(".content") private _savedScrollPos?: number;
|
||||
|
||||
private _getTabs = memoizeOne(
|
||||
(
|
||||
|
10
src/types.ts
10
src/types.ts
@ -47,6 +47,16 @@ declare global {
|
||||
|
||||
export type Constructor<T = {}> = new (...args: any[]) => T;
|
||||
|
||||
export interface ClassElement {
|
||||
kind: "field" | "method";
|
||||
key: PropertyKey;
|
||||
placement: "static" | "prototype" | "own";
|
||||
initializer?: Function;
|
||||
extras?: ClassElement[];
|
||||
finisher?: <T>(cls: Constructor<T>) => undefined | Constructor<T>;
|
||||
descriptor?: PropertyDescriptor;
|
||||
}
|
||||
|
||||
export interface WebhookError {
|
||||
code: number;
|
||||
message: string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user