Add restoreScroll decorator (#6289)

This commit is contained in:
Bram Kragten 2020-07-01 11:04:17 +02:00 committed by GitHub
parent 4bfc3a5629
commit b881adb853
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 69 additions and 26 deletions

View 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];
}
};
},
});
};

View File

@ -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 */

View File

@ -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`

View File

@ -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(
( (

View File

@ -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;