mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Render target picker combo-box in overlaying menu surface (#14970)
This commit is contained in:
parent
cabbbcf9f3
commit
5f9f51f92d
@ -214,7 +214,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
|
||||
if (!devEntities || !devEntities.length) {
|
||||
return false;
|
||||
}
|
||||
return deviceEntityLookup[device.id].some((entity) => {
|
||||
return devEntities.some((entity) => {
|
||||
const stateObj = this.hass.states[entity.entity_id];
|
||||
if (!stateObj) {
|
||||
return false;
|
||||
|
@ -4,7 +4,10 @@ import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { PolymerChangedEvent } from "../../polymer-types";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import "./ha-device-picker";
|
||||
import type { HaDevicePickerDeviceFilterFunc } from "./ha-device-picker";
|
||||
import type {
|
||||
HaDevicePickerDeviceFilterFunc,
|
||||
HaDevicePickerEntityFilterFunc,
|
||||
} from "./ha-device-picker";
|
||||
|
||||
@customElement("ha-devices-picker")
|
||||
class HaDevicesPicker extends LitElement {
|
||||
@ -44,6 +47,8 @@ class HaDevicesPicker extends LitElement {
|
||||
|
||||
@property() public deviceFilter?: HaDevicePickerDeviceFilterFunc;
|
||||
|
||||
@property() public entityFilter?: HaDevicePickerEntityFilterFunc;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
@ -59,6 +64,7 @@ class HaDevicesPicker extends LitElement {
|
||||
.curValue=${entityId}
|
||||
.hass=${this.hass}
|
||||
.deviceFilter=${this.deviceFilter}
|
||||
.entityFilter=${this.entityFilter}
|
||||
.includeDomains=${this.includeDomains}
|
||||
.excludeDomains=${this.excludeDomains}
|
||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||
@ -76,8 +82,10 @@ class HaDevicesPicker extends LitElement {
|
||||
.hass=${this.hass}
|
||||
.helper=${this.helper}
|
||||
.deviceFilter=${this.deviceFilter}
|
||||
.entityFilter=${this.entityFilter}
|
||||
.includeDomains=${this.includeDomains}
|
||||
.excludeDomains=${this.excludeDomains}
|
||||
.excludeDevices=${currentDevices}
|
||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||
.label=${this.pickDeviceLabel}
|
||||
.disabled=${this.disabled}
|
||||
|
@ -233,6 +233,9 @@ export class HaAreaPicker extends LitElement {
|
||||
});
|
||||
inputEntities = inputEntities!.filter((entity) => {
|
||||
const stateObj = this.hass.states[entity.entity_id];
|
||||
if (!stateObj) {
|
||||
return false;
|
||||
}
|
||||
return entityFilter!(stateObj);
|
||||
});
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import { HassEntity, HassServiceTarget } from "home-assistant-js-websocket";
|
||||
import { css, CSSResultGroup, html, LitElement, unsafeCSS } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { ComboBoxLightOpenedChangedEvent } from "@vaadin/combo-box/vaadin-combo-box-light";
|
||||
import { ensureArray } from "../common/array/ensure-array";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { computeDomain } from "../common/entity/compute_domain";
|
||||
@ -31,6 +32,8 @@ import "./ha-area-picker";
|
||||
import "./ha-icon-button";
|
||||
import "./ha-input-helper-text";
|
||||
import "./ha-svg-icon";
|
||||
import { stopPropagation } from "../common/dom/stop_propagation";
|
||||
import "@material/mwc-menu/mwc-menu-surface";
|
||||
|
||||
@customElement("ha-target-picker")
|
||||
export class HaTargetPicker extends LitElement {
|
||||
@ -64,28 +67,21 @@ export class HaTargetPicker extends LitElement {
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public disabled = false;
|
||||
|
||||
@property({ type: Boolean }) public horizontal = false;
|
||||
@property({ type: Boolean }) public addOnTop = false;
|
||||
|
||||
@state() private _addMode?: "area_id" | "entity_id" | "device_id";
|
||||
|
||||
@query("#input") private _inputElement?;
|
||||
|
||||
@query(".add-container", true) private _addContainer?: HTMLDivElement;
|
||||
|
||||
private _opened = false;
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
${this.horizontal
|
||||
? html`
|
||||
<div class="horizontal-container">
|
||||
${this._renderChips()} ${this._renderPicker()}
|
||||
</div>
|
||||
${this._renderItems()}
|
||||
`
|
||||
: html`
|
||||
<div>
|
||||
${this._renderItems()} ${this._renderPicker()}
|
||||
${this._renderChips()}
|
||||
</div>
|
||||
`}
|
||||
`;
|
||||
if (this.addOnTop) {
|
||||
return html` ${this._renderChips()} ${this._renderItems()} `;
|
||||
}
|
||||
return html` ${this._renderItems()} ${this._renderChips()} `;
|
||||
}
|
||||
|
||||
private _renderItems() {
|
||||
@ -132,7 +128,7 @@ export class HaTargetPicker extends LitElement {
|
||||
|
||||
private _renderChips() {
|
||||
return html`
|
||||
<div class="mdc-chip-set">
|
||||
<div class="mdc-chip-set add-container">
|
||||
<div
|
||||
class="mdc-chip area_id add"
|
||||
.type=${"area_id"}
|
||||
@ -193,6 +189,7 @@ export class HaTargetPicker extends LitElement {
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
${this._renderPicker()}
|
||||
</div>
|
||||
${this.helper
|
||||
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
|
||||
@ -200,11 +197,8 @@ export class HaTargetPicker extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private async _showPicker(ev) {
|
||||
private _showPicker(ev) {
|
||||
this._addMode = ev.currentTarget.type;
|
||||
await this.updateComplete;
|
||||
await this._inputElement?.focus();
|
||||
await this._inputElement?.open();
|
||||
}
|
||||
|
||||
private _renderChip(
|
||||
@ -239,7 +233,7 @@ export class HaTargetPicker extends LitElement {
|
||||
</span>
|
||||
${type === "entity_id"
|
||||
? ""
|
||||
: html` <span role="gridcell">
|
||||
: html`<span role="gridcell">
|
||||
<ha-icon-button
|
||||
class="expand-btn mdc-chip__icon mdc-chip__icon--trailing"
|
||||
tabindex="-1"
|
||||
@ -282,61 +276,72 @@ export class HaTargetPicker extends LitElement {
|
||||
}
|
||||
|
||||
private _renderPicker() {
|
||||
switch (this._addMode) {
|
||||
case "area_id":
|
||||
return html`
|
||||
<ha-area-picker
|
||||
.hass=${this.hass}
|
||||
id="input"
|
||||
.type=${"area_id"}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.target-picker.add_area_id"
|
||||
)}
|
||||
no-add
|
||||
.deviceFilter=${this.deviceFilter}
|
||||
.entityFilter=${this.entityFilter}
|
||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||
.includeDomains=${this.includeDomains}
|
||||
.excludeAreas=${ensureArray(this.value?.area_id)}
|
||||
@value-changed=${this._targetPicked}
|
||||
></ha-area-picker>
|
||||
`;
|
||||
case "device_id":
|
||||
return html`
|
||||
<ha-device-picker
|
||||
.hass=${this.hass}
|
||||
id="input"
|
||||
.type=${"device_id"}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.target-picker.add_device_id"
|
||||
)}
|
||||
.deviceFilter=${this.deviceFilter}
|
||||
.entityFilter=${this.entityFilter}
|
||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||
.includeDomains=${this.includeDomains}
|
||||
.excludeDevices=${ensureArray(this.value?.device_id)}
|
||||
@value-changed=${this._targetPicked}
|
||||
></ha-device-picker>
|
||||
`;
|
||||
case "entity_id":
|
||||
return html`
|
||||
<ha-entity-picker
|
||||
.hass=${this.hass}
|
||||
id="input"
|
||||
.type=${"entity_id"}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.target-picker.add_entity_id"
|
||||
)}
|
||||
.entityFilter=${this.entityFilter}
|
||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||
.includeDomains=${this.includeDomains}
|
||||
.excludeEntities=${ensureArray(this.value?.entity_id)}
|
||||
@value-changed=${this._targetPicked}
|
||||
allow-custom-entity
|
||||
></ha-entity-picker>
|
||||
`;
|
||||
if (!this._addMode) {
|
||||
return html``;
|
||||
}
|
||||
return html``;
|
||||
return html`<mwc-menu-surface
|
||||
open
|
||||
.anchor=${this._addContainer}
|
||||
.corner=${"BOTTOM_START"}
|
||||
@closed=${this._onClosed}
|
||||
@opened=${this._onOpened}
|
||||
@opened-changed=${this._openedChanged}
|
||||
@input=${stopPropagation}
|
||||
>${this._addMode === "area_id"
|
||||
? html`
|
||||
<ha-area-picker
|
||||
.hass=${this.hass}
|
||||
id="input"
|
||||
.type=${"area_id"}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.target-picker.add_area_id"
|
||||
)}
|
||||
no-add
|
||||
.deviceFilter=${this.deviceFilter}
|
||||
.entityFilter=${this.entityFilter}
|
||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||
.includeDomains=${this.includeDomains}
|
||||
.excludeAreas=${ensureArray(this.value?.area_id)}
|
||||
@value-changed=${this._targetPicked}
|
||||
@click=${this._preventDefault}
|
||||
></ha-area-picker>
|
||||
`
|
||||
: this._addMode === "device_id"
|
||||
? html`
|
||||
<ha-device-picker
|
||||
.hass=${this.hass}
|
||||
id="input"
|
||||
.type=${"device_id"}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.target-picker.add_device_id"
|
||||
)}
|
||||
.deviceFilter=${this.deviceFilter}
|
||||
.entityFilter=${this.entityFilter}
|
||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||
.includeDomains=${this.includeDomains}
|
||||
.excludeDevices=${ensureArray(this.value?.device_id)}
|
||||
@value-changed=${this._targetPicked}
|
||||
@click=${this._preventDefault}
|
||||
></ha-device-picker>
|
||||
`
|
||||
: html`
|
||||
<ha-entity-picker
|
||||
.hass=${this.hass}
|
||||
id="input"
|
||||
.type=${"entity_id"}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.target-picker.add_entity_id"
|
||||
)}
|
||||
.entityFilter=${this.entityFilter}
|
||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||
.includeDomains=${this.includeDomains}
|
||||
.excludeEntities=${ensureArray(this.value?.entity_id)}
|
||||
@value-changed=${this._targetPicked}
|
||||
@click=${this._preventDefault}
|
||||
allow-custom-entity
|
||||
></ha-entity-picker>
|
||||
`}</mwc-menu-surface
|
||||
>`;
|
||||
}
|
||||
|
||||
private _targetPicked(ev) {
|
||||
@ -347,7 +352,6 @@ export class HaTargetPicker extends LitElement {
|
||||
const value = ev.detail.value;
|
||||
const target = ev.currentTarget;
|
||||
target.value = "";
|
||||
this._addMode = undefined;
|
||||
if (
|
||||
this.value &&
|
||||
this.value[target.type] &&
|
||||
@ -454,6 +458,31 @@ export class HaTargetPicker extends LitElement {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private _onClosed(ev) {
|
||||
ev.stopPropagation();
|
||||
ev.target.open = true;
|
||||
}
|
||||
|
||||
private async _onOpened() {
|
||||
if (!this._addMode) {
|
||||
return;
|
||||
}
|
||||
await this._inputElement?.focus();
|
||||
await this._inputElement?.open();
|
||||
this._opened = true;
|
||||
}
|
||||
|
||||
private _openedChanged(ev: ComboBoxLightOpenedChangedEvent) {
|
||||
if (this._opened && !ev.detail.value) {
|
||||
this._opened = false;
|
||||
this._addMode = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private _preventDefault(ev: Event) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
private _deviceMeetsFilter(device: DeviceRegistryEntry): boolean {
|
||||
const devEntities = Object.values(this.hass.entities).filter(
|
||||
(entity) => entity.device_id === device.id
|
||||
@ -555,12 +584,6 @@ export class HaTargetPicker extends LitElement {
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
${unsafeCSS(chipStyles)}
|
||||
.horizontal-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
min-height: 56px;
|
||||
align-items: center;
|
||||
}
|
||||
.mdc-chip {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
@ -573,6 +596,10 @@ export class HaTargetPicker extends LitElement {
|
||||
.mdc-chip.add {
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
.add-container {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
}
|
||||
.mdc-chip:not(.add) {
|
||||
cursor: default;
|
||||
}
|
||||
@ -644,6 +671,15 @@ export class HaTargetPicker extends LitElement {
|
||||
opacity: var(--light-disabled-opacity);
|
||||
pointer-events: none;
|
||||
}
|
||||
mwc-menu-surface {
|
||||
--mdc-menu-min-width: 100%;
|
||||
}
|
||||
ha-entity-picker,
|
||||
ha-device-picker,
|
||||
ha-area-picker {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
||||
</app-header>
|
||||
|
||||
<div class="flex content">
|
||||
<div class="filters flex layout horizontal narrow-wrap">
|
||||
<div class="filters">
|
||||
<ha-date-range-picker
|
||||
.hass=${this.hass}
|
||||
?disabled=${this._isLoading}
|
||||
@ -169,7 +169,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
||||
.hass=${this.hass}
|
||||
.value=${this._targetPickerValue}
|
||||
.disabled=${this._isLoading}
|
||||
horizontal
|
||||
addOnTop
|
||||
@value-changed=${this._targetsChanged}
|
||||
></ha-target-picker>
|
||||
</div>
|
||||
@ -510,18 +510,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:host([narrow]) .narrow-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.horizontal {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:host(:not([narrow])) .selector-padding {
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
.progress-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
@ -529,11 +517,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
||||
.filters {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 8px 16px 0;
|
||||
}
|
||||
|
||||
:host([narrow]) .filters {
|
||||
flex-wrap: wrap;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
ha-date-range-picker {
|
||||
@ -544,11 +528,15 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
||||
direction: var(--direction);
|
||||
}
|
||||
|
||||
:host([narrow]) ha-date-range-picker {
|
||||
margin-right: 0;
|
||||
margin-inline-end: 0;
|
||||
margin-inline-start: initial;
|
||||
direction: var(--direction);
|
||||
@media all and (max-width: 1025px) {
|
||||
.filters {
|
||||
flex-direction: column;
|
||||
}
|
||||
ha-date-range-picker {
|
||||
margin-right: 0;
|
||||
margin-inline-end: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
ha-circular-progress {
|
||||
@ -558,17 +546,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
ha-entity-picker {
|
||||
display: inline-block;
|
||||
flex-grow: 1;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
:host([narrow]) ha-entity-picker {
|
||||
max-width: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.start-search {
|
||||
padding-top: 16px;
|
||||
text-align: center;
|
||||
|
@ -249,6 +249,7 @@ export class HaPanelLogbook extends LitElement {
|
||||
margin-inline-start: initial;
|
||||
max-width: 100%;
|
||||
direction: var(--direction);
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
:host([narrow]) ha-date-range-picker {
|
||||
@ -256,6 +257,7 @@ export class HaPanelLogbook extends LitElement {
|
||||
margin-inline-end: 0;
|
||||
margin-inline-start: initial;
|
||||
direction: var(--direction);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
|
Loading…
x
Reference in New Issue
Block a user