Use SWC for typescript, update to Lit 3, migrate decorators (#25150)

Co-authored-by: Wendelin <w@pe8.at>
pull/25157/head
Bram Kragten 2025-04-24 14:10:35 +02:00 committed by GitHub
parent c40bf8f3cd
commit e156dd36f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
241 changed files with 1676 additions and 1388 deletions

View File

@ -0,0 +1,22 @@
diff --git a/mwc-formfield-base.js b/mwc-formfield-base.js
index 7b763326d7d51835ad52646bfbc80fe21989abd3..f2baa8224e6d03df1fdb0b9fd03f5c6d77fc8747 100644
--- a/mwc-formfield-base.js
+++ b/mwc-formfield-base.js
@@ -9,7 +9,7 @@ import { BaseElement } from '@material/mwc-base/base-element.js';
import { FormElement } from '@material/mwc-base/form-element.js';
import { observer } from '@material/mwc-base/observer.js';
import { html } from 'lit';
-import { property, query, queryAssignedNodes } from 'lit/decorators.js';
+import { property, query, queryAssignedElements } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
export class FormfieldBase extends BaseElement {
constructor() {
@@ -96,7 +96,7 @@ __decorate([
query('.mdc-form-field')
], FormfieldBase.prototype, "mdcRoot", void 0);
__decorate([
- queryAssignedNodes('', true, '*')
+ queryAssignedElements({ slot: "", flatten: true, selector: "*" })
], FormfieldBase.prototype, "slottedInputs", void 0);
__decorate([
query('label')

View File

@ -0,0 +1,26 @@
diff --git a/mwc-list-base.js b/mwc-list-base.js
index 1ba95b6a01dcecea4d85b5cbbbcc3dfb04c40d5f..dced13fdb7929c490d6661b1bbe7e9f96dcd2285 100644
--- a/mwc-list-base.js
+++ b/mwc-list-base.js
@@ -11,7 +11,7 @@ import { BaseElement } from '@material/mwc-base/base-element.js';
import { observer } from '@material/mwc-base/observer.js';
import { deepActiveElementPath, doesElementContainFocus, isNodeElement } from '@material/mwc-base/utils.js';
import { html } from 'lit';
-import { property, query, queryAssignedNodes } from 'lit/decorators.js';
+import { property, query, queryAssignedElements } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import MDCListFoundation, { isIndexSet } from './mwc-list-foundation.js';
export { createSetFromIndex, isEventMulti, isIndexSet } from './mwc-list-foundation.js';
@@ -425,10 +425,10 @@ __decorate([
query('.mdc-deprecated-list')
], ListBase.prototype, "mdcRoot", void 0);
__decorate([
- queryAssignedNodes('', true, '*')
+ queryAssignedElements({ flatten: true, selector: "*" })
], ListBase.prototype, "assignedElements", void 0);
__decorate([
- queryAssignedNodes('', true, '[tabindex="0"]')
+ queryAssignedElements({ flatten: true, selector: '[tabindex="0"]' })
], ListBase.prototype, "tabbableElements", void 0);
__decorate([
property({ type: Boolean }),

View File

@ -73,6 +73,19 @@ module.exports.terserOptions = ({ latestBuild, isTestBuild }) => ({
sourceMap: !isTestBuild,
});
/** @type {import('@rspack/core').SwcLoaderOptions} */
module.exports.swcOptions = ({ latestBuild }) => ({
jsc: {
loose: true,
externalHelpers: true,
target: latestBuild ? "ES2021" : "ES5",
parser: {
syntax: "typescript",
decorators: true,
},
},
});
module.exports.babelOptions = ({
latestBuild,
isProdBuild,
@ -97,7 +110,6 @@ module.exports.babelOptions = ({
shippedProposals: true,
},
],
"@babel/preset-typescript",
],
plugins: [
[
@ -134,12 +146,6 @@ module.exports.babelOptions = ({
"@babel/plugin-transform-runtime",
{ version: dependencies["@babel/runtime"] },
],
// Transpile decorators (still in TC39 process)
// Modern browsers support class fields and private methods, but transform is required with the older decorator version dictated by Lit
[
"@babel/plugin-proposal-decorators",
{ version: "2018-09", decoratorsBeforeExport: true },
],
"@babel/plugin-transform-class-properties",
"@babel/plugin-transform-private-methods",
].filter(Boolean),

View File

@ -16,6 +16,7 @@ const detailsClose = "</details>\n";
const dummyAPI = {
version: babelVersion,
// eslint-disable-next-line @typescript-eslint/no-empty-function
assertVersion: () => {},
caller: (callback) =>
callback({

View File

@ -65,19 +65,28 @@ const createRspackConfig = ({
rules: [
{
test: /\.m?js$|\.ts$/,
use: (info) => ({
loader: "babel-loader",
options: {
...bundle.babelOptions({
latestBuild,
isProdBuild,
isTestBuild,
sw: info.issuerLayer === "sw",
}),
cacheDirectory: !isProdBuild,
cacheCompression: false,
exclude: /node_modules[\\/]core-js/,
use: (info) => [
{
loader: "babel-loader",
options: {
...bundle.babelOptions({
latestBuild,
isProdBuild,
isTestBuild,
sw: info.issuerLayer === "sw",
}),
cacheDirectory: !isProdBuild,
cacheCompression: false,
},
},
}),
{
loader: "builtin:swc-loader",
options: bundle.swcOptions({
latestBuild,
}),
},
],
resolve: {
fullySpecified: false,
},
@ -136,7 +145,8 @@ const createRspackConfig = ({
// calling define.amd will call require("!!webpack amd options")
resource.startsWith("!!webpack") ||
// loaded by webpack dev server but doesn't exist.
resource === "webpack/hot"
resource === "webpack/hot" ||
resource.startsWith("@swc/helpers")
) {
return false;
}

View File

@ -1,5 +1,5 @@
import "@material/mwc-button/mwc-button";
import "@material/mwc-list/mwc-list";
import type { ActionDetail } from "@material/mwc-list/mwc-list";
import { mdiCast, mdiCastConnected, mdiViewDashboard } from "@mdi/js";
import type { Auth, Connection } from "home-assistant-js-websocket";
@ -19,6 +19,8 @@ import {
import { atLeastVersion } from "../../../../src/common/config/version";
import { toggleAttribute } from "../../../../src/common/dom/toggle_attribute";
import "../../../../src/components/ha-icon";
import "../../../../src/components/ha-list";
import "../../../../src/components/ha-list-item";
import "../../../../src/components/ha-svg-icon";
import {
getLegacyLovelaceCollection,
@ -29,7 +31,6 @@ import type { LovelaceViewConfig } from "../../../../src/data/lovelace/config/vi
import "../../../../src/layouts/hass-loading-screen";
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
import "./hc-layout";
import "../../../../src/components/ha-list-item";
@customElement("hc-cast")
class HcCast extends LitElement {
@ -85,7 +86,7 @@ class HcCast extends LitElement {
`
: html`
<div class="section-header">PICK A VIEW</div>
<mwc-list @action=${this._handlePickView} activatable>
<ha-list @action=${this._handlePickView} activatable>
${(
this.lovelaceViews ?? [
generateDefaultViewConfig({}, {}, {}, {}, () => ""),
@ -113,7 +114,7 @@ class HcCast extends LitElement {
></ha-svg-icon>`}
</ha-list-item>
`
)}</mwc-list
)}</ha-list
>
`}

View File

@ -1,29 +1,30 @@
import type { TemplateResult } from "lit";
import { LitElement, html, css } from "lit";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-formfield";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import type { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockAreaRegistry } from "../../../../demo/src/stubs/area_registry";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
import type { Action } from "../../../../src/data/script";
import "../../../../src/panels/config/automation/action/ha-automation-action";
import { HaChooseAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-choose";
import { HaConditionAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-condition";
import { HaDelayAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-delay";
import { HaDeviceAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-device_id";
import { HaEventAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-event";
import { HaIfAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-if";
import { HaParallelAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-parallel";
import { HaPlayMediaAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-play_media";
import { HaRepeatAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-repeat";
import { HaSequenceAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-sequence";
import { HaServiceAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-service";
import { HaStopAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-stop";
import { HaWaitForTriggerAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-wait_for_trigger";
import { HaWaitAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-wait_template";
import type { Action } from "../../../../src/data/script";
import { HaConditionAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-condition";
import { HaSequenceAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-sequence";
import { HaParallelAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-parallel";
import { HaIfAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-if";
import { HaStopAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-stop";
import { HaPlayMediaAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-play_media";
const SCHEMAS: { name: string; actions: Action[] }[] = [
{ name: "Event", actions: [HaEventAction.defaultConfig] },

View File

@ -1,26 +1,27 @@
import type { TemplateResult } from "lit";
import { LitElement, html, css } from "lit";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import type { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockAreaRegistry } from "../../../../demo/src/stubs/area_registry";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
import "../../../../src/components/ha-formfield";
import type { ConditionWithShorthand } from "../../../../src/data/automation";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import "../../../../src/panels/config/automation/condition/ha-automation-condition";
import { HaAndCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-and";
import { HaDeviceCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-device";
import { HaNotCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-not";
import HaNumericStateCondition from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-numeric_state";
import { HaOrCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-or";
import { HaStateCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-state";
import { HaSunCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-sun";
import { HaTemplateCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-template";
import { HaTimeCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-time";
import { HaTriggerCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-trigger";
import { HaZoneCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-zone";
import { HaAndCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-and";
import { HaOrCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-or";
import { HaNotCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-not";
import type { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
const SCHEMAS: { name: string; conditions: ConditionWithShorthand[] }[] = [
{

View File

@ -1,35 +1,36 @@
import type { TemplateResult } from "lit";
import { LitElement, html, css } from "lit";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import type { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockAreaRegistry } from "../../../../demo/src/stubs/area_registry";
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
import { mockConfig } from "../../../../demo/src/stubs/config";
import { mockTags } from "../../../../demo/src/stubs/tags";
import { mockAuth } from "../../../../demo/src/stubs/auth";
import { mockConfig } from "../../../../demo/src/stubs/config";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
import { mockTags } from "../../../../demo/src/stubs/tags";
import "../../../../src/components/ha-formfield";
import type { Trigger } from "../../../../src/data/automation";
import { HaGeolocationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import "../../../../src/panels/config/automation/trigger/ha-automation-trigger";
import { HaConversationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-conversation";
import { HaDeviceTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-device";
import { HaEventTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-event";
import { HaGeolocationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location";
import { HaHassTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant";
import { HaTriggerList } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-list";
import { HaMQTTTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt";
import { HaNumericStateTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state";
import { HaPersistentNotificationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-persistent_notification";
import { HaStateTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-state";
import { HaSunTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-sun";
import { HaTagTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-tag";
import { HaTemplateTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-template";
import { HaTimeTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-time";
import { HaTimePatternTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern";
import { HaWebhookTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-webhook";
import { HaPersistentNotificationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-persistent_notification";
import { HaZoneTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-zone";
import { HaDeviceTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-device";
import { HaStateTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-state";
import { HaMQTTTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt";
import "../../../../src/panels/config/automation/trigger/ha-automation-trigger";
import { HaConversationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-conversation";
import { HaTriggerList } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-list";
import type { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
const SCHEMAS: { name: string; triggers: Trigger[] }[] = [
{

View File

@ -6,22 +6,23 @@ import { mockAreaRegistry } from "../../../../demo/src/stubs/area_registry";
import { mockConfigEntries } from "../../../../demo/src/stubs/config_entries";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockFloorRegistry } from "../../../../demo/src/stubs/floor_registry";
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
import { mockLabelRegistry } from "../../../../demo/src/stubs/label_registry";
import "../../../../src/components/ha-formfield";
import "../../../../src/components/ha-selector/ha-selector";
import "../../../../src/components/ha-settings-row";
import type { AreaRegistryEntry } from "../../../../src/data/area_registry";
import type { BlueprintInput } from "../../../../src/data/blueprint";
import type { DeviceRegistryEntry } from "../../../../src/data/device_registry";
import type { FloorRegistryEntry } from "../../../../src/data/floor_registry";
import type { LabelRegistryEntry } from "../../../../src/data/label_registry";
import { showDialog } from "../../../../src/dialogs/make-dialog-manager";
import { getEntity } from "../../../../src/fake_data/entity";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import type { ProvideHassElement } from "../../../../src/mixins/provide-hass-lit-mixin";
import type { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
import type { FloorRegistryEntry } from "../../../../src/data/floor_registry";
import type { LabelRegistryEntry } from "../../../../src/data/label_registry";
import { mockFloorRegistry } from "../../../../demo/src/stubs/floor_registry";
import { mockLabelRegistry } from "../../../../demo/src/stubs/label_registry";
import type { DeviceRegistryEntry } from "../../../../src/data/device_registry";
const ENTITIES = [
getEntity("alarm_control_panel", "alarm", "disarmed", {

View File

@ -1,9 +1,9 @@
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatDateTimeNumeric } from "../../../../src/common/datetime/format_date_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@ -49,7 +49,7 @@ export class DemoDateTimeDateTimeNumeric extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@ -96,7 +96,7 @@ export class DemoDateTimeDateTimeNumeric extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@ -1,9 +1,9 @@
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatDateTimeWithSeconds } from "../../../../src/common/datetime/format_date_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@ -49,7 +49,7 @@ export class DemoDateTimeDateTimeSeconds extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@ -96,7 +96,7 @@ export class DemoDateTimeDateTimeSeconds extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@ -1,9 +1,9 @@
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatShortDateTimeWithYear } from "../../../../src/common/datetime/format_date_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@ -49,7 +49,7 @@ export class DemoDateTimeDateTimeShortYear extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@ -96,7 +96,7 @@ export class DemoDateTimeDateTimeShortYear extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@ -1,9 +1,9 @@
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatShortDateTime } from "../../../../src/common/datetime/format_date_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@ -49,7 +49,7 @@ export class DemoDateTimeDateTimeShort extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@ -96,7 +96,7 @@ export class DemoDateTimeDateTimeShort extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@ -1,9 +1,9 @@
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatDateTime } from "../../../../src/common/datetime/format_date_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@ -49,7 +49,7 @@ export class DemoDateTimeDateTime extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@ -96,7 +96,7 @@ export class DemoDateTimeDateTime extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@ -1,8 +1,8 @@
import "@material/mwc-list/mwc-list";
import { css, html, LitElement } from "lit";
import { customElement } from "lit/decorators";
import { formatDateNumeric } from "../../../../src/common/datetime/format_date";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@ -27,7 +27,7 @@ export class DemoDateTimeDate extends LitElement {
};
const date = new Date();
return html`
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@ -86,7 +86,7 @@ export class DemoDateTimeDate extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@ -1,9 +1,9 @@
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatTimeWithSeconds } from "../../../../src/common/datetime/format_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@ -49,7 +49,7 @@ export class DemoDateTimeTimeSeconds extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@ -96,7 +96,7 @@ export class DemoDateTimeTimeSeconds extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@ -1,9 +1,9 @@
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatTimeWeekday } from "../../../../src/common/datetime/format_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@ -49,7 +49,7 @@ export class DemoDateTimeTimeWeekday extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@ -96,7 +96,7 @@ export class DemoDateTimeTimeWeekday extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@ -1,9 +1,9 @@
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatTime } from "../../../../src/common/datetime/format_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@ -49,7 +49,7 @@ export class DemoDateTimeTime extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@ -96,7 +96,7 @@ export class DemoDateTimeTime extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@ -1,5 +1,5 @@
import type { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
import "@material/mwc-list/mwc-list-item";
import { mdiDotsVertical } from "@mdi/js";
import type { PropertyValues, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
@ -11,6 +11,7 @@ import { navigate } from "../../../src/common/navigate";
import { extractSearchParam } from "../../../src/common/url/search-params";
import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-icon-button";
import "../../../src/components/ha-list-item";
import "../../../src/components/search-input";
import type { HassioAddonRepository } from "../../../src/data/hassio/addon";
import { reloadHassioAddons } from "../../../src/data/hassio/addon";
@ -89,17 +90,17 @@ export class HassioAddonStore extends LitElement {
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
<mwc-list-item>
<ha-list-item>
${this.supervisor.localize("store.check_updates")}
</mwc-list-item>
<mwc-list-item>
</ha-list-item>
<ha-list-item>
${this.supervisor.localize("store.repositories")}
</mwc-list-item>
</ha-list-item>
${this.hass.userData?.showAdvanced &&
atLeastVersion(this.hass.config.version, 0, 117)
? html`<mwc-list-item>
? html`<ha-list-item>
${this.supervisor.localize("store.registries")}
</mwc-list-item>`
</ha-list-item>`
: ""}
</ha-button-menu>
${repos.length === 0

View File

@ -1,6 +1,4 @@
import "@material/mwc-button";
import type { ActionDetail } from "@material/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { mdiDotsVertical } from "@mdi/js";
import { DEFAULT_SCHEMA, Type } from "js-yaml";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
@ -16,6 +14,7 @@ import "../../../../src/components/ha-form/ha-form";
import type { HaFormSchema } from "../../../../src/components/ha-form/types";
import "../../../../src/components/ha-formfield";
import "../../../../src/components/ha-icon-button";
import "../../../../src/components/ha-list-item";
import "../../../../src/components/ha-switch";
import "../../../../src/components/ha-yaml-editor";
import type { HaYamlEditor } from "../../../../src/components/ha-yaml-editor";
@ -178,7 +177,7 @@ class HassioAddonConfig extends LitElement {
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
<mwc-list-item .disabled=${!this._canShowSchema || this.disabled}>
<ha-list-item .disabled=${!this._canShowSchema || this.disabled}>
${this._yamlMode
? this.supervisor.localize(
"addon.configuration.options.edit_in_ui"
@ -186,13 +185,13 @@ class HassioAddonConfig extends LitElement {
: this.supervisor.localize(
"addon.configuration.options.edit_in_yaml"
)}
</mwc-list-item>
<mwc-list-item
</ha-list-item>
<ha-list-item
class=${!this.disabled ? "warning" : ""}
.disabled=${this.disabled}
>
${this.supervisor.localize("common.reset_defaults")}
</mwc-list-item>
</ha-list-item>
</ha-button-menu>
</div>
</div>
@ -419,7 +418,7 @@ class HassioAddonConfig extends LitElement {
z-index: 3;
--mdc-theme-text-primary-on-background: var(--primary-text-color);
}
mwc-list-item[disabled] {
ha-list-item[disabled] {
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
}
.header {

View File

@ -6,6 +6,7 @@ import { fireEvent } from "../../../../src/common/dom/fire_event";
import "../../../../src/components/buttons/ha-progress-button";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-formfield";
import "../../../../src/components/ha-form/ha-form";
import type { HaFormSchema } from "../../../../src/components/ha-form/types";
import type {

View File

@ -1,6 +1,6 @@
import "@material/mwc-button";
import type { ActionDetail } from "@material/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { mdiBackupRestore, mdiDelete, mdiDotsVertical, mdiPlus } from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
@ -18,6 +18,7 @@ import type {
import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-fab";
import "../../../src/components/ha-icon-button";
import "../../../src/components/ha-list-item";
import "../../../src/components/ha-svg-icon";
import type { HassioBackup } from "../../../src/data/hassio/backup";
import {
@ -32,6 +33,7 @@ import {
showAlertDialog,
showConfirmationDialog,
} from "../../../src/dialogs/generic/show-dialog-box";
import "../../../src/layouts/hass-loading-screen";
import "../../../src/layouts/hass-tabs-subpage-data-table";
import type { HaTabsSubpageDataTable } from "../../../src/layouts/hass-tabs-subpage-data-table";
import { haStyle } from "../../../src/resources/styles";
@ -42,7 +44,6 @@ import { showHassioBackupDialog } from "../dialogs/backup/show-dialog-hassio-bac
import { showHassioCreateBackupDialog } from "../dialogs/backup/show-dialog-hassio-create-backup";
import { supervisorTabs } from "../hassio-tabs";
import { hassioStyle } from "../resources/hassio-style";
import "../../../src/layouts/hass-loading-screen";
type BackupItem = HassioBackup & {
secondary: string;
@ -211,16 +212,16 @@ export class HassioBackups extends LitElement {
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
<mwc-list-item>
<ha-list-item>
${this.supervisor.localize("common.reload")}
</mwc-list-item>
<mwc-list-item>
</ha-list-item>
<ha-list-item>
${this.supervisor.localize("dialog.backup_location.title")}
</mwc-list-item>
</ha-list-item>
${atLeastVersion(this.hass.config.version, 0, 116)
? html`<mwc-list-item>
? html`<ha-list-item>
${this.supervisor.localize("backup.upload_backup")}
</mwc-list-item>`
</ha-list-item>`
: ""}
</ha-button-menu>

View File

@ -1,5 +1,5 @@
import type { ActionDetail } from "@material/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { mdiClose, mdiDotsVertical } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
@ -8,15 +8,17 @@ import { atLeastVersion } from "../../../../src/common/config/version";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import { stopPropagation } from "../../../../src/common/dom/stop_propagation";
import { slugify } from "../../../../src/common/string/slugify";
import "../../../../src/components/ha-md-dialog";
import "../../../../src/components/ha-dialog-header";
import "../../../../src/components/buttons/ha-progress-button";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-spinner";
import "../../../../src/components/ha-button";
import "../../../../src/components/ha-button-menu";
import "../../../../src/components/ha-dialog-header";
import "../../../../src/components/ha-header-bar";
import "../../../../src/components/ha-icon-button";
import "../../../../src/components/ha-list-item";
import "../../../../src/components/ha-md-dialog";
import type { HaMdDialog } from "../../../../src/components/ha-md-dialog";
import "../../../../src/components/ha-spinner";
import { getSignedPath } from "../../../../src/data/auth";
import type { HassioBackupDetail } from "../../../../src/data/hassio/backup";
import {
@ -36,7 +38,6 @@ import { fileDownload } from "../../../../src/util/file_download";
import "../../components/supervisor-backup-content";
import type { SupervisorBackupContent } from "../../components/supervisor-backup-content";
import type { HassioBackupDialogParams } from "./show-dialog-hassio-backup";
import type { HaMdDialog } from "../../../../src/components/ha-md-dialog";
@customElement("dialog-hassio-backup")
class HassioBackupDialog
@ -121,15 +122,15 @@ class HassioBackupDialog
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
<mwc-list-item
<ha-list-item
>${this._dialogParams.supervisor.localize(
"backup.download_backup"
)}</mwc-list-item
)}</ha-list-item
>
<mwc-list-item class="error"
<ha-list-item class="error"
>${this._dialogParams.supervisor.localize(
"backup.delete_backup_title"
)}</mwc-list-item
)}</ha-list-item
>
</ha-button-menu>`
: nothing}

View File

@ -1,12 +1,12 @@
import "@material/mwc-list/mwc-list-item";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import "../../../../src/components/ha-spinner";
import "../../../../src/components/ha-select";
import "../../../../src/components/ha-dialog";
import "../../../../src/components/ha-list-item";
import "../../../../src/components/ha-select";
import "../../../../src/components/ha-spinner";
import {
extractApiErrorMessage,
ignoreSupervisorError,
@ -95,8 +95,8 @@ class HassioDatadiskDialog extends LitElement {
>
${this.devices.map(
(device) =>
html`<mwc-list-item .value=${device}
>${device}</mwc-list-item
html`<ha-list-item .value=${device}
>${device}</ha-list-item
>`
)}
</ha-select>

View File

@ -1,6 +1,5 @@
import "@material/mwc-button/mwc-button";
import "@material/mwc-list/mwc-list";
import "@material/mwc-list/mwc-list-item";
import "@material/mwc-tab";
import "@material/mwc-tab-bar";
import { mdiClose } from "@mdi/js";
@ -10,14 +9,16 @@ import { customElement, property, state } from "lit/decorators";
import { cache } from "lit/directives/cache";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-spinner";
import "../../../../src/components/ha-dialog";
import "../../../../src/components/ha-expansion-panel";
import "../../../../src/components/ha-formfield";
import "../../../../src/components/ha-header-bar";
import "../../../../src/components/ha-icon-button";
import "../../../../src/components/ha-list";
import "../../../../src/components/ha-list-item";
import "../../../../src/components/ha-password-field";
import "../../../../src/components/ha-radio";
import "../../../../src/components/ha-spinner";
import "../../../../src/components/ha-textfield";
import type { HaTextField } from "../../../../src/components/ha-textfield";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
@ -169,12 +170,12 @@ export class DialogHassioNetwork
this._accessPoints.accesspoints &&
this._accessPoints.accesspoints.length !== 0
? html`
<mwc-list>
<ha-list>
${this._accessPoints.accesspoints
.filter((ap) => ap.ssid)
.map(
(ap) => html`
<mwc-list-item
<ha-list-item
twoline
@click=${this._selectAP}
.activated=${ap.ssid ===
@ -189,10 +190,10 @@ export class DialogHassioNetwork
)}:
${ap.signal}
</span>
</mwc-list-item>
</ha-list-item>
`
)}
</mwc-list>
</ha-list>
`
: ""}
${this._wifiConfiguration
@ -634,7 +635,7 @@ export class DialogHassioNetwork
ha-textfield {
padding: 0 14px;
}
mwc-list-item {
ha-list-item {
--mdc-list-side-padding: 10px;
}
`,

View File

@ -1,5 +1,5 @@
import "@material/mwc-button";
import "@material/mwc-list/mwc-list-item";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
@ -197,9 +197,6 @@ class HassioCoreInfo extends LitElement {
color: var(--secondary-text-color);
--mdc-menu-min-width: 200px;
}
mwc-list-item ha-svg-icon {
color: var(--secondary-text-color);
}
a {
text-decoration: none;
}

View File

@ -1,5 +1,5 @@
import "@material/mwc-button";
import "@material/mwc-list/mwc-list-item";
import { mdiDotsVertical } from "@mdi/js";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
@ -10,6 +10,7 @@ import { fireEvent } from "../../../src/common/dom/fire_event";
import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-card";
import "../../../src/components/ha-list-item";
import "../../../src/components/ha-icon-button";
import "../../../src/components/ha-settings-row";
import {
@ -188,31 +189,31 @@ class HassioHostInfo extends LitElement {
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
<mwc-list-item
<ha-list-item
.action=${"hardware"}
@click=${this._handleMenuAction}
>
${this.supervisor.localize("system.host.hardware")}
</mwc-list-item>
</ha-list-item>
${this.supervisor.host.features.includes("haos")
? html`
<mwc-list-item
<ha-list-item
.action=${"import_from_usb"}
@click=${this._handleMenuAction}
>
${this.supervisor.localize("system.host.import_from_usb")}
</mwc-list-item>
</ha-list-item>
${this.supervisor.host.features.includes("os_agent") &&
atLeastVersion(this.supervisor.host.agent_version, 1, 2, 0)
? html`
<mwc-list-item
<ha-list-item
.action=${"move_datadisk"}
@click=${this._handleMenuAction}
>
${this.supervisor.localize(
"system.host.move_datadisk"
)}
</mwc-list-item>
</ha-list-item>
`
: ""}
`
@ -438,7 +439,7 @@ class HassioHostInfo extends LitElement {
color: var(--secondary-text-color);
--mdc-menu-min-width: 200px;
}
mwc-list-item ha-svg-icon {
ha-list-item ha-svg-icon {
color: var(--secondary-text-color);
}
a {

View File

@ -1,5 +1,5 @@
import "@material/mwc-button";
import "@material/mwc-list/mwc-list-item";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
@ -8,6 +8,7 @@ import "../../../src/components/ha-alert";
import "../../../src/components/ha-ansi-to-html";
import "../../../src/components/ha-card";
import "../../../src/components/ha-select";
import "../../../src/components/ha-list-item";
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
import { fetchHassioLogs } from "../../../src/data/hassio/supervisor";
import type { Supervisor } from "../../../src/data/supervisor/supervisor";
@ -80,9 +81,9 @@ class HassioSupervisorLog extends LitElement {
>
${logProviders.map(
(provider) => html`
<mwc-list-item .value=${provider.key}>
<ha-list-item .value=${provider.key}>
${provider.name}
</mwc-list-item>
</ha-list-item>
`
)}
</ha-select>

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list-item";
import {
css,
type CSSResultGroup,

View File

@ -52,10 +52,10 @@
"@fullcalendar/luxon3": "6.1.17",
"@fullcalendar/timegrid": "6.1.17",
"@lezer/highlight": "1.2.1",
"@lit-labs/context": "0.4.1",
"@lit-labs/motion": "1.0.8",
"@lit-labs/observers": "2.0.5",
"@lit-labs/virtualizer": "2.1.0",
"@lit/context": "1.1.4",
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
"@material/mwc-base": "0.27.0",
@ -65,10 +65,10 @@
"@material/mwc-drawer": "0.27.0",
"@material/mwc-fab": "0.27.0",
"@material/mwc-floating-label": "0.27.0",
"@material/mwc-formfield": "0.27.0",
"@material/mwc-formfield": "patch:@material/mwc-formfield@npm%3A0.27.0#~/.yarn/patches/@material-mwc-formfield-npm-0.27.0-9528cb60f6.patch",
"@material/mwc-icon-button": "0.27.0",
"@material/mwc-linear-progress": "0.27.0",
"@material/mwc-list": "0.27.0",
"@material/mwc-list": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch",
"@material/mwc-menu": "0.27.0",
"@material/mwc-radio": "0.27.0",
"@material/mwc-select": "0.27.0",
@ -86,6 +86,7 @@
"@mdi/svg": "7.4.47",
"@replit/codemirror-indentation-markers": "6.5.3",
"@shoelace-style/shoelace": "2.20.1",
"@swc/helpers": "0.5.17",
"@thomasloven/round-slider": "0.6.0",
"@tsparticles/engine": "3.8.1",
"@tsparticles/preset-links": "3.2.0",
@ -119,8 +120,8 @@
"leaflet": "1.9.4",
"leaflet-draw": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch",
"leaflet.markercluster": "1.5.3",
"lit": "2.8.0",
"lit-html": "2.8.0",
"lit": "3.3.0",
"lit-html": "3.3.0",
"luxon": "3.6.1",
"marked": "15.0.8",
"memoize-one": "6.0.0",
@ -152,10 +153,8 @@
"devDependencies": {
"@babel/core": "7.26.10",
"@babel/helper-define-polyfill-provider": "0.6.4",
"@babel/plugin-proposal-decorators": "7.25.9",
"@babel/plugin-transform-runtime": "7.26.10",
"@babel/preset-env": "7.26.9",
"@babel/preset-typescript": "7.27.0",
"@bundle-stats/plugin-webpack-filter": "4.19.1",
"@lokalise/node-api": "14.4.0",
"@octokit/auth-oauth-device": "7.1.5",
@ -230,13 +229,14 @@
},
"resolutions": {
"@material/mwc-button@^0.25.3": "^0.27.0",
"lit": "2.8.0",
"lit-html": "2.8.0",
"lit": "3.3.0",
"lit-html": "3.3.0",
"clean-css": "5.3.3",
"@lit/reactive-element": "1.6.3",
"@lit/reactive-element": "2.1.0",
"@fullcalendar/daygrid": "6.1.17",
"globals": "16.0.0",
"tslib": "2.8.1"
"tslib": "2.8.1",
"@material/mwc-list@^0.27.0": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch"
},
"packageManager": "yarn@4.9.1"
}

View File

@ -1,9 +1,9 @@
import "@material/mwc-list";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import type { LocalizeFunc } from "../common/translations/localize";
import "../components/ha-icon-next";
import "../components/ha-list";
import "../components/ha-list-item";
import type { AuthProvider } from "../data/auth";
@ -29,7 +29,7 @@ export class HaPickAuthProvider extends LitElement {
>${this.localize("ui.panel.page-authorize.pick_auth_provider")}</span
>
</h3>
<mwc-list>
<ha-list>
${this.authProviders.map(
(provider) => html`
<ha-list-item
@ -43,7 +43,7 @@ export class HaPickAuthProvider extends LitElement {
</ha-list-item>
`
)}
</mwc-list>
</ha-list>
`;
}
@ -77,7 +77,7 @@ export class HaPickAuthProvider extends LitElement {
background: var(--card-background-color);
padding: 0 15px;
}
mwc-list {
ha-list {
margin: 16px -16px 0;
--mdc-list-side-padding: 24px;
}

View File

@ -1,46 +1,65 @@
import type { LitElement } from "lit";
import type { ClassElement } from "../../types";
import type { ReactiveElement } from "lit";
import { throttle } from "../util/throttle";
const throttleReplaceState = throttle((value) => {
history.replaceState({ scrollPosition: value }, "");
}, 300);
export const restoreScroll =
(selector: string): any =>
(element: ClassElement) => ({
kind: "method",
placement: "prototype",
key: element.key,
descriptor: {
set(this: LitElement, value: number) {
throttleReplaceState(value);
this[`__${String(element.key)}`] = value;
},
get(this: LitElement) {
return (
this[`__${String(element.key)}`] || history.state?.scrollPosition
);
},
enumerable: true,
configurable: true,
},
finisher(cls: typeof LitElement) {
const connectedCallback = cls.prototype.connectedCallback;
cls.prototype.connectedCallback = function () {
connectedCallback.call(this);
const scrollPos = this[element.key];
if (scrollPos) {
this.updateComplete.then(() => {
const target = this.renderRoot.querySelector(selector);
if (!target) {
return;
}
setTimeout(() => {
target.scrollTop = scrollPos;
}, 0);
});
}
export function restoreScroll(selector: string) {
return <ElemClass extends ReactiveElement>(
proto: ElemClass,
propertyKey: string
) => {
if (typeof propertyKey === "object") {
throw new Error("This decorator does not support this compilation type.");
}
const connectedCallback = proto.connectedCallback;
proto.connectedCallback = function () {
connectedCallback.call(this);
const scrollPos = this[propertyKey];
if (scrollPos) {
this.updateComplete.then(() => {
const target = this.renderRoot.querySelector(selector);
if (!target) {
return;
}
setTimeout(() => {
target.scrollTop = scrollPos;
}, 0);
});
}
};
const descriptor = Object.getOwnPropertyDescriptor(proto, propertyKey);
let newDescriptor: PropertyDescriptor;
if (descriptor === undefined) {
newDescriptor = {
get(this: ReactiveElement) {
return (
this[`__${String(propertyKey)}`] || history.state?.scrollPosition
);
},
set(this: ReactiveElement, value) {
throttleReplaceState(value);
this[`__${String(propertyKey)}`] = value;
},
configurable: true,
enumerable: true,
};
},
});
} else {
const oldSetter = descriptor.set;
newDescriptor = {
...descriptor,
set(this: ReactiveElement, value) {
throttleReplaceState(value);
this[`__${String(propertyKey)}`] = value;
oldSetter?.call(this, value);
},
};
}
Object.defineProperty(proto, propertyKey, newDescriptor);
};
}

View File

@ -1,14 +1,17 @@
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { ReactiveElement } from "lit";
import { ReactiveElement } from "lit";
import type { InternalPropertyDeclaration } from "lit/decorators";
import type { ClassElement } from "../../types";
type Callback = (oldValue: any, newValue: any) => void;
type ReactiveStorageElement = ReactiveElement & {
__unbsubLocalStorage: UnsubscribeFunc | undefined;
};
class StorageClass {
constructor(storage = window.localStorage) {
this.storage = storage;
if (storage !== window.localStorage) {
constructor(store = window.localStorage) {
this.storage = store;
if (this.storage !== window.localStorage) {
// storage events only work for localStorage
return;
}
@ -99,17 +102,23 @@ class StorageClass {
const storages: Record<string, StorageClass> = {};
export const storage =
(options: {
key?: string;
storage?: "localStorage" | "sessionStorage";
subscribe?: boolean;
state?: boolean;
stateOptions?: InternalPropertyDeclaration;
serializer?: (value: any) => any;
deserializer?: (value: any) => any;
}): any =>
(clsElement: ClassElement) => {
export function storage(options: {
key?: string;
storage?: "localStorage" | "sessionStorage";
subscribe?: boolean;
state?: boolean;
stateOptions?: InternalPropertyDeclaration;
serializer?: (value: any) => any;
deserializer?: (value: any) => any;
}) {
return <ElemClass extends ReactiveElement>(
proto: ElemClass,
propertyKey: string
) => {
if (typeof propertyKey === "object") {
throw new Error("This decorator does not support this compilation type.");
}
const storageName = options.storage || "localStorage";
let storageInstance: StorageClass;
@ -120,11 +129,7 @@ export const storage =
storages[storageName] = storageInstance;
}
const key = String(clsElement.key);
const storageKey = options.key || String(clsElement.key);
const initVal = clsElement.initializer
? clsElement.initializer()
: undefined;
const storageKey = options.key || String(propertyKey);
storageInstance.addFromStorage(storageKey);
@ -134,7 +139,7 @@ export const storage =
storageInstance.subscribeChanges(
storageKey!,
(oldValue, _newValue) => {
el.requestUpdate(clsElement.key, oldValue);
el.requestUpdate(propertyKey, oldValue);
}
)
: undefined;
@ -144,7 +149,7 @@ export const storage =
? options.deserializer
? options.deserializer(storageInstance.getValue(storageKey!))
: storageInstance.getValue(storageKey!)
: initVal;
: undefined;
const setValue = (el: ReactiveElement, value: any) => {
let oldValue: unknown | undefined;
@ -156,44 +161,62 @@ export const storage =
options.serializer ? options.serializer(value) : value
);
if (options.state) {
el.requestUpdate(clsElement.key, oldValue);
el.requestUpdate(propertyKey, oldValue);
}
};
return {
kind: "method",
placement: "prototype",
key: clsElement.key,
descriptor: {
set(this: ReactiveElement, value: unknown) {
setValue(this, value);
},
get() {
if (options.state && options.subscribe) {
const connectedCallback = proto.connectedCallback;
const disconnectedCallback = proto.disconnectedCallback;
proto.connectedCallback = function () {
connectedCallback.call(this);
const el = this as unknown as ReactiveStorageElement;
if (!el.__unbsubLocalStorage) {
el.__unbsubLocalStorage = subscribeChanges?.(this);
}
};
proto.disconnectedCallback = function () {
disconnectedCallback.call(this);
const el = this as unknown as ReactiveStorageElement;
el.__unbsubLocalStorage?.();
el.__unbsubLocalStorage = undefined;
};
}
if (options.state) {
ReactiveElement.createProperty(propertyKey, {
noAccessor: true,
...options.stateOptions,
});
}
const descriptor = Object.getOwnPropertyDescriptor(proto, propertyKey);
let newDescriptor: PropertyDescriptor;
if (descriptor === undefined) {
newDescriptor = {
get(this: ReactiveElement) {
return getValue();
},
enumerable: true,
set(this: ReactiveElement, value) {
// Don't set the initial value if we have a value in localStorage
if (this.hasUpdated || getValue() === undefined) {
setValue(this, value);
}
this.requestUpdate(propertyKey, undefined);
},
configurable: true,
},
finisher(cls: typeof ReactiveElement) {
if (options.state && options.subscribe) {
const connectedCallback = cls.prototype.connectedCallback;
const disconnectedCallback = cls.prototype.disconnectedCallback;
cls.prototype.connectedCallback = function () {
connectedCallback.call(this);
this[`__unbsubLocalStorage${key}`] = subscribeChanges?.(this);
};
cls.prototype.disconnectedCallback = function () {
disconnectedCallback.call(this);
this[`__unbsubLocalStorage${key}`]?.();
this[`__unbsubLocalStorage${key}`] = undefined;
};
}
if (options.state) {
cls.createProperty(clsElement.key, {
noAccessor: true,
...options.stateOptions,
});
}
},
};
enumerable: true,
};
} else {
const oldSetter = descriptor.set;
newDescriptor = {
...descriptor,
set(this: ReactiveElement, value) {
setValue(this, value);
oldSetter?.call(this, value);
},
};
}
Object.defineProperty(proto, propertyKey, newDescriptor);
};
}

View File

@ -1,39 +1,103 @@
import type { PropertyDeclaration, PropertyValues, ReactiveElement } from "lit";
import type { ClassElement } from "../../types";
import {
ReactiveElement,
type PropertyDeclaration,
type PropertyValues,
} from "lit";
import { shallowEqual } from "../util/shallow-equal";
/**
* Transform function type.
*/
export type Transformer<T = any, V = any> = (value: V) => T;
export type Transformer<T = any, V = any> = (value: T) => V | undefined;
type ReactiveTransformElement = ReactiveElement & {
_transformers: Map<PropertyKey, Transformer>;
_watching: Map<PropertyKey, Set<PropertyKey>>;
};
type ReactiveElementClassWithTransformers = typeof ReactiveElement & {
prototype: ReactiveTransformElement;
};
/**
* Specifies a transformer callback that is run when the value of the decorated property, or any of the properties in the watching array, changes.
* The result of the transformer is assigned to the decorated property.
* The transformer receives the current as argument.
*/
export const transform =
<T, V>(config: {
transformer: Transformer<T, V>;
watch?: PropertyKey[];
propertyOptions?: PropertyDeclaration;
}): any =>
(clsElement: ClassElement) => {
const key = String(clsElement.key);
return {
...clsElement,
kind: "method",
descriptor: {
set(this: ReactiveTransformElement, value: V) {
export function transform<T, V>(config: {
transformer: Transformer<T, V>;
watch?: PropertyKey[];
propertyOptions?: PropertyDeclaration;
}) {
return <ElemClass extends ReactiveElement>(
proto: ElemClass,
propertyKey: string
) => {
if (typeof propertyKey === "object") {
throw new Error("This decorator does not support this compilation type.");
}
const key = String(propertyKey);
const el = proto as unknown as ReactiveTransformElement;
// if we haven't wrapped `willUpdate` in this class, do so
if (!el._transformers) {
el._transformers = new Map<PropertyKey, Transformer>();
el._watching = new Map<PropertyKey, Set<PropertyKey>>();
// @ts-ignore
const userWillUpdate = el.willUpdate;
// @ts-ignore
el.willUpdate = function (
this: ReactiveTransformElement,
changedProperties: PropertyValues
) {
userWillUpdate.call(this, changedProperties);
const keys = new Set<PropertyKey>();
changedProperties.forEach((_v, k) => {
const watchers = this._watching;
const ks: Set<PropertyKey> | undefined = watchers.get(k);
if (ks !== undefined) {
ks.forEach((wk) => keys.add(wk));
}
});
keys.forEach((k) => {
// trigger setter
this[k] = this[`__original_${String(k)}`];
});
};
// clone any existing observers (superclasses)
// eslint-disable-next-line no-prototype-builtins
} else if (!el.hasOwnProperty("_transformers")) {
const tranformers = el._transformers;
el._transformers = new Map();
tranformers.forEach((v: any, k: PropertyKey) =>
el._transformers.set(k, v)
);
}
// set this method
el._transformers.set(propertyKey, config.transformer);
if (config.watch) {
// store watchers
config.watch.forEach((k) => {
let curWatch = el._watching.get(k);
if (!curWatch) {
curWatch = new Set();
el._watching.set(k, curWatch);
}
curWatch.add(propertyKey);
});
}
ReactiveElement.createProperty(propertyKey, {
noAccessor: true,
hasChanged: (v: any, o: any) => !shallowEqual(v, o),
...config.propertyOptions,
});
const descriptor = Object.getOwnPropertyDescriptor(proto, propertyKey);
let newDescriptor: PropertyDescriptor;
if (descriptor === undefined) {
newDescriptor = {
get(this: ReactiveTransformElement): V {
return this[`__transform_${key}`];
},
set(this: ReactiveTransformElement, value: T) {
const oldValue = this[`__transform_${key}`];
const trnsformr: Transformer<T, V> | undefined =
this._transformers.get(key);
@ -45,65 +109,28 @@ export const transform =
this[`__original_${key}`] = value;
this.requestUpdate(key, oldValue);
},
get(): T {
return this[`__transform_${key}`];
},
enumerable: true,
configurable: true,
},
finisher(cls: ReactiveElementClassWithTransformers) {
// if we haven't wrapped `willUpdate` in this class, do so
if (!cls.prototype._transformers) {
cls.prototype._transformers = new Map<PropertyKey, Transformer>();
cls.prototype._watching = new Map<PropertyKey, Set<PropertyKey>>();
// @ts-ignore
const userWillUpdate = cls.prototype.willUpdate;
// @ts-ignore
cls.prototype.willUpdate = function (
this: ReactiveTransformElement,
changedProperties: PropertyValues
) {
userWillUpdate.call(this, changedProperties);
const keys = new Set<PropertyKey>();
changedProperties.forEach((_v, k) => {
const watchers = this._watching;
const ks: Set<PropertyKey> | undefined = watchers.get(k);
if (ks !== undefined) {
ks.forEach((wk) => keys.add(wk));
}
});
keys.forEach((k) => {
// trigger setter
this[k] = this[`__original_${String(k)}`];
});
};
// clone any existing observers (superclasses)
// eslint-disable-next-line no-prototype-builtins
} else if (!cls.prototype.hasOwnProperty("_transformers")) {
const tranformers = cls.prototype._transformers;
cls.prototype._transformers = new Map();
tranformers.forEach((v: any, k: PropertyKey) =>
cls.prototype._transformers.set(k, v)
);
}
// set this method
cls.prototype._transformers.set(clsElement.key, config.transformer);
if (config.watch) {
// store watchers
config.watch.forEach((k) => {
let curWatch = cls.prototype._watching.get(k);
if (!curWatch) {
curWatch = new Set();
cls.prototype._watching.set(k, curWatch);
}
curWatch.add(clsElement.key);
});
}
cls.createProperty(clsElement.key, {
noAccessor: true,
hasChanged: (v: any, o: any) => !shallowEqual(v, o),
...config.propertyOptions,
});
},
};
enumerable: true,
};
} else {
const oldSetter = descriptor.set;
newDescriptor = {
...descriptor,
set(this: ReactiveTransformElement, value: T) {
const oldValue = this[`__transform_${key}`];
const trnsformr: Transformer | undefined =
this._transformers.get(key);
if (trnsformr) {
this[`__transform_${key}`] = trnsformr.call(this, value);
} else {
this[`__transform_${key}`] = value;
}
this[`__original_${key}`] = value;
this.requestUpdate(key, oldValue);
oldSetter?.call(this, value);
},
};
}
Object.defineProperty(proto, propertyKey, newDescriptor);
};
}

View File

@ -1,4 +1,4 @@
import { consume } from "@lit-labs/context";
import { consume } from "@lit/context";
import { ResizeController } from "@lit-labs/observers/resize-controller";
import { mdiChevronDown, mdiChevronUp, mdiRestart } from "@mdi/js";
import { differenceInMinutes } from "date-fns";

View File

@ -1,16 +1,23 @@
import { MdAssistChip } from "@material/web/chips/assist-chip";
import { AssistChip } from "@material/web/chips/internal/assist-chip";
import { styles } from "@material/web/chips/internal/assist-styles";
import { styles as sharedStyles } from "@material/web/chips/internal/shared-styles";
import { styles as elevatedStyles } from "@material/web/chips/internal/elevated-styles";
import { css, html } from "lit";
import { customElement, property } from "lit/decorators";
@customElement("ha-assist-chip")
// @ts-ignore
export class HaAssistChip extends MdAssistChip {
export class HaAssistChip extends AssistChip {
@property({ type: Boolean, reflect: true }) filled = false;
@property({ type: Boolean }) active = false;
static override styles = [
...super.styles,
sharedStyles,
elevatedStyles,
styles,
css`
:host {
--md-sys-color-primary: var(--primary-text-color);

View File

@ -1,14 +1,23 @@
import { MdFilterChip } from "@material/web/chips/filter-chip";
import { FilterChip } from "@material/web/chips/internal/filter-chip";
import { styles } from "@material/web/chips/internal/filter-styles";
import { styles as selectableStyles } from "@material/web/chips/internal/selectable-styles";
import { styles as sharedStyles } from "@material/web/chips/internal/shared-styles";
import { styles as trailingIconStyles } from "@material/web/chips/internal/trailing-icon-styles";
import { styles as elevatedStyles } from "@material/web/chips/internal/elevated-styles";
import { css, html } from "lit";
import { customElement, property } from "lit/decorators";
@customElement("ha-filter-chip")
export class HaFilterChip extends MdFilterChip {
export class HaFilterChip extends FilterChip {
@property({ type: Boolean, reflect: true, attribute: "no-leading-icon" })
noLeadingIcon = false;
static override styles = [
...super.styles,
sharedStyles,
elevatedStyles,
trailingIconStyles,
selectableStyles,
styles,
css`
:host {
--md-sys-color-primary: var(--primary-text-color);

View File

@ -1,11 +1,18 @@
import { MdInputChip } from "@material/web/chips/input-chip";
import { InputChip } from "@material/web/chips/internal/input-chip";
import { styles } from "@material/web/chips/internal/input-styles";
import { styles as selectableStyles } from "@material/web/chips/internal/selectable-styles";
import { styles as sharedStyles } from "@material/web/chips/internal/shared-styles";
import { styles as trailingIconStyles } from "@material/web/chips/internal/trailing-icon-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-input-chip")
export class HaInputChip extends MdInputChip {
export class HaInputChip extends InputChip {
static override styles = [
...super.styles,
sharedStyles,
trailingIconStyles,
selectableStyles,
styles,
css`
:host {
--md-sys-color-primary: var(--primary-text-color);

View File

@ -1,4 +1,3 @@
import "@material/mwc-list";
import { mdiDrag, mdiEye, mdiEyeOff } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { LitElement, css, html, nothing } from "lit";
@ -6,18 +5,19 @@ import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { repeat } from "lit/directives/repeat";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../common/dom/fire_event";
import { haStyleDialog } from "../../resources/styles";
import type { HomeAssistant } from "../../types";
import "../ha-button";
import { createCloseHeading } from "../ha-dialog";
import "../ha-list";
import "../ha-list-item";
import "../ha-sortable";
import "../ha-button";
import type {
DataTableColumnContainer,
DataTableColumnData,
} from "./ha-data-table";
import type { DataTableSettingsDialogParams } from "./show-dialog-data-table-settings";
import { fireEvent } from "../../common/dom/fire_event";
@customElement("dialog-data-table-settings")
export class DialogDataTableSettings extends LitElement {
@ -104,7 +104,7 @@ export class DialogDataTableSettings extends LitElement {
draggable-selector=".draggable"
handle-selector=".handle"
>
<mwc-list>
<ha-list>
${repeat(
columns,
(col) => col.key,
@ -150,7 +150,7 @@ export class DialogDataTableSettings extends LitElement {
</ha-list-item>`;
}
)}
</mwc-list>
</ha-list>
</ha-sortable>
<ha-button slot="secondaryAction" @click=${this._reset}
>${localize("ui.components.data-table.settings.restore")}</ha-button

View File

@ -1,5 +1,4 @@
import { consume } from "@lit-labs/context";
import "@material/mwc-list/mwc-list-item";
import { consume } from "@lit/context";
import { css, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
@ -11,6 +10,7 @@ import {
} from "../../data/device_automation";
import type { EntityRegistryEntry } from "../../data/entity_registry";
import type { HomeAssistant } from "../../types";
import "../ha-list-item";
import "../ha-select";
const NO_AUTOMATION_KEY = "NO_AUTOMATION";
@ -106,24 +106,24 @@ export abstract class HaDeviceAutomationPicker<
.disabled=${this._automations.length === 0}
>
${value === NO_AUTOMATION_KEY
? html`<mwc-list-item .value=${NO_AUTOMATION_KEY}>
? html`<ha-list-item .value=${NO_AUTOMATION_KEY}>
${this.NO_AUTOMATION_TEXT}
</mwc-list-item>`
</ha-list-item>`
: ""}
${value === UNKNOWN_AUTOMATION_KEY
? html`<mwc-list-item .value=${UNKNOWN_AUTOMATION_KEY}>
? html`<ha-list-item .value=${UNKNOWN_AUTOMATION_KEY}>
${this.UNKNOWN_AUTOMATION_TEXT}
</mwc-list-item>`
</ha-list-item>`
: ""}
${this._automations.map(
(automation, idx) => html`
<mwc-list-item .value=${`${automation.device_id}_${idx}`}>
<ha-list-item .value=${`${automation.device_id}_${idx}`}>
${this._localizeDeviceAutomation(
this.hass,
this._entityReg,
automation
)}
</mwc-list-item>
</ha-list-item>
`
)}
</ha-select>

View File

@ -26,7 +26,6 @@ import "../ha-combo-box";
import type { HaComboBox } from "../ha-combo-box";
import "../ha-combo-box-item";
import "../ha-icon-button";
import "../ha-list-item";
import "../ha-svg-icon";
import "./state-badge";

View File

@ -28,7 +28,6 @@ import type { HaComboBox } from "./ha-combo-box";
import "./ha-combo-box-item";
import "./ha-floor-icon";
import "./ha-icon-button";
import "./ha-list-item";
import "./ha-svg-icon";
import "./ha-tree-indicator";

View File

@ -25,7 +25,6 @@ import "./ha-combo-box";
import type { HaComboBox } from "./ha-combo-box";
import "./ha-combo-box-item";
import "./ha-icon-button";
import "./ha-list-item";
import "./ha-svg-icon";
type ScorableAreaRegistryEntry = ScorableTextItem & AreaRegistryEntry;

View File

@ -1,16 +1,16 @@
import "@material/mwc-list/mwc-list-item";
import { mdiClose } from "@mdi/js";
import type { TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { mdiClose } from "@mdi/js";
import { ifDefined } from "lit/directives/if-defined";
import { fireEvent } from "../common/dom/fire_event";
import { stopPropagation } from "../common/dom/stop_propagation";
import "./ha-select";
import "./ha-icon-button";
import "./ha-input-helper-text";
import "./ha-list-item";
import "./ha-select";
import "./ha-textfield";
import type { HaTextField } from "./ha-textfield";
import "./ha-input-helper-text";
export interface TimeChangedEvent {
days?: number;
@ -266,8 +266,8 @@ export class HaBaseTimeInput extends LitElement {
@selected=${this._valueChanged}
@closed=${stopPropagation}
>
<mwc-list-item value="AM">AM</mwc-list-item>
<mwc-list-item value="PM">PM</mwc-list-item>
<ha-list-item value="AM">AM</ha-list-item>
<ha-list-item value="PM">PM</ha-list-item>
</ha-select>`}
</div>
${this.helper

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list-item";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import memoizeOne from "memoize-one";
@ -8,6 +7,7 @@ import { stringCompare } from "../common/string/compare";
import type { Blueprint, BlueprintDomain, Blueprints } from "../data/blueprint";
import { fetchBlueprints } from "../data/blueprint";
import type { HomeAssistant } from "../types";
import "./ha-list-item";
import "./ha-select";
@customElement("ha-blueprint-picker")
@ -64,9 +64,9 @@ class HaBluePrintPicker extends LitElement {
>
${this._processedBlueprints(this.blueprints).map(
(blueprint) => html`
<mwc-list-item .value=${blueprint.path}>
<ha-list-item .value=${blueprint.path}>
${blueprint.name}
</mwc-list-item>
</ha-list-item>
`
)}
</ha-select>

View File

@ -1,5 +1,4 @@
import type { Button } from "@material/mwc-button";
import "@material/mwc-menu";
import type { Corner, Menu, MenuCorner } from "@material/mwc-menu";
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
@ -7,6 +6,7 @@ import { customElement, property, query } from "lit/decorators";
import { mainWindow } from "../common/dom/get_main_window";
import { FOCUS_TARGET } from "../dialogs/make-dialog-manager";
import type { HaIconButton } from "./ha-icon-button";
import "./ha-menu";
@customElement("ha-button-menu")
export class HaButtonMenu extends LitElement {
@ -31,7 +31,7 @@ export class HaButtonMenu extends LitElement {
@property({ type: Boolean, attribute: "no-anchor" }) public noAnchor = false;
@query("mwc-menu", true) private _menu?: Menu;
@query("ha-menu", true) private _menu?: Menu;
public get items() {
return this._menu?.items;
@ -54,7 +54,7 @@ export class HaButtonMenu extends LitElement {
<div @click=${this._handleClick}>
<slot name="trigger" @slotchange=${this._setTriggerAria}></slot>
</div>
<mwc-menu
<ha-menu
.corner=${this.corner}
.menuCorner=${this.menuCorner}
.fixed=${this.fixed}
@ -64,7 +64,7 @@ export class HaButtonMenu extends LitElement {
.x=${this.x}
>
<slot></slot>
</mwc-menu>
</ha-menu>
`;
}
@ -73,7 +73,7 @@ export class HaButtonMenu extends LitElement {
if (mainWindow.document.dir === "rtl") {
this.updateComplete.then(() => {
this.querySelectorAll("mwc-list-item").forEach((item) => {
this.querySelectorAll("ha-list-item").forEach((item) => {
const style = document.createElement("style");
style.innerHTML =
"span.material-icons:first-of-type { margin-left: var(--mdc-list-item-graphic-margin, 32px) !important; margin-right: 0px !important;}";
@ -93,7 +93,7 @@ export class HaButtonMenu extends LitElement {
private get _triggerButton() {
return this.querySelector(
'ha-icon-button[slot="trigger"], mwc-button[slot="trigger"]'
'ha-icon-button[slot="trigger"], ha-button[slot="trigger"], mwc-button[slot="trigger"]'
) as HaIconButton | Button | null;
}

View File

@ -1,6 +1,6 @@
import { css } from "lit";
import { customElement, property } from "lit/decorators";
import { HaMdListItem } from "./ha-md-list-item";
import { HaMdListItem, haMdListStyles } from "./ha-md-list-item";
@customElement("ha-combo-box-item")
export class HaComboBoxItem extends HaMdListItem {
@ -8,7 +8,7 @@ export class HaComboBoxItem extends HaMdListItem {
public borderTop = false;
static override styles = [
...super.styles,
...haMdListStyles,
css`
:host {
--md-list-item-one-line-container-height: 48px;

View File

@ -12,6 +12,7 @@ import type { HaIcon } from "./ha-icon";
import "./ha-ripple";
import "./ha-svg-icon";
import type { HaSvgIcon } from "./ha-svg-icon";
import "./ha-menu";
@customElement("ha-control-select-menu")
export class HaControlSelectMenu extends SelectBase {
@ -91,6 +92,27 @@ export class HaControlSelectMenu extends SelectBase {
`;
}
protected override renderMenu() {
const classes = this.getMenuClasses();
return html`<ha-menu
innerRole="listbox"
wrapFocus
class=${classMap(classes)}
activatable
.fullwidth=${this.fixedMenuPosition ? false : !this.naturalMenuWidth}
.open=${this.menuOpen}
.anchor=${this.anchorElement}
.fixed=${this.fixedMenuPosition}
@selected=${this.onSelected}
@opened=${this.onOpened}
@closed=${this.onClosed}
@items-updated=${this.onItemsUpdated}
@keydown=${this.handleTypeahead}
>
${this.renderMenuContent()}
</ha-menu>`;
}
private _renderArrow() {
if (!this.showArrow) return nothing;
@ -240,13 +262,6 @@ export class HaControlSelectMenu extends SelectBase {
cursor: not-allowed;
color: var(--disabled-color);
}
mwc-menu {
--mdc-shape-medium: 8px;
}
mwc-list {
--mdc-list-vertical-padding: 0;
}
`,
];
}

View File

@ -1,7 +1,7 @@
import "@material/mwc-button/mwc-button";
import "@material/mwc-list/mwc-list";
import type { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
import "@material/mwc-list/mwc-list-item";
import { mdiCalendar } from "@mdi/js";
import { isThisYear } from "date-fns";
import { fromZonedTime, toZonedTime } from "date-fns-tz";
@ -10,6 +10,8 @@ import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import { shiftDateRange } from "../common/datetime/calc_date";
import type { DateRange } from "../common/datetime/calc_date_range";
import { calcDateRange } from "../common/datetime/calc_date_range";
import { firstWeekdayIndex } from "../common/datetime/first_weekday";
import {
formatShortDateTime,
@ -23,9 +25,9 @@ import "./date-range-picker";
import "./ha-icon-button";
import "./ha-icon-button-next";
import "./ha-icon-button-prev";
import "./ha-list";
import "./ha-list-item";
import "./ha-textarea";
import { calcDateRange } from "../common/datetime/calc_date_range";
import type { DateRange } from "../common/datetime/calc_date_range";
export type DateRangePickerRanges = Record<string, [Date, Date]>;
@ -187,11 +189,11 @@ export class HaDateRangePicker extends LitElement {
</div>
${this.ranges !== false && (this.ranges || this._ranges)
? html`<div slot="ranges" class="date-range-ranges">
<mwc-list @action=${this._setDateRange} activatable>
<ha-list @action=${this._setDateRange} activatable>
${Object.keys(this.ranges || this._ranges!).map(
(name) => html`<mwc-list-item>${name}</mwc-list-item>`
(name) => html`<ha-list-item>${name}</ha-list-item>`
)}
</mwc-list>
</ha-list>
</div>`
: nothing}
<div slot="footer" class="date-range-footer">

View File

@ -1,6 +1,4 @@
import "@material/mwc-list/mwc-list";
import type { SelectedDetail } from "@material/mwc-list";
import "@material/mwc-menu/mwc-menu-surface";
import { mdiFilterVariantRemove } from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
@ -12,9 +10,10 @@ import type { RelatedResult } from "../data/search";
import { findRelated } from "../data/search";
import { haStyleScrollbar } from "../resources/styles";
import type { HomeAssistant } from "../types";
import "./ha-check-list-item";
import "./ha-expansion-panel";
import "./ha-icon-button";
import "./ha-check-list-item";
import "./ha-list";
@customElement("ha-filter-blueprints")
export class HaFilterBlueprints extends LitElement {
@ -62,7 +61,7 @@ export class HaFilterBlueprints extends LitElement {
</div>
${this._blueprints && this._shouldRender
? html`
<mwc-list
<ha-list
@selected=${this._blueprintsSelected}
multi
class="ha-scrollbar"
@ -77,7 +76,7 @@ export class HaFilterBlueprints extends LitElement {
${blueprint.metadata.name || id}
</ha-check-list-item>`
)}
</mwc-list>
</ha-list>
`
: nothing}
</ha-expansion-panel>
@ -95,7 +94,7 @@ export class HaFilterBlueprints extends LitElement {
if (changed.has("expanded") && this.expanded) {
setTimeout(() => {
if (this.narrow || !this.expanded) return;
this.renderRoot.querySelector("mwc-list")!.style.height =
this.renderRoot.querySelector("ha-list")!.style.height =
`${this.clientHeight - 49}px`;
}, 300);
}

View File

@ -1,5 +1,3 @@
import "@material/mwc-list/mwc-list";
import "@material/mwc-list/mwc-list-item";
import type { ActionDetail, SelectedDetail } from "@material/mwc-list";
import {
mdiDelete,
@ -30,6 +28,7 @@ import "./ha-expansion-panel";
import "./ha-icon";
import "./ha-button-menu";
import "./ha-list-item";
import "./ha-list";
import { stopPropagation } from "../common/dom/stop_propagation";
@customElement("ha-filter-categories")
@ -82,7 +81,7 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) {
</div>
${this._shouldRender
? html`
<mwc-list
<ha-list
@selected=${this._categorySelected}
class="ha-scrollbar"
activatable
@ -126,16 +125,16 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) {
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
<mwc-list-item graphic="icon"
<ha-list-item graphic="icon"
><ha-svg-icon
.path=${mdiPencil}
slot="graphic"
></ha-svg-icon
>${this.hass.localize(
"ui.panel.config.category.editor.edit"
)}</mwc-list-item
)}</ha-list-item
>
<mwc-list-item graphic="icon" class="warning"
<ha-list-item graphic="icon" class="warning"
><ha-svg-icon
class="warning"
.path=${mdiDelete}
@ -143,12 +142,12 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) {
></ha-svg-icon
>${this.hass.localize(
"ui.panel.config.category.editor.delete"
)}</mwc-list-item
)}</ha-list-item
>
</ha-button-menu>
</ha-list-item>`
)}
</mwc-list>
</ha-list>
`
: nothing}
</ha-expansion-panel>
@ -169,7 +168,7 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) {
if (changed.has("expanded") && this.expanded) {
setTimeout(() => {
if (!this.expanded) return;
this.renderRoot.querySelector("mwc-list")!.style.height =
this.renderRoot.querySelector("ha-list")!.style.height =
`${this.clientHeight - (49 + 48)}px`;
}, 300);
}
@ -312,7 +311,7 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) {
padding: 0px 2px;
color: var(--text-primary-color);
}
mwc-list {
ha-list {
--mdc-list-item-meta-size: auto;
--mdc-list-side-padding-right: 4px;
--mdc-icon-button-size: 36px;

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list";
import { mdiFilterVariantRemove } from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
@ -14,6 +13,7 @@ import { loadVirtualizer } from "../resources/virtualizer";
import type { HomeAssistant } from "../types";
import "./ha-check-list-item";
import "./ha-expansion-panel";
import "./ha-list";
import "./search-input-outlined";
@customElement("ha-filter-devices")
@ -68,7 +68,7 @@ export class HaFilterDevices extends LitElement {
@value-changed=${this._handleSearchChange}
>
</search-input-outlined>
<mwc-list class="ha-scrollbar" multi>
<ha-list class="ha-scrollbar" multi>
<lit-virtualizer
.items=${this._devices(
this.hass.devices,
@ -80,7 +80,7 @@ export class HaFilterDevices extends LitElement {
@click=${this._handleItemClick}
>
</lit-virtualizer>
</mwc-list>`
</ha-list>`
: nothing}
</ha-expansion-panel>
`;
@ -117,7 +117,7 @@ export class HaFilterDevices extends LitElement {
if (changed.has("expanded") && this.expanded) {
setTimeout(() => {
if (!this.expanded) return;
this.renderRoot.querySelector("mwc-list")!.style.height =
this.renderRoot.querySelector("ha-list")!.style.height =
`${this.clientHeight - 49 - 32}px`; // 32px is the height of the search input
}, 300);
}

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list";
import { mdiFilterVariantRemove } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
@ -6,15 +5,16 @@ import { customElement, property, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import memoizeOne from "memoize-one";
import { fireEvent } from "../common/dom/fire_event";
import { computeDomain } from "../common/entity/compute_domain";
import { stringCompare } from "../common/string/compare";
import { domainToName } from "../data/integration";
import { haStyleScrollbar } from "../resources/styles";
import type { HomeAssistant } from "../types";
import "./ha-check-list-item";
import "./ha-domain-icon";
import "./ha-expansion-panel";
import "./ha-check-list-item";
import "./ha-list";
import "./search-input-outlined";
import { computeDomain } from "../common/entity/compute_domain";
@customElement("ha-filter-domains")
export class HaFilterDomains extends LitElement {
@ -57,7 +57,7 @@ export class HaFilterDomains extends LitElement {
@value-changed=${this._handleSearchChange}
>
</search-input-outlined>
<mwc-list
<ha-list
class="ha-scrollbar"
@click=${this._handleItemClick}
multi
@ -80,7 +80,7 @@ export class HaFilterDomains extends LitElement {
${domainToName(this.hass.localize, domain)}
</ha-check-list-item>`
)}
</mwc-list> `
</ha-list> `
: nothing}
</ha-expansion-panel>
`;
@ -111,7 +111,7 @@ export class HaFilterDomains extends LitElement {
if (changed.has("expanded") && this.expanded) {
setTimeout(() => {
if (!this.expanded) return;
this.renderRoot.querySelector("mwc-list")!.style.height =
this.renderRoot.querySelector("ha-list")!.style.height =
`${this.clientHeight - 49 - 32}px`; // 32px is the height of the search input
}, 300);
}

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list";
import { mdiFilterVariantRemove } from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
@ -14,8 +13,9 @@ import { haStyleScrollbar } from "../resources/styles";
import { loadVirtualizer } from "../resources/virtualizer";
import type { HomeAssistant } from "../types";
import "./ha-check-list-item";
import "./ha-state-icon";
import "./ha-expansion-panel";
import "./ha-list";
import "./ha-state-icon";
import "./search-input-outlined";
@customElement("ha-filter-entities")
@ -71,7 +71,7 @@ export class HaFilterEntities extends LitElement {
@value-changed=${this._handleSearchChange}
>
</search-input-outlined>
<mwc-list class="ha-scrollbar" multi>
<ha-list class="ha-scrollbar" multi>
<lit-virtualizer
.items=${this._entities(
this.hass.states,
@ -84,7 +84,7 @@ export class HaFilterEntities extends LitElement {
@click=${this._handleItemClick}
>
</lit-virtualizer>
</mwc-list>
</ha-list>
`
: nothing}
</ha-expansion-panel>
@ -95,7 +95,7 @@ export class HaFilterEntities extends LitElement {
if (changed.has("expanded") && this.expanded) {
setTimeout(() => {
if (!this.expanded) return;
this.renderRoot.querySelector("mwc-list")!.style.height =
this.renderRoot.querySelector("ha-list")!.style.height =
`${this.clientHeight - 49 - 32}px`; // 32px is the height of the search input
}, 300);
}

View File

@ -1,5 +1,3 @@
import "@material/mwc-list/mwc-list";
import "@material/mwc-menu/mwc-menu-surface";
import { mdiFilterVariantRemove, mdiTextureBox } from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
@ -15,12 +13,13 @@ import { findRelated } from "../data/search";
import { haStyleScrollbar } from "../resources/styles";
import type { HomeAssistant } from "../types";
import "./ha-check-list-item";
import "./ha-expansion-panel";
import "./ha-floor-icon";
import "./ha-icon";
import "./ha-icon-button";
import "./ha-list";
import "./ha-svg-icon";
import "./ha-tree-indicator";
import "./ha-icon-button";
import "./ha-expansion-panel";
@customElement("ha-filter-floor-areas")
export class HaFilterFloorAreas extends LitElement {
@ -74,7 +73,7 @@ export class HaFilterFloorAreas extends LitElement {
</div>
${this._shouldRender
? html`
<mwc-list class="ha-scrollbar">
<ha-list class="ha-scrollbar">
${repeat(
areas?.floors || [],
(floor) => floor.floor_id,
@ -108,7 +107,7 @@ export class HaFilterFloorAreas extends LitElement {
(area) => area.area_id,
(area) => this._renderArea(area)
)}
</mwc-list>
</ha-list>
`
: nothing}
</ha-expansion-panel>
@ -183,7 +182,7 @@ export class HaFilterFloorAreas extends LitElement {
if (changed.has("expanded") && this.expanded) {
setTimeout(() => {
if (!this.expanded) return;
this.renderRoot.querySelector("mwc-list")!.style.height =
this.renderRoot.querySelector("ha-list")!.style.height =
`${this.clientHeight - 49}px`;
}, 300);
}

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list";
import { mdiFilterVariantRemove } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
@ -11,10 +10,11 @@ import type { IntegrationManifest } from "../data/integration";
import { fetchIntegrationManifests } from "../data/integration";
import { haStyleScrollbar } from "../resources/styles";
import type { HomeAssistant } from "../types";
import "./ha-domain-icon";
import "./search-input-outlined";
import "./ha-expansion-panel";
import "./ha-check-list-item";
import "./ha-domain-icon";
import "./ha-expansion-panel";
import "./ha-list";
import "./search-input-outlined";
@customElement("ha-filter-integrations")
export class HaFilterIntegrations extends LitElement {
@ -57,7 +57,7 @@ export class HaFilterIntegrations extends LitElement {
@value-changed=${this._handleSearchChange}
>
</search-input-outlined>
<mwc-list
<ha-list
class="ha-scrollbar"
@click=${this._handleItemClick}
multi
@ -82,7 +82,7 @@ export class HaFilterIntegrations extends LitElement {
${integration.name || integration.domain}
</ha-check-list-item>`
)}
</mwc-list> `
</ha-list> `
: nothing}
</ha-expansion-panel>
`;
@ -92,7 +92,7 @@ export class HaFilterIntegrations extends LitElement {
if (changed.has("expanded") && this.expanded) {
setTimeout(() => {
if (!this.expanded) return;
this.renderRoot.querySelector("mwc-list")!.style.height =
this.renderRoot.querySelector("ha-list")!.style.height =
`${this.clientHeight - 49 - 32}px`; // 32px is the height of the search input
}, 300);
}

View File

@ -1,16 +1,15 @@
import "@material/mwc-list/mwc-list";
import type { SelectedDetail } from "@material/mwc-list";
import "@material/mwc-menu/mwc-menu-surface";
import memoizeOne from "memoize-one";
import { mdiCog, mdiFilterVariantRemove } from "@mdi/js";
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { CSSResultGroup } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import memoizeOne from "memoize-one";
import { computeCssColor } from "../common/color/compute-color";
import { fireEvent } from "../common/dom/fire_event";
import { navigate } from "../common/navigate";
import { stringCompare } from "../common/string/compare";
import type { LabelRegistryEntry } from "../data/label_registry";
import { subscribeLabelRegistry } from "../data/label_registry";
import { SubscribeMixin } from "../mixins/subscribe-mixin";
@ -19,11 +18,11 @@ import type { HomeAssistant } from "../types";
import "./ha-check-list-item";
import "./ha-expansion-panel";
import "./ha-icon";
import "./ha-label";
import "./ha-icon-button";
import "./ha-label";
import "./ha-list";
import "./ha-list-item";
import "./search-input-outlined";
import { stringCompare } from "../common/string/compare";
@customElement("ha-filter-labels")
export class HaFilterLabels extends SubscribeMixin(LitElement) {
@ -93,7 +92,7 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) {
@value-changed=${this._handleSearchChange}
>
</search-input-outlined>
<mwc-list
<ha-list
@selected=${this._labelSelected}
class="ha-scrollbar"
multi
@ -122,7 +121,7 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) {
</ha-check-list-item>`;
}
)}
</mwc-list> `
</ha-list> `
: nothing}
</ha-expansion-panel>
${this.expanded
@ -142,7 +141,7 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) {
if (changed.has("expanded") && this.expanded) {
setTimeout(() => {
if (!this.expanded) return;
this.renderRoot.querySelector("mwc-list")!.style.height =
this.renderRoot.querySelector("ha-list")!.style.height =
`${this.clientHeight - (49 + 48 + 32)}px`;
}, 300);
}

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list";
import type { List, SelectedDetail } from "@material/mwc-list";
import { mdiFilterVariantRemove } from "@mdi/js";
import type { CSSResultGroup } from "lit";
@ -11,6 +10,7 @@ import "./ha-check-list-item";
import "./ha-expansion-panel";
import "./ha-icon";
import "./ha-icon-button";
import "./ha-list";
@customElement("ha-filter-states")
export class HaFilterStates extends LitElement {
@ -32,7 +32,7 @@ export class HaFilterStates extends LitElement {
@state() private _shouldRender = false;
@query("mwc-list") private _list!: List;
@query("ha-list") private _list!: List;
protected render() {
if (!this.states) {
@ -58,7 +58,7 @@ export class HaFilterStates extends LitElement {
</div>
${this._shouldRender
? html`
<mwc-list
<ha-list
@selected=${this._statesSelected}
multi
class="ha-scrollbar"
@ -79,7 +79,7 @@ export class HaFilterStates extends LitElement {
${item.label}
</ha-check-list-item>`
)}
</mwc-list>
</ha-list>
`
: nothing}
</ha-expansion-panel>

View File

@ -6,6 +6,7 @@ import { stopPropagation } from "../../common/dom/stop_propagation";
import type { LocalizeFunc } from "../../common/translations/localize";
import type { HomeAssistant } from "../../types";
import "./ha-form";
import "../ha-list-item";
import type {
HaFormOptionalActionsSchema,
HaFormDataContainer,

View File

@ -184,8 +184,8 @@ export class HaForm extends LitElement implements HaFormElement {
return context;
}
protected createRenderRoot() {
const root = super.createRenderRoot();
protected createRenderRoot(): HTMLElement | DocumentFragment {
const root = super.createRenderRoot() as ShadowRoot;
// attach it as soon as possible to make sure we fetch all events.
this.addValueChangedListener(root);
return root;

View File

@ -7,7 +7,6 @@ import { haStyle } from "../resources/styles";
import type { HomeAssistant } from "../types";
import "./ha-md-button-menu";
import "./ha-icon-button";
import "./ha-list-item";
import "./ha-svg-icon";
import "./ha-tooltip";
import "./ha-md-menu-item";

14
src/components/ha-list.ts Normal file
View File

@ -0,0 +1,14 @@
import { ListBase } from "@material/mwc-list/mwc-list-base";
import { styles } from "@material/mwc-list/mwc-list.css";
import { customElement } from "lit/decorators";
@customElement("ha-list")
export class HaList extends ListBase {
static styles = styles;
}
declare global {
interface HTMLElementTagNameMap {
"ha-list": HaList;
}
}

View File

@ -2,11 +2,11 @@ import type { Button } from "@material/mwc-button";
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property, query } from "lit/decorators";
import { FOCUS_TARGET } from "../dialogs/make-dialog-manager";
import { fireEvent } from "../common/dom/fire_event";
import { FOCUS_TARGET } from "../dialogs/make-dialog-manager";
import type { HaIconButton } from "./ha-icon-button";
import "./ha-menu";
import type { HaMenu } from "./ha-menu";
import "./ha-md-menu";
import type { HaMdMenu } from "./ha-md-menu";
@customElement("ha-md-button-menu")
export class HaMdButtonMenu extends LitElement {
@ -19,7 +19,7 @@ export class HaMdButtonMenu extends LitElement {
@property({ type: Boolean, attribute: "has-overflow" }) public hasOverflow =
false;
@query("ha-menu", true) private _menu!: HaMenu;
@query("ha-menu", true) private _menu!: HaMdMenu;
public get items() {
return this._menu.items;
@ -38,14 +38,14 @@ export class HaMdButtonMenu extends LitElement {
<div @click=${this._handleClick}>
<slot name="trigger" @slotchange=${this._setTriggerAria}></slot>
</div>
<ha-menu
<ha-md-menu
.positioning=${this.positioning}
.hasOverflow=${this.hasOverflow}
@opening=${this._handleOpening}
@closing=${this._handleClosing}
>
<slot></slot>
</ha-menu>
</ha-md-menu>
`;
}

View File

@ -1,4 +1,5 @@
import { MdDialog } from "@material/web/dialog/dialog";
import { Dialog } from "@material/web/dialog/internal/dialog";
import { styles } from "@material/web/dialog/internal/dialog-styles";
import {
type DialogAnimation,
DIALOG_DEFAULT_CLOSE_ANIMATION,
@ -8,10 +9,10 @@ import { css } from "lit";
import { customElement, property } from "lit/decorators";
// workaround to be able to overlay a dialog with another dialog
MdDialog.addInitializer(async (instance) => {
Dialog.addInitializer(async (instance) => {
await instance.updateComplete;
const dialogInstance = instance as MdDialog;
const dialogInstance = instance as HaMdDialog;
// @ts-expect-error dialog is private
dialogInstance.dialog.prepend(dialogInstance.scrim);
@ -49,7 +50,7 @@ let DIALOG_POLYFILL: Promise<typeof import("dialog-polyfill")>;
*
*/
@customElement("ha-md-dialog")
export class HaMdDialog extends MdDialog {
export class HaMdDialog extends Dialog {
/**
* When true the dialog will not close when the user presses the esc key or press out of the dialog.
*/
@ -146,7 +147,7 @@ export class HaMdDialog extends MdDialog {
}
static override styles = [
...super.styles,
styles,
css`
:host {
--md-dialog-container-color: var(--card-background-color);

View File

@ -1,11 +1,12 @@
import { MdDivider } from "@material/web/divider/divider";
import { Divider } from "@material/web/divider/internal/divider";
import { styles } from "@material/web/divider/internal/divider-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-md-divider")
export class HaMdDivider extends MdDivider {
export class HaMdDivider extends Divider {
static override styles = [
...super.styles,
styles,
css`
:host {
--md-divider-color: var(--divider-color);

View File

@ -1,26 +1,29 @@
import { MdListItem } from "@material/web/list/list-item";
import { ListItemEl } from "@material/web/list/internal/listitem/list-item";
import { styles } from "@material/web/list/internal/listitem/list-item-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
export const haMdListStyles = [
styles,
css`
:host {
--ha-icon-display: block;
--md-sys-color-primary: var(--primary-text-color);
--md-sys-color-secondary: var(--secondary-text-color);
--md-sys-color-surface: var(--card-background-color);
--md-sys-color-on-surface: var(--primary-text-color);
--md-sys-color-on-surface-variant: var(--secondary-text-color);
}
md-item {
overflow: var(--md-item-overflow, hidden);
align-items: var(--md-item-align-items, center);
}
`,
];
@customElement("ha-md-list-item")
export class HaMdListItem extends MdListItem {
static override styles = [
...super.styles,
css`
:host {
--ha-icon-display: block;
--md-sys-color-primary: var(--primary-text-color);
--md-sys-color-secondary: var(--secondary-text-color);
--md-sys-color-surface: var(--card-background-color);
--md-sys-color-on-surface: var(--primary-text-color);
--md-sys-color-on-surface-variant: var(--secondary-text-color);
}
md-item {
overflow: var(--md-item-overflow, hidden);
align-items: var(--md-item-align-items, center);
}
`,
];
export class HaMdListItem extends ListItemEl {
static override styles = haMdListStyles;
}
declare global {

View File

@ -1,11 +1,12 @@
import { MdList } from "@material/web/list/list";
import { List } from "@material/web/list/internal/list";
import { styles } from "@material/web/list/internal/list-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-md-list")
export class HaMdList extends MdList {
export class HaMdList extends List {
static override styles = [
...super.styles,
styles,
css`
:host {
--md-sys-color-surface: var(--card-background-color);

View File

@ -1,13 +1,14 @@
import { MdMenuItem } from "@material/web/menu/menu-item";
import { MenuItemEl } from "@material/web/menu/internal/menuitem/menu-item";
import { styles } from "@material/web/menu/internal/menuitem/menu-item-styles";
import { css } from "lit";
import { customElement, property } from "lit/decorators";
@customElement("ha-md-menu-item")
export class HaMdMenuItem extends MdMenuItem {
export class HaMdMenuItem extends MenuItemEl {
@property({ attribute: false }) clickAction?: (item?: HTMLElement) => void;
static override styles = [
...super.styles,
styles,
css`
:host {
--ha-icon-display: block;

View File

@ -0,0 +1,47 @@
import { Menu } from "@material/web/menu/internal/menu";
import { styles } from "@material/web/menu/internal/menu-styles";
import type { CloseMenuEvent } from "@material/web/menu/menu";
import {
CloseReason,
KeydownCloseKey,
} from "@material/web/menu/internal/controllers/shared";
import { css } from "lit";
import { customElement } from "lit/decorators";
import type { HaMdMenuItem } from "./ha-md-menu-item";
@customElement("ha-md-menu")
export class HaMdMenu extends Menu {
connectedCallback(): void {
super.connectedCallback();
this.addEventListener("close-menu", this._handleCloseMenu);
}
private _handleCloseMenu(ev: CloseMenuEvent) {
if (
ev.detail.reason.kind === CloseReason.KEYDOWN &&
ev.detail.reason.key === KeydownCloseKey.ESCAPE
) {
return;
}
(ev.detail.initiator as HaMdMenuItem).clickAction?.(ev.detail.initiator);
}
static override styles = [
styles,
css`
:host {
--md-sys-color-surface-container: var(--card-background-color);
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
"ha-md-menu": HaMdMenu;
}
interface HTMLElementEventMap {
"close-menu": CloseMenuEvent;
}
}

View File

@ -1,11 +1,12 @@
import { MdSelectOption } from "@material/web/select/select-option";
import { SelectOptionEl } from "@material/web/select/internal/selectoption/select-option";
import { styles } from "@material/web/menu/internal/menuitem/menu-item-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-md-select-option")
export class HaMdSelectOption extends MdSelectOption {
export class HaMdSelectOption extends SelectOptionEl {
static override styles = [
...super.styles,
styles,
css`
:host {
--ha-icon-display: block;

View File

@ -1,11 +1,14 @@
import { MdFilledSelect } from "@material/web/select/filled-select";
import { FilledSelect } from "@material/web/select/internal/filled-select";
import { styles as sharedStyles } from "@material/web/select/internal/shared-styles";
import { styles } from "@material/web/select/internal/filled-select-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-md-select")
export class HaMdSelect extends MdFilledSelect {
export class HaMdSelect extends FilledSelect {
static override styles = [
...super.styles,
sharedStyles,
styles,
css`
:host {
--ha-icon-display: block;

View File

@ -1,11 +1,14 @@
import { MdFilledTextField } from "@material/web/textfield/filled-text-field";
import { styles } from "@material/web/textfield/internal/filled-styles";
import { FilledTextField } from "@material/web/textfield/internal/filled-text-field";
import { styles as sharedStyles } from "@material/web/textfield/internal/shared-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-md-textfield")
export class HaMdTextfield extends MdFilledTextField {
export class HaMdTextfield extends FilledTextField {
static override styles = [
...super.styles,
sharedStyles,
styles,
css`
:host {
--ha-icon-display: block;

View File

@ -1,46 +1,45 @@
import { MdMenu } from "@material/web/menu/menu";
import type { CloseMenuEvent } from "@material/web/menu/menu";
import {
CloseReason,
KeydownCloseKey,
} from "@material/web/menu/internal/controllers/shared";
import { css } from "lit";
import { MenuBase } from "@material/mwc-menu/mwc-menu-base";
import { styles } from "@material/mwc-menu/mwc-menu.css";
import { html } from "lit";
import { customElement } from "lit/decorators";
import type { HaMdMenuItem } from "./ha-md-menu-item";
import { classMap } from "lit/directives/class-map";
import "./ha-list";
@customElement("ha-menu")
export class HaMenu extends MdMenu {
connectedCallback(): void {
super.connectedCallback();
this.addEventListener("close-menu", this._handleCloseMenu);
}
private _handleCloseMenu(ev: CloseMenuEvent) {
if (
ev.detail.reason.kind === CloseReason.KEYDOWN &&
ev.detail.reason.key === KeydownCloseKey.ESCAPE
) {
return;
export class HaMenu extends MenuBase {
protected get listElement() {
if (!this.listElement_) {
this.listElement_ = this.renderRoot.querySelector("ha-list");
return this.listElement_;
}
(ev.detail.initiator as HaMdMenuItem).clickAction?.(ev.detail.initiator);
return this.listElement_;
}
static override styles = [
...super.styles,
css`
:host {
--md-sys-color-surface-container: var(--card-background-color);
}
`,
];
protected renderList() {
const itemRoles = this.innerRole === "menu" ? "menuitem" : "option";
const classes = this.renderListClasses();
return html`<ha-list
rootTabbable
.innerAriaLabel=${this.innerAriaLabel}
.innerRole=${this.innerRole}
.multi=${this.multi}
class=${classMap(classes)}
.itemRoles=${itemRoles}
.wrapFocus=${this.wrapFocus}
.activatable=${this.activatable}
@action=${this.onAction}
>
<slot></slot>
</ha-list>`;
}
static styles = styles;
}
declare global {
interface HTMLElementTagNameMap {
"ha-menu": HaMenu;
}
interface HTMLElementEventMap {
"close-menu": CloseMenuEvent;
}
}

View File

@ -5,7 +5,6 @@ import { ifDefined } from "lit/directives/if-defined";
import type { PageNavigation } from "../layouts/hass-tabs-subpage";
import type { HomeAssistant } from "../types";
import "./ha-icon-next";
import "./ha-list-item";
import "./ha-svg-icon";
import "./ha-md-list";
import "./ha-md-list-item";

View File

@ -1,11 +1,14 @@
import { MdOutlinedButton } from "@material/web/button/outlined-button";
import { OutlinedButton } from "@material/web/button/internal/outlined-button";
import { styles as sharedStyles } from "@material/web/button/internal/shared-styles";
import { styles } from "@material/web/button/internal/outlined-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-outlined-button")
export class HaOutlinedButton extends MdOutlinedButton {
export class HaOutlinedButton extends OutlinedButton {
static override styles = [
...super.styles,
sharedStyles,
styles,
css`
:host {
--ha-icon-display: block;

View File

@ -1,14 +1,17 @@
import { MdOutlinedField } from "@material/web/field/outlined-field";
import { OutlinedField } from "@material/web/field/internal/outlined-field";
import { styles } from "@material/web/field/internal/outlined-styles";
import { styles as sharedStyles } from "@material/web/field/internal/shared-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
import { literal } from "lit/static-html";
@customElement("ha-outlined-field")
export class HaOutlinedField extends MdOutlinedField {
export class HaOutlinedField extends OutlinedField {
protected readonly fieldTag = literal`ha-outlined-field`;
static override styles = [
...super.styles,
sharedStyles,
styles,
css`
.container::before {
display: block;

View File

@ -1,16 +1,19 @@
import { MdOutlinedIconButton } from "@material/web/iconbutton/outlined-icon-button";
import { IconButton } from "@material/web/iconbutton/internal/icon-button";
import { styles } from "@material/web/iconbutton/internal/outlined-styles";
import { styles as sharedStyles } from "@material/web/iconbutton/internal/shared-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-outlined-icon-button")
export class HaOutlinedIconButton extends MdOutlinedIconButton {
export class HaOutlinedIconButton extends IconButton {
static override styles = [
css`
.icon-button {
border-radius: var(--_container-shape);
}
`,
...super.styles,
sharedStyles,
styles,
css`
:host {
--ha-icon-display: block;

View File

@ -1,15 +1,18 @@
import { MdOutlinedTextField } from "@material/web/textfield/outlined-text-field";
import { OutlinedTextField } from "@material/web/textfield/internal/outlined-text-field";
import { styles } from "@material/web/textfield/internal/outlined-styles";
import { styles as sharedStyles } from "@material/web/textfield/internal/shared-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
import { literal } from "lit/static-html";
import "./ha-outlined-field";
@customElement("ha-outlined-text-field")
export class HaOutlinedTextField extends MdOutlinedTextField {
export class HaOutlinedTextField extends OutlinedTextField {
protected readonly fieldTag = literal`ha-outlined-field`;
static override styles = [
...super.styles,
sharedStyles,
styles,
css`
:host {
--md-sys-color-on-surface: var(--primary-text-color);

View File

@ -0,0 +1,52 @@
import { css } from "lit";
import { RadioListItemBase } from "@material/mwc-list/mwc-radio-list-item-base";
import { styles as controlStyles } from "@material/mwc-list/mwc-control-list-item.css";
import { styles } from "@material/mwc-list/mwc-list-item.css";
import { customElement } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
@customElement("ha-radio-list-item")
export class HaRadioListItem extends RadioListItemBase {
async onChange(event) {
super.onChange(event);
fireEvent(this, event.type);
}
static override styles = [
styles,
controlStyles,
css`
:host {
--mdc-theme-secondary: var(--primary-color);
}
:host([graphic="avatar"]) .mdc-deprecated-list-item__graphic,
:host([graphic="medium"]) .mdc-deprecated-list-item__graphic,
:host([graphic="large"]) .mdc-deprecated-list-item__graphic,
:host([graphic="control"]) .mdc-deprecated-list-item__graphic {
margin-inline-end: var(--mdc-list-item-graphic-margin, 16px);
margin-inline-start: 0px;
direction: var(--direction);
}
.mdc-deprecated-list-item__meta {
flex-shrink: 0;
direction: var(--direction);
margin-inline-start: auto;
margin-inline-end: 0;
}
.mdc-deprecated-list-item__graphic {
margin-top: var(--radio-list-item-graphic-margin-top);
}
:host([graphic="icon"]) .mdc-deprecated-list-item__graphic {
margin-inline-start: 0;
margin-inline-end: var(--mdc-list-item-graphic-margin, 32px);
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
"ha-radio-list-item": HaRadioListItem;
}
}

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list";
import {
mdiAlertCircleOutline,
mdiDevices,
@ -25,6 +24,7 @@ import "./ha-icon-next";
import "./ha-list-item";
import "./ha-state-icon";
import "./ha-switch";
import "./ha-list";
@customElement("ha-related-items")
export class HaRelatedItems extends LitElement {
@ -132,7 +132,7 @@ export class HaRelatedItems extends LitElement {
}
if (Object.keys(this._related).length === 0) {
return html`
<mwc-list>
<ha-list>
<ha-list-item hasMeta graphic="icon" noninteractive>
<ha-svg-icon
.path=${mdiAlertCircleOutline}
@ -142,7 +142,7 @@ export class HaRelatedItems extends LitElement {
"ui.components.related-items.no_related_found"
)}
</ha-list-item>
</mwc-list>
</ha-list>
`;
}
@ -156,7 +156,7 @@ export class HaRelatedItems extends LitElement {
? html`<h3>
${this.hass.localize("ui.components.related-items.integration")}
</h3>
<mwc-list
<ha-list
>${configEntries?.map((entry) => {
if (!entry) {
return nothing;
@ -209,14 +209,14 @@ export class HaRelatedItems extends LitElement {
</ha-list-item>
</a>`
)}
</mwc-list>`
</ha-list>`
: nothing}
${this._related.area
? html`<h3>
${this.hass.localize("ui.components.related-items.area")}
</h3>
<mwc-list>
${this._related.area.map((relatedAreaId) => {
<ha-list
>${this._related.area.map((relatedAreaId) => {
const area = this.hass.areas[relatedAreaId];
if (!area) {
return nothing;
@ -250,13 +250,13 @@ export class HaRelatedItems extends LitElement {
</a>
`;
})}
</mwc-list>`
</ha-list>`
: nothing}
${this._related.device
? html`<h3>
${this.hass.localize("ui.components.related-items.device")}
</h3>
<mwc-list>
<ha-list>
${this._related.device.map((relatedDeviceId) => {
const device = this.hass.devices[relatedDeviceId];
if (!device) {
@ -275,12 +275,12 @@ export class HaRelatedItems extends LitElement {
</a>
`;
})}
</mwc-list>`
</ha-list>`
: nothing}
${this._related.entity
? html`
<h3>${this.hass.localize("ui.components.related-items.entity")}</h3>
<mwc-list>
<ha-list>
${this._relatedEntities(this._related.entity).map(
(entity) => html`
<ha-list-item
@ -299,13 +299,13 @@ export class HaRelatedItems extends LitElement {
</ha-list-item>
`
)}
</mwc-list>
</ha-list>
`
: nothing}
${this._related.group
? html`
<h3>${this.hass.localize("ui.components.related-items.group")}</h3>
<mwc-list>
<ha-list>
${this._relatedGroups(this._related.group).map(
(group) => html`
<ha-list-item
@ -324,13 +324,13 @@ export class HaRelatedItems extends LitElement {
</ha-list-item>
`
)}
</mwc-list>
</ha-list>
`
: nothing}
${this._related.scene
? html`
<h3>${this.hass.localize("ui.components.related-items.scene")}</h3>
<mwc-list>
<ha-list>
${this._relatedScenes(this._related.scene).map(
(scene) => html`
<ha-list-item
@ -349,7 +349,7 @@ export class HaRelatedItems extends LitElement {
</ha-list-item>
`
)}
</mwc-list>
</ha-list>
`
: nothing}
${this._related.automation_blueprint
@ -357,7 +357,7 @@ export class HaRelatedItems extends LitElement {
<h3>
${this.hass.localize("ui.components.related-items.blueprint")}
</h3>
<mwc-list>
<ha-list>
${this._related.automation_blueprint.map((path) => {
const blueprintMeta = this._blueprints
? this._blueprints.automation[path]
@ -375,7 +375,7 @@ export class HaRelatedItems extends LitElement {
</ha-list-item>
</a>`;
})}
</mwc-list>
</ha-list>
`
: nothing}
${this._related.automation
@ -383,7 +383,7 @@ export class HaRelatedItems extends LitElement {
<h3>
${this.hass.localize("ui.components.related-items.automation")}
</h3>
<mwc-list>
<ha-list>
${this._relatedAutomations(this._related.automation).map(
(automation) => html`
<ha-list-item
@ -403,7 +403,7 @@ export class HaRelatedItems extends LitElement {
</ha-list-item>
`
)}
</mwc-list>
</ha-list>
`
: nothing}
${this._related.script_blueprint
@ -411,7 +411,7 @@ export class HaRelatedItems extends LitElement {
<h3>
${this.hass.localize("ui.components.related-items.blueprint")}
</h3>
<mwc-list>
<ha-list>
${this._related.script_blueprint.map((path) => {
const blueprintMeta = this._blueprints
? this._blueprints.script[path]
@ -429,13 +429,13 @@ export class HaRelatedItems extends LitElement {
</ha-list-item>
</a>`;
})}
</mwc-list>
</ha-list>
`
: nothing}
${this._related.script
? html`
<h3>${this.hass.localize("ui.components.related-items.script")}</h3>
<mwc-list>
<ha-list>
${this._relatedScripts(this._related.script).map(
(script) => html`
<ha-list-item
@ -454,7 +454,7 @@ export class HaRelatedItems extends LitElement {
</ha-list-item>
`
)}
</mwc-list>
</ha-list>
`
: nothing}
`;

View File

@ -1,10 +1,11 @@
import { AttachableController } from "@material/web/internal/controller/attachable-controller";
import { MdRipple } from "@material/web/ripple/ripple";
import { Ripple } from "@material/web/ripple/internal/ripple";
import { styles } from "@material/web/ripple/internal/ripple-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-ripple")
export class HaRipple extends MdRipple {
export class HaRipple extends Ripple {
private readonly attachableTouchController = new AttachableController(
this,
this._onTouchControlChange.bind(this)
@ -37,7 +38,7 @@ export class HaRipple extends MdRipple {
}
static override styles = [
...super.styles,
styles,
css`
:host {
--md-ripple-hover-opacity: var(--ha-ripple-hover-opacity, 0.08);

View File

@ -3,9 +3,11 @@ import { styles } from "@material/mwc-select/mwc-select.css";
import { mdiClose } from "@mdi/js";
import { css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { debounce } from "../common/util/debounce";
import { nextRender } from "../common/util/render-status";
import "./ha-icon-button";
import "./ha-menu";
@customElement("ha-select")
export class HaSelect extends SelectBase {
@ -32,6 +34,27 @@ export class HaSelect extends SelectBase {
`;
}
protected override renderMenu() {
const classes = this.getMenuClasses();
return html`<ha-menu
innerRole="listbox"
wrapFocus
class=${classMap(classes)}
activatable
.fullwidth=${this.fixedMenuPosition ? false : !this.naturalMenuWidth}
.open=${this.menuOpen}
.anchor=${this.anchorElement}
.fixed=${this.fixedMenuPosition}
@selected=${this.onSelected}
@opened=${this.onOpened}
@closed=${this.onClosed}
@items-updated=${this.onItemsUpdated}
@keydown=${this.handleTypeahead}
>
${this.renderMenuContent()}
</ha-menu>`;
}
protected override renderLeadingIcon() {
if (!this.icon) {
return nothing;

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list-item";
import { LitElement, css, html } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list-item";
import { mdiDrag } from "@mdi/js";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query } from "lit/decorators";
@ -16,10 +15,11 @@ import "../ha-combo-box";
import type { HaComboBox } from "../ha-combo-box";
import "../ha-formfield";
import "../ha-input-helper-text";
import "../ha-list-item";
import "../ha-radio";
import "../ha-select";
import "../ha-sortable";
import "../ha-select-box";
import "../ha-sortable";
@customElement("ha-selector-select")
export class HaSelectSelector extends LitElement {
@ -274,8 +274,8 @@ export class HaSelectSelector extends LitElement {
>
${options.map(
(item: SelectOption) => html`
<mwc-list-item .value=${item.value} .disabled=${item.disabled}
>${item.label}</mwc-list-item
<ha-list-item .value=${item.value} .disabled=${item.disabled}
>${item.label}</ha-list-item
>
`
)}
@ -420,11 +420,10 @@ export class HaSelectSelector extends LitElement {
position: relative;
}
ha-select,
mwc-formfield,
ha-formfield {
display: block;
}
mwc-list-item[disabled] {
ha-list-item[disabled] {
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
}
ha-chip-set {

View File

@ -1,17 +1,18 @@
import { MdSlider } from "@material/web/slider/slider";
import { Slider } from "@material/web/slider/internal/slider";
import { styles } from "@material/web/slider/internal/slider-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
import { mainWindow } from "../common/dom/get_main_window";
@customElement("ha-slider")
export class HaSlider extends MdSlider {
export class HaSlider extends Slider {
public connectedCallback() {
super.connectedCallback();
this.dir = mainWindow.document.dir;
}
static override styles = [
...super.styles,
styles,
css`
:host {
--md-sys-color-primary: var(--primary-color);

View File

@ -1,16 +1,17 @@
import { MdSubMenu } from "@material/web/menu/sub-menu";
import { SubMenu } from "@material/web/menu/internal/submenu/sub-menu";
import { styles } from "@material/web/menu/internal/submenu/sub-menu-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-sub-menu")
export class HaSubMenu extends MdSubMenu {
export class HaSubMenu extends SubMenu {
async show() {
super.show();
this.menu.hasOverflow = false;
}
static override styles = [
...super.styles,
styles,
css`
:host {
--ha-icon-display: block;

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list-item";
import type { TemplateResult } from "lit";
import { css, html, nothing, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
@ -6,6 +5,7 @@ import { fireEvent } from "../common/dom/fire_event";
import { stopPropagation } from "../common/dom/stop_propagation";
import type { HomeAssistant } from "../types";
import "./ha-select";
import "./ha-list-item";
const DEFAULT_THEME = "default";
@ -39,23 +39,23 @@ export class HaThemePicker extends LitElement {
>
${!this.required
? html`
<mwc-list-item value="remove">
<ha-list-item value="remove">
${this.hass!.localize("ui.components.theme-picker.no_theme")}
</mwc-list-item>
</ha-list-item>
`
: nothing}
${this.includeDefault
? html`
<mwc-list-item .value=${DEFAULT_THEME}>
<ha-list-item .value=${DEFAULT_THEME}>
Home Assistant
</mwc-list-item>
</ha-list-item>
`
: nothing}
${Object.keys(this.hass!.themes.themes)
.sort()
.map(
(theme) =>
html`<mwc-list-item .value=${theme}>${theme}</mwc-list-item>`
html`<ha-list-item .value=${theme}>${theme}</ha-list-item>`
)}
</ha-select>
`;

View File

@ -1,36 +1,36 @@
import { animate } from "@lit-labs/motion";
import "@material/mwc-list/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { mdiClose, mdiDelete } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { fireEvent } from "../../common/dom/fire_event";
import { computeRTLDirection } from "../../common/util/compute_rtl";
import { deleteImage, getIdFromUrl } from "../../data/image_upload";
import type { MediaPlayerItem } from "../../data/media-player";
import { MediaClassBrowserSettings } from "../../data/media-player";
import {
browseLocalMediaPlayer,
removeLocalMedia,
isLocalMediaSourceContentId,
isImageUploadMediaSourceContentId,
isLocalMediaSourceContentId,
removeLocalMedia,
} from "../../data/media_source";
import { deleteImage, getIdFromUrl } from "../../data/image_upload";
import { showConfirmationDialog } from "../../dialogs/generic/show-dialog-box";
import { haStyleDialog } from "../../resources/styles";
import type { HomeAssistant } from "../../types";
import "../ha-button";
import "../ha-check-list-item";
import "../ha-spinner";
import "../ha-dialog";
import "../ha-dialog-header";
import "../ha-list";
import "../ha-spinner";
import "../ha-svg-icon";
import "../ha-tip";
import "./ha-media-player-browse";
import "./ha-media-upload-button";
import type { MediaManageDialogParams } from "./show-media-manage-dialog";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
@customElement("dialog-media-manage")
class DialogMediaManage extends LitElement {
@ -170,7 +170,7 @@ class DialogMediaManage extends LitElement {
: ""}
</div>`
: html`
<mwc-list multi @selected=${this._handleSelected}>
<ha-list multi @selected=${this._handleSelected}>
${repeat(
children,
(item) => item.media_content_id,
@ -201,7 +201,7 @@ class DialogMediaManage extends LitElement {
`;
}
)}
</mwc-list>
</ha-list>
`}
${isComponentLoaded(this.hass, "hassio")
? html`<ha-tip .hass=${this.hass}>

View File

@ -12,6 +12,7 @@ import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import type { HASSDomEvent } from "../../common/dom/fire_event";
import { fireEvent } from "../../common/dom/fire_event";
import { stopPropagation } from "../../common/dom/stop_propagation";
import type {
MediaPickedEvent,
MediaPlayerBrowseAction,
@ -22,6 +23,7 @@ import { haStyleDialog } from "../../resources/styles";
import type { HomeAssistant } from "../../types";
import "../ha-dialog";
import "../ha-dialog-header";
import "../ha-list-item";
import "./ha-media-manage-button";
import "./ha-media-player-browse";
import type {
@ -29,7 +31,6 @@ import type {
MediaPlayerItemId,
} from "./ha-media-player-browse";
import type { MediaPlayerBrowseDialogParams } from "./show-media-browser-dialog";
import { stopPropagation } from "../../common/dom/stop_propagation";
@customElement("dialog-media-player-browse")
class DialogMediaPlayerBrowse extends LitElement {
@ -118,7 +119,7 @@ class DialogMediaPlayerBrowse extends LitElement {
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<mwc-list-item graphic="icon">
<ha-list-item graphic="icon">
${this.hass.localize("ui.components.media-browser.auto")}
<ha-svg-icon
class=${this._preferredLayout === "auto"
@ -127,8 +128,8 @@ class DialogMediaPlayerBrowse extends LitElement {
slot="graphic"
.path=${mdiAlphaABoxOutline}
></ha-svg-icon>
</mwc-list-item>
<mwc-list-item graphic="icon">
</ha-list-item>
<ha-list-item graphic="icon">
${this.hass.localize("ui.components.media-browser.grid")}
<ha-svg-icon
class=${this._preferredLayout === "grid"
@ -137,8 +138,8 @@ class DialogMediaPlayerBrowse extends LitElement {
slot="graphic"
.path=${mdiGrid}
></ha-svg-icon>
</mwc-list-item>
<mwc-list-item graphic="icon">
</ha-list-item>
<ha-list-item graphic="icon">
${this.hass.localize("ui.components.media-browser.list")}
<ha-svg-icon
slot="graphic"
@ -147,7 +148,7 @@ class DialogMediaPlayerBrowse extends LitElement {
: ""}
.path=${mdiListBoxOutline}
></ha-svg-icon>
</mwc-list-item>
</ha-list-item>
</ha-button-menu>
<ha-icon-button
.label=${this.hass.localize("ui.common.close")}

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list-item";
import "@material/mwc-button/mwc-button";
import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
@ -48,7 +47,7 @@ class BrowseMediaTTS extends LitElement {
state: true,
subscribe: false,
})
private _message!: string;
private _message?: string;
protected render() {
return html`<ha-card>

View File

@ -1,8 +1,7 @@
import type { LitVirtualizer } from "@lit-labs/virtualizer";
import { grid } from "@lit-labs/virtualizer/layouts/grid";
import "@material/mwc-button/mwc-button";
import "@material/mwc-list/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { mdiArrowUpRight, mdiPlay, mdiPlus } from "@mdi/js";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
@ -50,6 +49,8 @@ import "../ha-fab";
import "../ha-icon-button";
import "../ha-svg-icon";
import "../ha-tooltip";
import "../ha-list";
import "../ha-list-item";
import "./ha-browse-media-tts";
import type { TtsMediaPickedEvent } from "./ha-browse-media-tts";
import { loadVirtualizer } from "../../resources/virtualizer";
@ -516,7 +517,7 @@ export class HaMediaPlayerBrowse extends LitElement {
: ""}
`
: html`
<mwc-list>
<ha-list>
<lit-virtualizer
scroller
.items=${children}
@ -527,7 +528,7 @@ export class HaMediaPlayerBrowse extends LitElement {
></lit-virtualizer>
${currentItem.not_shown
? html`
<mwc-list-item
<ha-list-item
noninteractive
class="not-shown"
.graphic=${mediaClass.show_list_images
@ -540,10 +541,10 @@ export class HaMediaPlayerBrowse extends LitElement {
{ count: currentItem.not_shown }
)}
</span>
</mwc-list-item>
</ha-list-item>
`
: ""}
</mwc-list>
</ha-list>
`
}
</div>
@ -623,7 +624,7 @@ export class HaMediaPlayerBrowse extends LitElement {
: "none";
return html`
<mwc-list-item
<ha-list-item
@click=${this._childClicked}
.item=${child}
.graphic=${mediaClass.show_list_images ? "medium" : "avatar"}
@ -660,7 +661,7 @@ export class HaMediaPlayerBrowse extends LitElement {
: nothing}
</div>`}
<span class="title">${child.title}</span>
</mwc-list-item>
</ha-list-item>
`;
};
@ -1001,22 +1002,22 @@ export class HaMediaPlayerBrowse extends LitElement {
/* ============= CHILDREN ============= */
mwc-list {
ha-list {
--mdc-list-vertical-padding: 0;
--mdc-list-item-graphic-margin: 0;
--mdc-theme-text-icon-on-background: var(--secondary-text-color);
margin-top: 10px;
}
mwc-list li:last-child {
ha-list li:last-child {
display: none;
}
mwc-list li[divider] {
ha-list li[divider] {
border-bottom-color: var(--divider-color);
}
mwc-list-item {
ha-list-item {
width: 100%;
}
@ -1152,7 +1153,7 @@ export class HaMediaPlayerBrowse extends LitElement {
padding-left: 16px;
}
mwc-list-item .graphic {
ha-list-item .graphic {
background-size: contain;
background-repeat: no-repeat;
background-position: center;
@ -1163,7 +1164,7 @@ export class HaMediaPlayerBrowse extends LitElement {
line-height: initial;
}
mwc-list-item .graphic .play {
ha-list-item .graphic .play {
opacity: 0;
transition: all 0.5s;
background-color: rgba(var(--rgb-card-background-color), 0.5);
@ -1171,17 +1172,17 @@ export class HaMediaPlayerBrowse extends LitElement {
--mdc-icon-button-size: 40px;
}
mwc-list-item:hover .graphic .play {
ha-list-item:hover .graphic .play {
opacity: 1;
color: var(--primary-text-color);
}
mwc-list-item .graphic .play.show {
ha-list-item .graphic .play.show {
opacity: 1;
background-color: transparent;
}
mwc-list-item .title {
ha-list-item .title {
margin-left: 16px;
margin-inline-start: 16px;
margin-inline-end: initial;

View File

@ -1,5 +1,5 @@
import { dump } from "js-yaml";
import { consume } from "@lit-labs/context";
import { consume } from "@lit/context";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";

View File

@ -1,4 +1,4 @@
import { consume } from "@lit-labs/context";
import { consume } from "@lit/context";
import {
mdiAlertCircle,
mdiCircle,

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list-item";
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { property } from "lit/decorators";
@ -46,10 +45,10 @@ class HaUserPicker extends LitElement {
@selected=${this._userChanged}
>
${this.users?.length === 0
? html`<mwc-list-item value="">
? html`<ha-list-item value="">
${this.noUserLabel ||
this.hass?.localize("ui.components.user-picker.no_user")}
</mwc-list-item>`
</ha-list-item>`
: ""}
${this._sortedUsers(this.users).map(
(user) => html`
@ -92,9 +91,6 @@ class HaUserPicker extends LitElement {
:host {
display: inline-block;
}
mwc-list {
display: block;
}
`;
}

View File

@ -1,4 +1,4 @@
import { createContext } from "@lit-labs/context";
import { createContext } from "@lit/context";
import type { HassConfig } from "home-assistant-js-websocket";
import type { HomeAssistant } from "../types";
import type { EntityRegistryEntry } from "./entity_registry";

View File

@ -1,20 +1,21 @@
import { format } from "date-fns";
import type { HassEntity } from "home-assistant-js-websocket";
import type { TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import { format } from "date-fns";
import { computeStateName } from "../../../common/entity/compute_state_name";
import "../../../components/entity/ha-entity-toggle";
import "../../../components/entity/state-badge";
import "../../../components/ha-climate-state";
import "../../../components/ha-cover-controls";
import "../../../components/ha-cover-tilt-controls";
import "../../../components/ha-date-input";
import "../../../components/ha-humidifier-state";
import "../../../components/ha-list-item";
import "../../../components/ha-select";
import "../../../components/ha-slider";
import "../../../components/ha-time-input";
import "../../../components/entity/ha-entity-toggle";
import "../../../components/entity/state-badge";
import { isTiltOnly } from "../../../data/cover";
import { isUnavailableState } from "../../../data/entity";
import type { ImageEntity } from "../../../data/image";
@ -293,9 +294,9 @@ class EntityPreviewRow extends LitElement {
${stateObj.attributes.options
? stateObj.attributes.options.map(
(option) => html`
<mwc-list-item .value=${option}>
<ha-list-item .value=${option}>
${this.hass!.formatEntityState(stateObj, option)}
</mwc-list-item>
</ha-list-item>
`
)
: ""}

View File

@ -1,13 +1,13 @@
import "@material/mwc-list/mwc-list-item";
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import "../../components/ha-icon-next";
import "../../components/ha-list-item";
import type { DataEntryFlowStepMenu } from "../../data/data_entry_flow";
import type { HomeAssistant } from "../../types";
import type { FlowConfig } from "./show-dialog-data-entry-flow";
import "../../components/ha-icon-next";
import { configFlowContentStyles } from "./styles";
import { fireEvent } from "../../common/dom/fire_event";
@customElement("step-flow-menu")
class StepFlowMenu extends LitElement {
@ -47,10 +47,10 @@ class StepFlowMenu extends LitElement {
<div class="options">
${options.map(
(option) => html`
<mwc-list-item hasMeta .step=${option} @click=${this._handleStep}>
<ha-list-item hasMeta .step=${option} @click=${this._handleStep}>
<span>${translations[option]}</span>
<ha-icon-next slot="meta"></ha-icon-next>
</mwc-list-item>
</ha-list-item>
`
)}
</div>
@ -83,7 +83,7 @@ class StepFlowMenu extends LitElement {
.content + .options {
margin-top: 8px;
}
mwc-list-item {
ha-list-item {
--mdc-list-side-padding: 24px;
}
`,

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list-item";
import {
mdiArrowOscillating,
mdiFan,

View File

@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list-item";
import {
mdiBrightness6,
mdiCreation,

Some files were not shown because too many files have changed in this diff Show More