mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 19:26:36 +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,
|
PropertyValues,
|
||||||
query,
|
query,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
|
eventOptions,
|
||||||
|
internalProperty,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { classMap } from "lit-html/directives/class-map";
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
@ -23,6 +25,7 @@ import type { HaCheckbox } from "../ha-checkbox";
|
|||||||
import "../ha-icon";
|
import "../ha-icon";
|
||||||
import { filterData, sortData } from "./sort-filter";
|
import { filterData, sortData } from "./sort-filter";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
|
import { restoreScroll } from "../../common/decorators/restore-scroll";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// for fire event
|
// for fire event
|
||||||
@ -96,15 +99,15 @@ export class HaDataTable extends LitElement {
|
|||||||
|
|
||||||
@property({ type: String }) public filter = "";
|
@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;
|
@query("slot[name='header']") private _header!: HTMLSlotElement;
|
||||||
|
|
||||||
@ -118,6 +121,9 @@ export class HaDataTable extends LitElement {
|
|||||||
|
|
||||||
private curRequest = 0;
|
private curRequest = 0;
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
@restoreScroll(".scroller") private _savedScrollPos?: number;
|
||||||
|
|
||||||
private _debounceSearch = debounce(
|
private _debounceSearch = debounce(
|
||||||
(value: string) => {
|
(value: string) => {
|
||||||
this._filter = value;
|
this._filter = value;
|
||||||
@ -286,7 +292,10 @@ export class HaDataTable extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<div class="mdc-data-table__content scroller">
|
<div
|
||||||
|
class="mdc-data-table__content scroller"
|
||||||
|
@scroll=${this._saveScrollPos}
|
||||||
|
>
|
||||||
${scroll({
|
${scroll({
|
||||||
items: !this.hasFab
|
items: !this.hasFab
|
||||||
? this._filteredData
|
? this._filteredData
|
||||||
@ -499,6 +508,11 @@ export class HaDataTable extends LitElement {
|
|||||||
this._table.style.height = `calc(100% - ${this._header.clientHeight}px)`;
|
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 {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
/* default mdc styles, colors changed, without checkbox styles */
|
/* default mdc styles, colors changed, without checkbox styles */
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
import { classMap } from "lit-html/directives/class-map";
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
import "../components/ha-menu-button";
|
import "../components/ha-menu-button";
|
||||||
import "../components/ha-icon-button-arrow-prev";
|
import "../components/ha-icon-button-arrow-prev";
|
||||||
|
import { restoreScroll } from "../common/decorators/restore-scroll";
|
||||||
|
|
||||||
@customElement("hass-subpage")
|
@customElement("hass-subpage")
|
||||||
class HassSubpage extends LitElement {
|
class HassSubpage extends LitElement {
|
||||||
@ -23,16 +24,8 @@ class HassSubpage extends LitElement {
|
|||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
public hassio = false;
|
public hassio = false;
|
||||||
|
|
||||||
@property() private _savedScrollPos?: number;
|
// @ts-ignore
|
||||||
|
@restoreScroll(".content") private _savedScrollPos?: number;
|
||||||
public connectedCallback() {
|
|
||||||
super.connectedCallback();
|
|
||||||
if (this._savedScrollPos) {
|
|
||||||
(this.shadowRoot!.querySelector(
|
|
||||||
".content"
|
|
||||||
) as HTMLDivElement).scrollTop = this._savedScrollPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
|
@ -20,6 +20,7 @@ import { HomeAssistant, Route } from "../types";
|
|||||||
import "../components/ha-svg-icon";
|
import "../components/ha-svg-icon";
|
||||||
import "../components/ha-icon";
|
import "../components/ha-icon";
|
||||||
import "../components/ha-tab";
|
import "../components/ha-tab";
|
||||||
|
import { restoreScroll } from "../common/decorators/restore-scroll";
|
||||||
|
|
||||||
export interface PageNavigation {
|
export interface PageNavigation {
|
||||||
path: string;
|
path: string;
|
||||||
@ -53,16 +54,8 @@ class HassTabsSubpage extends LitElement {
|
|||||||
|
|
||||||
@property() private _activeTab?: PageNavigation;
|
@property() private _activeTab?: PageNavigation;
|
||||||
|
|
||||||
@property() private _savedScrollPos?: number;
|
// @ts-ignore
|
||||||
|
@restoreScroll(".content") private _savedScrollPos?: number;
|
||||||
public connectedCallback() {
|
|
||||||
super.connectedCallback();
|
|
||||||
if (this._savedScrollPos) {
|
|
||||||
(this.shadowRoot!.querySelector(
|
|
||||||
".content"
|
|
||||||
) as HTMLDivElement).scrollTop = this._savedScrollPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _getTabs = memoizeOne(
|
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 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 {
|
export interface WebhookError {
|
||||||
code: number;
|
code: number;
|
||||||
message: string;
|
message: string;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user