diff --git a/package.json b/package.json index a3d3345a33..ac3a7acdb8 100644 --- a/package.json +++ b/package.json @@ -117,6 +117,7 @@ "leaflet": "^1.7.1", "leaflet-draw": "^1.0.4", "lit": "^2.0.0-rc.2", + "lit-vaadin-helpers": "^0.1.3", "marked": "2.0.0", "mdn-polyfills": "^5.16.0", "memoize-one": "^5.0.2", diff --git a/src/components/device/ha-area-devices-picker.ts b/src/components/device/ha-area-devices-picker.ts index 2f70b6ffca..712e1b1bb3 100644 --- a/src/components/device/ha-area-devices-picker.ts +++ b/src/components/device/ha-area-devices-picker.ts @@ -38,6 +38,7 @@ import { PolymerChangedEvent } from "../../polymer-types"; import { HomeAssistant } from "../../types"; import "../ha-svg-icon"; import "./ha-devices-picker"; +import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers"; interface DevicesByArea { [areaId: string]: AreaDevices; @@ -49,42 +50,28 @@ interface AreaDevices { devices: string[]; } -const rowRenderer = ( - root: HTMLElement, - _owner, - model: { item: AreaDevices } -) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - -
[[item.name]]
-
[[item.devices.length]] devices
-
-
- `; - } - root.querySelector(".name")!.textContent = model.item.name!; - root.querySelector( - "[secondary]" - )!.textContent = `${model.item.devices.length.toString()} devices`; -}; +const rowRenderer: ComboBoxLitRenderer = (item) => html` + + +
${item.name}
+
${item.devices.length} devices
+
+
`; @customElement("ha-area-devices-picker") export class HaAreaDevicesPicker extends SubscribeMixin(LitElement) { @@ -310,7 +297,7 @@ export class HaAreaDevicesPicker extends SubscribeMixin(LitElement) { item-label-path="name" .items=${areas} .value=${this._value} - .renderer=${rowRenderer} + ${comboBoxRenderer(rowRenderer)} @opened-changed=${this._openedChanged} @value-changed=${this._areaPicked} > diff --git a/src/components/device/ha-device-picker.ts b/src/components/device/ha-device-picker.ts index cc2052dac4..1333f9fb82 100644 --- a/src/components/device/ha-device-picker.ts +++ b/src/components/device/ha-device-picker.ts @@ -33,6 +33,7 @@ import { PolymerChangedEvent } from "../../polymer-types"; import { HomeAssistant } from "../../types"; import "../ha-combo-box"; import type { HaComboBox } from "../ha-combo-box"; +import { ComboBoxLitRenderer } from "lit-vaadin-helpers"; interface Device { name: string; @@ -44,27 +45,18 @@ export type HaDevicePickerDeviceFilterFunc = ( device: DeviceRegistryEntry ) => boolean; -const rowRenderer = (root: HTMLElement, _owner, model: { item: Device }) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - -
[[item.name]]
-
[[item.area]]
-
-
- `; - } - - root.querySelector(".name")!.textContent = model.item.name!; - root.querySelector("[secondary]")!.textContent = model.item.area!; -}; +const rowRenderer: ComboBoxLitRenderer = (item) => html` + + + ${item.name} + ${item.area} + + `; @customElement("ha-device-picker") export class HaDevicePicker extends SubscribeMixin(LitElement) { diff --git a/src/components/entity/ha-entity-attribute-picker.ts b/src/components/entity/ha-entity-attribute-picker.ts index 729c94db77..b0b07b40ea 100644 --- a/src/components/entity/ha-entity-attribute-picker.ts +++ b/src/components/entity/ha-entity-attribute-picker.ts @@ -12,6 +12,7 @@ import { PropertyValues, TemplateResult, } from "lit"; +import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers"; import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { PolymerChangedEvent } from "../../polymer-types"; @@ -22,22 +23,13 @@ import "./state-badge"; export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean; -const rowRenderer = (root: HTMLElement, _owner, model: { item: string }) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - `; - } - root.querySelector("paper-item")!.textContent = formatAttributeName( - model.item - ); -}; +const rowRenderer: ComboBoxLitRenderer = (item) => html` + ${formatAttributeName(item)}`; @customElement("ha-entity-attribute-picker") class HaEntityAttributePicker extends LitElement { @@ -82,8 +74,8 @@ class HaEntityAttributePicker extends LitElement { diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts index c5981a01e7..e17393a775 100644 --- a/src/components/entity/ha-entity-picker.ts +++ b/src/components/entity/ha-entity-picker.ts @@ -13,6 +13,7 @@ import { PropertyValues, TemplateResult, } from "lit"; +import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers"; import { customElement, property, query } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; @@ -25,32 +26,19 @@ import "./state-badge"; export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean; -const rowRenderer = ( - root: HTMLElement, - _owner, - model: { item: HassEntity } -) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - - -
-
-
-
- `; - } - root.querySelector("state-badge")!.stateObj = model.item; - root.querySelector(".name")!.textContent = computeStateName(model.item); - root.querySelector("[secondary]")!.textContent = model.item.entity_id; -}; +const rowRenderer: ComboBoxLitRenderer = (item) => html` + + + + ${computeStateName(item)} + ${item.entity_id} + + `; @customElement("ha-entity-picker") export class HaEntityPicker extends LitElement { @@ -221,7 +209,7 @@ export class HaEntityPicker extends LitElement { item-label-path="entity_id" .value=${this._value} .allowCustomValue=${this.allowCustomEntity} - .renderer=${rowRenderer} + ${comboBoxRenderer(rowRenderer)} @opened-changed=${this._openedChanged} @value-changed=${this._valueChanged} @filter-changed=${this._filterChanged} diff --git a/src/components/ha-addon-picker.ts b/src/components/ha-addon-picker.ts index 421b297750..f868d5ead6 100644 --- a/src/components/ha-addon-picker.ts +++ b/src/components/ha-addon-picker.ts @@ -9,32 +9,20 @@ import { showAlertDialog } from "../dialogs/generic/show-dialog-box"; import { PolymerChangedEvent } from "../polymer-types"; import { HomeAssistant } from "../types"; import { HaComboBox } from "./ha-combo-box"; +import { ComboBoxLitRenderer } from "lit-vaadin-helpers"; -const rowRenderer = ( - root: HTMLElement, - _owner, - model: { item: HassioAddonInfo } -) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - -
[[item.name]]
-
[[item.slug]]
-
-
- `; - } - - root.querySelector(".name")!.textContent = model.item.name; - root.querySelector("[secondary]")!.textContent = model.item.slug; -}; +const rowRenderer: ComboBoxLitRenderer = (item) => html` + + + ${item.name} + ${item.slug} + + `; @customElement("ha-addon-picker") class HaAddonPicker extends LitElement { diff --git a/src/components/ha-area-picker.ts b/src/components/ha-area-picker.ts index 1781bcc040..f6d99c4510 100644 --- a/src/components/ha-area-picker.ts +++ b/src/components/ha-area-picker.ts @@ -14,7 +14,9 @@ import { PropertyValues, TemplateResult, } from "lit"; -import { customElement, property, state, query } from "lit/decorators"; +import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers"; +import { customElement, property, query, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import memoizeOne from "memoize-one"; import { fireEvent } from "../common/dom/fire_event"; import { computeDomain } from "../common/entity/compute_domain"; @@ -42,36 +44,20 @@ import { HomeAssistant } from "../types"; import type { HaDevicePickerDeviceFilterFunc } from "./device/ha-device-picker"; import "./ha-svg-icon"; -const rowRenderer = ( - root: HTMLElement, - _owner, - model: { item: AreaRegistryEntry } -) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - -
[[item.name]]
-
-
- `; - } - root.querySelector(".name")!.textContent = model.item.name!; - if (model.item.area_id === "add_new") { - root.querySelector("paper-item")!.className = "add-new"; - } else { - root.querySelector("paper-item")!.classList.remove("add-new"); - } -}; +const rowRenderer: ComboBoxLitRenderer = ( + item +) => html` + + ${item.name} + `; @customElement("ha-area-picker") export class HaAreaPicker extends SubscribeMixin(LitElement) { @@ -340,8 +326,8 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) { item-id-path="area_id" item-label-path="name" .value=${this._value} - .renderer=${rowRenderer} .disabled=${this.disabled} + ${comboBoxRenderer(rowRenderer)} @opened-changed=${this._openedChanged} @value-changed=${this._areaChanged} > diff --git a/src/components/ha-combo-box.ts b/src/components/ha-combo-box.ts index eb122e1c7e..f1e4650d7c 100644 --- a/src/components/ha-combo-box.ts +++ b/src/components/ha-combo-box.ts @@ -6,31 +6,20 @@ import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-listbox/paper-listbox"; import "@vaadin/vaadin-combo-box/theme/material/vaadin-combo-box-light"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; -import { customElement, property, state, query } from "lit/decorators"; +import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers"; +import { customElement, property, query, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { PolymerChangedEvent } from "../polymer-types"; import { HomeAssistant } from "../types"; import "./ha-svg-icon"; -const defaultRowRenderer = ( - root: HTMLElement, - _owner, - model: { item: any } -) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - `; - } - - root.querySelector("paper-item")!.textContent = model.item; -}; +const defaultRowRenderer: ComboBoxLitRenderer = (item) => html` + ${item}`; @customElement("ha-combo-box") export class HaComboBox extends LitElement { @@ -53,11 +42,7 @@ export class HaComboBox extends LitElement { @property({ attribute: "item-id-path" }) public itemIdPath?: string; - @property() public renderer?: ( - root: HTMLElement, - owner: HTMLElement, - model: { item: any } - ) => void; + @property() public renderer?: ComboBoxLitRenderer; @property({ type: Boolean }) public disabled?: boolean; @@ -90,9 +75,9 @@ export class HaComboBox extends LitElement { .value=${this.value} .items=${this.items} .filteredItems=${this.filteredItems} - .renderer=${this.renderer || defaultRowRenderer} .allowCustomValue=${this.allowCustomValue} .disabled=${this.disabled} + ${comboBoxRenderer(this.renderer || defaultRowRenderer)} @opened-changed=${this._openedChanged} @filter-changed=${this._filterChanged} @value-changed=${this._valueChanged} diff --git a/src/components/ha-service-picker.ts b/src/components/ha-service-picker.ts index 2bc92b97c4..10755ca50e 100644 --- a/src/components/ha-service-picker.ts +++ b/src/components/ha-service-picker.ts @@ -6,33 +6,22 @@ import { LocalizeFunc } from "../common/translations/localize"; import { domainToName } from "../data/integration"; import { HomeAssistant } from "../types"; import "./ha-combo-box"; +import { ComboBoxLitRenderer } from "lit-vaadin-helpers"; -const rowRenderer = ( - root: HTMLElement, - _owner, - model: { item: { service: string; name: string } } -) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - -
[[item.name]]
-
[[item.service]]
-
-
- `; - } - - root.querySelector(".name")!.textContent = model.item.name; - root.querySelector("[secondary]")!.textContent = - model.item.name === model.item.service ? "" : model.item.service; -}; +const rowRenderer: ComboBoxLitRenderer<{ service: string; name: string }> = ( + item +) => html` + + + ${item.name} + ${item.name === item.service ? "" : item.service} + + `; class HaServicePicker extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; diff --git a/yarn.lock b/yarn.lock index 870d8430ee..96f52c3197 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8721,6 +8721,13 @@ lit-html@2.0.0-rc.3, lit-html@^1.4.0, lit-html@^2.0.0-rc.3: dependencies: "@types/trusted-types" "^1.0.1" +lit-vaadin-helpers@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/lit-vaadin-helpers/-/lit-vaadin-helpers-0.1.3.tgz#6230ffdb90f7808d087107f18e83f14d64f0f5d5" + integrity sha512-fEUJEVzC1IluUbOOExBYuwal/DyhZqheIvtDV/Tlnmbq1NFtIjgybFQuFNXAyHDaaVwuKDijTGP1c3wwf9rg8w== + dependencies: + lit "^2.0.0-rc.1" + lit@^2.0.0-rc.1, lit@^2.0.0-rc.2: version "2.0.0-rc.2" resolved "https://registry.yarnpkg.com/lit/-/lit-2.0.0-rc.2.tgz#724a2d621aa098001d73bf7106f3a72b7b5948ef"