mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-03 09:24:04 +00:00
Compare commits
1 Commits
keyboard-i
...
keyboard-i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b869bdecd7 |
@@ -38,14 +38,6 @@ export interface HASSDomEvent<T> extends Event {
|
||||
detail: T;
|
||||
}
|
||||
|
||||
export type HASSDomTargetEvent<T extends EventTarget> = Event & {
|
||||
target: T;
|
||||
};
|
||||
|
||||
export type HASSDomCurrentTargetEvent<T extends EventTarget> = Event & {
|
||||
currentTarget: T;
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches a custom event with an optional detail value.
|
||||
*
|
||||
|
||||
@@ -17,10 +17,6 @@ import memoizeOne from "memoize-one";
|
||||
import { STRINGS_SEPARATOR_DOT } from "../../common/const";
|
||||
import { restoreScroll } from "../../common/decorators/restore-scroll";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import type {
|
||||
HASSDomCurrentTargetEvent,
|
||||
HASSDomTargetEvent,
|
||||
} from "../../common/dom/fire_event";
|
||||
import { stringCompare } from "../../common/string/compare";
|
||||
import type { LocalizeFunc } from "../../common/translations/localize";
|
||||
import { debounce } from "../../common/util/debounce";
|
||||
@@ -107,7 +103,6 @@ export interface DataTableRowData {
|
||||
export type SortableColumnContainer = Record<string, ClonedDataTableColumnData>;
|
||||
|
||||
const UNDEFINED_GROUP_KEY = "zzzzz_undefined";
|
||||
const AUTO_FOCUS_ALLOWED_ACTIVE_TAGS = ["BODY", "HTML", "HOME-ASSISTANT"];
|
||||
|
||||
@customElement("ha-data-table")
|
||||
export class HaDataTable extends LitElement {
|
||||
@@ -171,10 +166,6 @@ export class HaDataTable extends LitElement {
|
||||
|
||||
@query("slot[name='header']") private _header!: HTMLSlotElement;
|
||||
|
||||
@query(".mdc-data-table__header-row") private _headerRow?: HTMLDivElement;
|
||||
|
||||
@query("lit-virtualizer") private _scroller?: HTMLElement;
|
||||
|
||||
@state() private _collapsedGroups: string[] = [];
|
||||
|
||||
@state() private _lastSelectedRowId: string | null = null;
|
||||
@@ -189,8 +180,6 @@ export class HaDataTable extends LitElement {
|
||||
|
||||
private _lastUpdate = 0;
|
||||
|
||||
private _didAutoFocusScroller = false;
|
||||
|
||||
// @ts-ignore
|
||||
@restoreScroll(".scroller") private _savedScrollPos?: number;
|
||||
|
||||
@@ -253,26 +242,16 @@ export class HaDataTable extends LitElement {
|
||||
this.updateComplete.then(() => this._calcTableHeight());
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
if (!this._headerRow) {
|
||||
protected updated() {
|
||||
const header = this.renderRoot.querySelector(".mdc-data-table__header-row");
|
||||
if (!header) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._headerRow.scrollWidth > this._headerRow.clientWidth) {
|
||||
this.style.setProperty(
|
||||
"--table-row-width",
|
||||
`${this._headerRow.scrollWidth}px`
|
||||
);
|
||||
if (header.scrollWidth > header.clientWidth) {
|
||||
this.style.setProperty("--table-row-width", `${header.scrollWidth}px`);
|
||||
} else {
|
||||
this.style.removeProperty("--table-row-width");
|
||||
}
|
||||
|
||||
this._focusTableOnLoad();
|
||||
|
||||
// Refocus on toggle checkbox changes
|
||||
if (changedProps.has("selectable")) {
|
||||
this._focusScroller();
|
||||
}
|
||||
}
|
||||
|
||||
public willUpdate(properties: PropertyValues) {
|
||||
@@ -538,7 +517,6 @@ export class HaDataTable extends LitElement {
|
||||
<lit-virtualizer
|
||||
scroller
|
||||
class="mdc-data-table__content scroller ha-scrollbar"
|
||||
tabindex=${ifDefined(!this.autoHeight ? "0" : undefined)}
|
||||
@scroll=${this._saveScrollPos}
|
||||
.items=${this._groupData(
|
||||
this._filteredData,
|
||||
@@ -851,10 +829,8 @@ export class HaDataTable extends LitElement {
|
||||
): Promise<DataTableRowData[]> => filterData(data, columns, filter)
|
||||
);
|
||||
|
||||
private _handleHeaderClick(
|
||||
ev: HASSDomCurrentTargetEvent<HTMLElement & { columnId: string }>
|
||||
) {
|
||||
const columnId = ev.currentTarget.columnId;
|
||||
private _handleHeaderClick(ev: Event) {
|
||||
const columnId = (ev.currentTarget as any).columnId;
|
||||
if (!this.columns[columnId].sortable) {
|
||||
return;
|
||||
}
|
||||
@@ -872,12 +848,11 @@ export class HaDataTable extends LitElement {
|
||||
column: columnId,
|
||||
direction: this.sortDirection,
|
||||
});
|
||||
|
||||
this._focusScroller();
|
||||
}
|
||||
|
||||
private _handleHeaderRowCheckboxClick(ev: HASSDomTargetEvent<HaCheckbox>) {
|
||||
if (ev.target.checked) {
|
||||
private _handleHeaderRowCheckboxClick(ev: Event) {
|
||||
const checkbox = ev.target as HaCheckbox;
|
||||
if (checkbox.checked) {
|
||||
this.selectAll();
|
||||
} else {
|
||||
this._checkedRows = [];
|
||||
@@ -886,10 +861,9 @@ export class HaDataTable extends LitElement {
|
||||
this._lastSelectedRowId = null;
|
||||
}
|
||||
|
||||
private _handleRowCheckboxClicked = (
|
||||
ev: HASSDomCurrentTargetEvent<HaCheckbox & { rowId: string }>
|
||||
) => {
|
||||
const rowId = ev.currentTarget.rowId;
|
||||
private _handleRowCheckboxClicked = (ev: Event) => {
|
||||
const checkbox = ev.currentTarget as HaCheckbox;
|
||||
const rowId = (checkbox as any).rowId;
|
||||
|
||||
const groupedData = this._groupData(
|
||||
this._filteredData,
|
||||
@@ -926,7 +900,7 @@ export class HaDataTable extends LitElement {
|
||||
...this._selectRange(groupedData, lastSelectedRowIndex, rowIndex),
|
||||
];
|
||||
}
|
||||
} else if (!ev.currentTarget.checked) {
|
||||
} else if (!checkbox.checked) {
|
||||
if (!this._checkedRows.includes(rowId)) {
|
||||
this._checkedRows = [...this._checkedRows, rowId];
|
||||
}
|
||||
@@ -964,9 +938,7 @@ export class HaDataTable extends LitElement {
|
||||
return checkedRows;
|
||||
}
|
||||
|
||||
private _handleRowClick = (
|
||||
ev: HASSDomCurrentTargetEvent<HTMLElement & { rowId: string }>
|
||||
) => {
|
||||
private _handleRowClick = (ev: Event) => {
|
||||
if (
|
||||
ev
|
||||
.composedPath()
|
||||
@@ -982,13 +954,14 @@ export class HaDataTable extends LitElement {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const rowId = ev.currentTarget.rowId;
|
||||
const rowId = (ev.currentTarget as any).rowId;
|
||||
fireEvent(this, "row-click", { id: rowId }, { bubbles: false });
|
||||
};
|
||||
|
||||
private _setTitle(ev: HASSDomCurrentTargetEvent<HTMLElement>) {
|
||||
if (ev.currentTarget.scrollWidth > ev.currentTarget.offsetWidth) {
|
||||
ev.currentTarget.setAttribute("title", ev.currentTarget.innerText);
|
||||
private _setTitle(ev: Event) {
|
||||
const target = ev.currentTarget as HTMLElement;
|
||||
if (target.scrollWidth > target.offsetWidth) {
|
||||
target.setAttribute("title", target.innerText);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1010,27 +983,6 @@ export class HaDataTable extends LitElement {
|
||||
this._debounceSearch((ev.target as HTMLInputElement).value);
|
||||
}
|
||||
|
||||
private _focusTableOnLoad() {
|
||||
if (
|
||||
this._didAutoFocusScroller ||
|
||||
this.autoHeight ||
|
||||
(document.activeElement &&
|
||||
!AUTO_FOCUS_ALLOWED_ACTIVE_TAGS.includes(
|
||||
document.activeElement.tagName
|
||||
))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._focusScroller();
|
||||
}
|
||||
|
||||
private _focusScroller(): void {
|
||||
this._scroller?.focus({
|
||||
preventScroll: true,
|
||||
});
|
||||
}
|
||||
|
||||
private async _calcTableHeight() {
|
||||
if (this.autoHeight) {
|
||||
return;
|
||||
@@ -1040,27 +992,23 @@ export class HaDataTable extends LitElement {
|
||||
}
|
||||
|
||||
@eventOptions({ passive: true })
|
||||
private _saveScrollPos(e: HASSDomTargetEvent<HTMLDivElement>) {
|
||||
this._savedScrollPos = e.target.scrollTop;
|
||||
private _saveScrollPos(e: Event) {
|
||||
this._savedScrollPos = (e.target as HTMLDivElement).scrollTop;
|
||||
|
||||
if (this._headerRow) {
|
||||
this._headerRow.scrollLeft = e.target.scrollLeft;
|
||||
}
|
||||
this.renderRoot.querySelector(".mdc-data-table__header-row")!.scrollLeft = (
|
||||
e.target as HTMLDivElement
|
||||
).scrollLeft;
|
||||
}
|
||||
|
||||
@eventOptions({ passive: true })
|
||||
private _scrollContent(e: HASSDomTargetEvent<HTMLDivElement>) {
|
||||
if (!this._scroller) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._scroller.scrollLeft = e.target.scrollLeft;
|
||||
private _scrollContent(e: Event) {
|
||||
this.renderRoot.querySelector("lit-virtualizer")!.scrollLeft = (
|
||||
e.target as HTMLDivElement
|
||||
).scrollLeft;
|
||||
}
|
||||
|
||||
private _collapseGroup = (
|
||||
ev: HASSDomCurrentTargetEvent<HTMLElement & { group: string }>
|
||||
) => {
|
||||
const groupName = ev.currentTarget.group;
|
||||
private _collapseGroup = (ev: Event) => {
|
||||
const groupName = (ev.currentTarget as any).group;
|
||||
if (this._collapsedGroups.includes(groupName)) {
|
||||
this._collapsedGroups = this._collapsedGroups.filter(
|
||||
(grp) => grp !== groupName
|
||||
@@ -1483,11 +1431,6 @@ export class HaDataTable extends LitElement {
|
||||
contain: size layout !important;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
lit-virtualizer:focus,
|
||||
lit-virtualizer:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, eventOptions, property, state } from "lit/decorators";
|
||||
import {
|
||||
customElement,
|
||||
eventOptions,
|
||||
property,
|
||||
query,
|
||||
state,
|
||||
} from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { canShowPage } from "../common/config/can_show_page";
|
||||
@@ -75,6 +81,8 @@ export class HassTabsSubpage extends LitElement {
|
||||
|
||||
@state() private _activeTab?: PageNavigation;
|
||||
|
||||
@query(".content") private _content?: HTMLDivElement;
|
||||
|
||||
// @ts-ignore
|
||||
@restoreScroll(".content") private _savedScrollPos?: number;
|
||||
|
||||
@@ -211,6 +219,15 @@ export class HassTabsSubpage extends LitElement {
|
||||
this._savedScrollPos = (e.target as HTMLDivElement).scrollTop;
|
||||
}
|
||||
|
||||
public focusContentScroller() {
|
||||
if (!this._content) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._content.style.outline = "none";
|
||||
this._content.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
private _backTapped(): void {
|
||||
if (this.backCallback) {
|
||||
this.backCallback();
|
||||
|
||||
@@ -55,6 +55,7 @@ import {
|
||||
import type { ImprovDiscoveredDevice } from "../../../external_app/external_messaging";
|
||||
import "../../../layouts/hass-loading-screen";
|
||||
import "../../../layouts/hass-tabs-subpage";
|
||||
import type { HassTabsSubpage } from "../../../layouts/hass-tabs-subpage";
|
||||
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
@@ -170,6 +171,8 @@ class HaConfigIntegrationsDashboard extends KeyboardShortcutMixin(
|
||||
|
||||
@query("ha-input-search") private _searchInput!: HaInputSearch;
|
||||
|
||||
@query("hass-tabs-subpage") private _tabsSubpage?: HassTabsSubpage;
|
||||
|
||||
public disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
window.removeEventListener(
|
||||
@@ -424,6 +427,10 @@ class HaConfigIntegrationsDashboard extends KeyboardShortcutMixin(
|
||||
this.configEntries.map((entry) => entry.domain)
|
||||
);
|
||||
}
|
||||
|
||||
if (this.configEntries && this.configEntriesInProgress) {
|
||||
this._tabsSubpage?.focusContentScroller();
|
||||
}
|
||||
}
|
||||
|
||||
protected render() {
|
||||
|
||||
Reference in New Issue
Block a user