mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-02 00:27:49 +01:00
Simplify dialogs (#29848)
This commit is contained in:
@@ -8,6 +8,7 @@ import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
|
|||||||
import { mockFloorRegistry } from "../../../../demo/src/stubs/floor_registry";
|
import { mockFloorRegistry } from "../../../../demo/src/stubs/floor_registry";
|
||||||
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
|
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
|
||||||
import { mockLabelRegistry } from "../../../../demo/src/stubs/label_registry";
|
import { mockLabelRegistry } from "../../../../demo/src/stubs/label_registry";
|
||||||
|
import type { HASSDomEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import "../../../../src/components/ha-formfield";
|
import "../../../../src/components/ha-formfield";
|
||||||
import "../../../../src/components/ha-selector/ha-selector";
|
import "../../../../src/components/ha-selector/ha-selector";
|
||||||
import "../../../../src/components/ha-settings-row";
|
import "../../../../src/components/ha-settings-row";
|
||||||
@@ -16,7 +17,10 @@ import type { BlueprintInput } from "../../../../src/data/blueprint";
|
|||||||
import type { DeviceRegistryEntry } from "../../../../src/data/device/device_registry";
|
import type { DeviceRegistryEntry } from "../../../../src/data/device/device_registry";
|
||||||
import type { FloorRegistryEntry } from "../../../../src/data/floor_registry";
|
import type { FloorRegistryEntry } from "../../../../src/data/floor_registry";
|
||||||
import type { LabelRegistryEntry } from "../../../../src/data/label/label_registry";
|
import type { LabelRegistryEntry } from "../../../../src/data/label/label_registry";
|
||||||
import { showDialog } from "../../../../src/dialogs/make-dialog-manager";
|
import {
|
||||||
|
showDialog,
|
||||||
|
type ShowDialogParams,
|
||||||
|
} from "../../../../src/dialogs/make-dialog-manager";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import type { ProvideHassElement } from "../../../../src/mixins/provide-hass-lit-mixin";
|
import type { ProvideHassElement } from "../../../../src/mixins/provide-hass-lit-mixin";
|
||||||
import type { HomeAssistant } from "../../../../src/types";
|
import type { HomeAssistant } from "../../../../src/types";
|
||||||
@@ -634,14 +638,15 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
private _dialogManager = (e) => {
|
private _dialogManager = (e: HASSDomEvent<ShowDialogParams<unknown>>) => {
|
||||||
const { dialogTag, dialogImport, dialogParams, addHistory } = e.detail;
|
const { dialogTag, dialogImport, dialogParams, addHistory, parentElement } =
|
||||||
|
e.detail;
|
||||||
showDialog(
|
showDialog(
|
||||||
this,
|
this,
|
||||||
this.shadowRoot!,
|
|
||||||
dialogTag,
|
dialogTag,
|
||||||
dialogParams,
|
dialogParams,
|
||||||
dialogImport,
|
dialogImport,
|
||||||
|
parentElement,
|
||||||
addHistory
|
addHistory
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class HaLandingPage extends LandingPageBaseElement {
|
|||||||
protected firstUpdated(changedProps: PropertyValues) {
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
|
|
||||||
makeDialogManager(this, this.shadowRoot!);
|
makeDialogManager(this);
|
||||||
|
|
||||||
if (window.innerWidth > 450) {
|
if (window.innerWidth > 450) {
|
||||||
import("../../src/resources/particles");
|
import("../../src/resources/particles");
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export class HaBottomSheet extends ScrollableFadeMixin(LitElement) {
|
|||||||
await this.updateComplete;
|
await this.updateComplete;
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
if (this.hass && isIosApp(this.hass)) {
|
if (this.hass && isIosApp(this.hass.auth.external)) {
|
||||||
const element = this.renderRoot.querySelector("[autofocus]");
|
const element = this.renderRoot.querySelector("[autofocus]");
|
||||||
if (element !== null) {
|
if (element !== null) {
|
||||||
if (!element.id) {
|
if (!element.id) {
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
|
import { consume, type ContextType } from "@lit/context";
|
||||||
import { mdiInvertColorsOff, mdiPalette } from "@mdi/js";
|
import { mdiInvertColorsOff, mdiPalette } from "@mdi/js";
|
||||||
import { html, LitElement, nothing } from "lit";
|
import { html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
import { styleMap } from "lit/directives/style-map";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { computeCssColor, THEME_COLORS } from "../common/color/compute-color";
|
import { computeCssColor, THEME_COLORS } from "../common/color/compute-color";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import type { LocalizeKeys } from "../common/translations/localize";
|
import type { LocalizeKeys } from "../common/translations/localize";
|
||||||
import type { HomeAssistant, ValueChangedEvent } from "../types";
|
import { localizeContext } from "../data/context";
|
||||||
|
import type { ValueChangedEvent } from "../types";
|
||||||
import "./ha-generic-picker";
|
import "./ha-generic-picker";
|
||||||
import type { PickerComboBoxItem } from "./ha-picker-combo-box";
|
import type { PickerComboBoxItem } from "./ha-picker-combo-box";
|
||||||
import type { PickerValueRenderer } from "./ha-picker-field";
|
import type { PickerValueRenderer } from "./ha-picker-field";
|
||||||
|
|
||||||
@customElement("ha-color-picker")
|
@customElement("ha-color-picker")
|
||||||
export class HaColorPicker extends LitElement {
|
export class HaColorPicker extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@property() public label?: string;
|
@property() public label?: string;
|
||||||
|
|
||||||
@property() public helper?: string;
|
@property() public helper?: string;
|
||||||
@@ -34,12 +34,15 @@ export class HaColorPicker extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public required = false;
|
@property({ type: Boolean }) public required = false;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
@consume({ context: localizeContext, subscribe: true })
|
||||||
|
private localize!: ContextType<typeof localizeContext>;
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const effectiveValue = this.value ?? this.defaultColor ?? "";
|
const effectiveValue = this.value ?? this.defaultColor ?? "";
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-generic-picker
|
<ha-generic-picker
|
||||||
.hass=${this.hass}
|
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.required=${this.required}
|
.required=${this.required}
|
||||||
.hideClearIcon=${!this.value && !!this.defaultColor}
|
.hideClearIcon=${!this.value && !!this.defaultColor}
|
||||||
@@ -50,7 +53,7 @@ export class HaColorPicker extends LitElement {
|
|||||||
.rowRenderer=${this._rowRenderer}
|
.rowRenderer=${this._rowRenderer}
|
||||||
.valueRenderer=${this._valueRenderer}
|
.valueRenderer=${this._valueRenderer}
|
||||||
@value-changed=${this._valueChanged}
|
@value-changed=${this._valueChanged}
|
||||||
.notFoundLabel=${this.hass.localize(
|
.notFoundLabel=${this.localize?.(
|
||||||
"ui.components.color-picker.no_colors_found"
|
"ui.components.color-picker.no_colors_found"
|
||||||
)}
|
)}
|
||||||
.getAdditionalItems=${this._getAdditionalItems}
|
.getAdditionalItems=${this._getAdditionalItems}
|
||||||
@@ -78,7 +81,9 @@ export class HaColorPicker extends LitElement {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: searchString,
|
id: searchString,
|
||||||
primary: this.hass.localize("ui.components.color-picker.custom_color"),
|
primary:
|
||||||
|
this.localize?.("ui.components.color-picker.custom_color") ||
|
||||||
|
"Custom color",
|
||||||
secondary: searchString,
|
secondary: searchString,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -101,16 +106,15 @@ export class HaColorPicker extends LitElement {
|
|||||||
): PickerComboBoxItem[] => {
|
): PickerComboBoxItem[] => {
|
||||||
const items: PickerComboBoxItem[] = [];
|
const items: PickerComboBoxItem[] = [];
|
||||||
|
|
||||||
const defaultSuffix = this.hass.localize(
|
const defaultSuffix =
|
||||||
"ui.components.color-picker.default"
|
this.localize?.("ui.components.color-picker.default") || "Default";
|
||||||
);
|
|
||||||
|
|
||||||
const addDefaultSuffix = (label: string, isDefault: boolean) =>
|
const addDefaultSuffix = (label: string, isDefault: boolean) =>
|
||||||
isDefault && defaultSuffix ? `${label} (${defaultSuffix})` : label;
|
isDefault && defaultSuffix ? `${label} (${defaultSuffix})` : label;
|
||||||
|
|
||||||
if (includeNone) {
|
if (includeNone) {
|
||||||
const noneLabel =
|
const noneLabel =
|
||||||
this.hass.localize("ui.components.color-picker.none") || "None";
|
this.localize?.("ui.components.color-picker.none") || "None";
|
||||||
items.push({
|
items.push({
|
||||||
id: "none",
|
id: "none",
|
||||||
primary: addDefaultSuffix(noneLabel, defaultColor === "none"),
|
primary: addDefaultSuffix(noneLabel, defaultColor === "none"),
|
||||||
@@ -120,7 +124,7 @@ export class HaColorPicker extends LitElement {
|
|||||||
|
|
||||||
if (includeState) {
|
if (includeState) {
|
||||||
const stateLabel =
|
const stateLabel =
|
||||||
this.hass.localize("ui.components.color-picker.state") || "State";
|
this.localize?.("ui.components.color-picker.state") || "State";
|
||||||
items.push({
|
items.push({
|
||||||
id: "state",
|
id: "state",
|
||||||
primary: addDefaultSuffix(stateLabel, defaultColor === "state"),
|
primary: addDefaultSuffix(stateLabel, defaultColor === "state"),
|
||||||
@@ -130,7 +134,7 @@ export class HaColorPicker extends LitElement {
|
|||||||
|
|
||||||
Array.from(THEME_COLORS).forEach((color) => {
|
Array.from(THEME_COLORS).forEach((color) => {
|
||||||
const themeLabel =
|
const themeLabel =
|
||||||
this.hass.localize(
|
this.localize?.(
|
||||||
`ui.components.color-picker.colors.${color}` as LocalizeKeys
|
`ui.components.color-picker.colors.${color}` as LocalizeKeys
|
||||||
) || color;
|
) || color;
|
||||||
items.push({
|
items.push({
|
||||||
@@ -184,7 +188,7 @@ export class HaColorPicker extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<ha-svg-icon slot="start" .path=${mdiInvertColorsOff}></ha-svg-icon>
|
<ha-svg-icon slot="start" .path=${mdiInvertColorsOff}></ha-svg-icon>
|
||||||
<span slot="headline">
|
<span slot="headline">
|
||||||
${this.hass.localize("ui.components.color-picker.none")}
|
${this.localize?.("ui.components.color-picker.none") || "None"}
|
||||||
</span>
|
</span>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -192,7 +196,7 @@ export class HaColorPicker extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<ha-svg-icon slot="start" .path=${mdiPalette}></ha-svg-icon>
|
<ha-svg-icon slot="start" .path=${mdiPalette}></ha-svg-icon>
|
||||||
<span slot="headline">
|
<span slot="headline">
|
||||||
${this.hass.localize("ui.components.color-picker.state")}
|
${this.localize?.("ui.components.color-picker.state") || "State"}
|
||||||
</span>
|
</span>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -200,7 +204,7 @@ export class HaColorPicker extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<span slot="start">${this._renderColorCircle(value)}</span>
|
<span slot="start">${this._renderColorCircle(value)}</span>
|
||||||
<span slot="headline">
|
<span slot="headline">
|
||||||
${this.hass.localize(
|
${this.localize?.(
|
||||||
`ui.components.color-picker.colors.${value}` as LocalizeKeys
|
`ui.components.color-picker.colors.${value}` as LocalizeKeys
|
||||||
) || value}
|
) || value}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import "@home-assistant/webawesome/dist/components/dialog/dialog";
|
import "@home-assistant/webawesome/dist/components/dialog/dialog";
|
||||||
import type WaDialog from "@home-assistant/webawesome/dist/components/dialog/dialog";
|
import type WaDialog from "@home-assistant/webawesome/dist/components/dialog/dialog";
|
||||||
|
import { consume, type ContextType } from "@lit/context";
|
||||||
import { mdiClose } from "@mdi/js";
|
import { mdiClose } from "@mdi/js";
|
||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
import {
|
import {
|
||||||
@@ -13,9 +14,9 @@ import { ifDefined } from "lit/directives/if-defined";
|
|||||||
import type { HASSDomEvent } from "../common/dom/fire_event";
|
import type { HASSDomEvent } from "../common/dom/fire_event";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import { withViewTransition } from "../common/util/view-transition";
|
import { withViewTransition } from "../common/util/view-transition";
|
||||||
|
import { authContext, localizeContext } from "../data/context";
|
||||||
import { ScrollableFadeMixin } from "../mixins/scrollable-fade-mixin";
|
import { ScrollableFadeMixin } from "../mixins/scrollable-fade-mixin";
|
||||||
import { haStyleScrollbar } from "../resources/styles";
|
import { haStyleScrollbar } from "../resources/styles";
|
||||||
import type { HomeAssistant } from "../types";
|
|
||||||
import { isIosApp } from "../util/is_ios";
|
import { isIosApp } from "../util/is_ios";
|
||||||
import "./ha-dialog-header";
|
import "./ha-dialog-header";
|
||||||
import "./ha-icon-button";
|
import "./ha-icon-button";
|
||||||
@@ -84,8 +85,6 @@ type DialogHideEvent = CustomEvent<{ source?: Element }>;
|
|||||||
*/
|
*/
|
||||||
@customElement("ha-dialog")
|
@customElement("ha-dialog")
|
||||||
export class HaDialog extends ScrollableFadeMixin(LitElement) {
|
export class HaDialog extends ScrollableFadeMixin(LitElement) {
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
|
||||||
|
|
||||||
@property({ attribute: "aria-labelledby" })
|
@property({ attribute: "aria-labelledby" })
|
||||||
public ariaLabelledBy?: string;
|
public ariaLabelledBy?: string;
|
||||||
|
|
||||||
@@ -124,6 +123,14 @@ export class HaDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
|
|
||||||
@query(".body") public bodyContainer!: HTMLDivElement;
|
@query(".body") public bodyContainer!: HTMLDivElement;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
@consume({ context: localizeContext, subscribe: true })
|
||||||
|
private localize!: ContextType<typeof localizeContext>;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
@consume({ context: authContext, subscribe: true })
|
||||||
|
private auth?: ContextType<typeof authContext>;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private _bodyScrolled = false;
|
private _bodyScrolled = false;
|
||||||
|
|
||||||
@@ -177,7 +184,7 @@ export class HaDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
<slot name="headerNavigationIcon" slot="navigationIcon">
|
<slot name="headerNavigationIcon" slot="navigationIcon">
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
data-dialog="close"
|
data-dialog="close"
|
||||||
.label=${this.hass?.localize("ui.common.close") ?? "Close"}
|
.label=${this.localize?.("ui.common.close") ?? "Close"}
|
||||||
.path=${mdiClose}
|
.path=${mdiClose}
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
</slot>
|
</slot>
|
||||||
@@ -214,13 +221,13 @@ export class HaDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
await this.updateComplete;
|
await this.updateComplete;
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
if (this.hass && isIosApp(this.hass)) {
|
if (this.auth?.external && isIosApp(this.auth.external)) {
|
||||||
const element = this.querySelector("[autofocus]");
|
const element = this.querySelector("[autofocus]");
|
||||||
if (element !== null) {
|
if (element !== null) {
|
||||||
if (!element.id) {
|
if (!element.id) {
|
||||||
element.id = "ha-dialog-autofocus";
|
element.id = "ha-dialog-autofocus";
|
||||||
}
|
}
|
||||||
this.hass?.auth.external?.fireMessage({
|
this.auth.external.fireMessage({
|
||||||
type: "focus_element",
|
type: "focus_element",
|
||||||
payload: {
|
payload: {
|
||||||
element_id: element.id,
|
element_id: element.id,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import "@home-assistant/webawesome/dist/components/popover/popover";
|
import "@home-assistant/webawesome/dist/components/popover/popover";
|
||||||
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
|
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
|
||||||
|
import { consume, type ContextType } from "@lit/context";
|
||||||
import { mdiPlaylistPlus } from "@mdi/js";
|
import { mdiPlaylistPlus } from "@mdi/js";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
@@ -13,10 +14,9 @@ import { customElement, property, query, state } from "lit/decorators";
|
|||||||
import { ifDefined } from "lit/directives/if-defined";
|
import { ifDefined } from "lit/directives/if-defined";
|
||||||
import { tinykeys } from "tinykeys";
|
import { tinykeys } from "tinykeys";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import { throttle } from "../common/util/throttle";
|
import { authContext } from "../data/context";
|
||||||
import { PickerMixin } from "../mixins/picker-mixin";
|
import { PickerMixin } from "../mixins/picker-mixin";
|
||||||
import type { FuseWeightedKey } from "../resources/fuseMultiTerm";
|
import type { FuseWeightedKey } from "../resources/fuseMultiTerm";
|
||||||
import type { HomeAssistant } from "../types";
|
|
||||||
import { isIosApp } from "../util/is_ios";
|
import { isIosApp } from "../util/is_ios";
|
||||||
import "./ha-bottom-sheet";
|
import "./ha-bottom-sheet";
|
||||||
import "./ha-button";
|
import "./ha-button";
|
||||||
@@ -33,8 +33,6 @@ import "./ha-svg-icon";
|
|||||||
|
|
||||||
@customElement("ha-generic-picker")
|
@customElement("ha-generic-picker")
|
||||||
export class HaGenericPicker extends PickerMixin(LitElement) {
|
export class HaGenericPicker extends PickerMixin(LitElement) {
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
|
||||||
|
|
||||||
@property({ type: Boolean, attribute: "allow-custom-value" })
|
@property({ type: Boolean, attribute: "allow-custom-value" })
|
||||||
public allowCustomValue;
|
public allowCustomValue;
|
||||||
|
|
||||||
@@ -115,6 +113,10 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
|
|||||||
|
|
||||||
@query("ha-picker-combo-box") private _comboBox?: HaPickerComboBox;
|
@query("ha-picker-combo-box") private _comboBox?: HaPickerComboBox;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
@consume({ context: authContext, subscribe: true })
|
||||||
|
private auth?: ContextType<typeof authContext>;
|
||||||
|
|
||||||
@state() private _opened = false;
|
@state() private _opened = false;
|
||||||
|
|
||||||
@state() private _pickerWrapperOpen = false;
|
@state() private _pickerWrapperOpen = false;
|
||||||
@@ -146,10 +148,6 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
|
|||||||
protected willUpdate(changedProperties: PropertyValues) {
|
protected willUpdate(changedProperties: PropertyValues) {
|
||||||
if (changedProperties.has("value")) {
|
if (changedProperties.has("value")) {
|
||||||
this._setUnknownValue();
|
this._setUnknownValue();
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (changedProperties.has("hass")) {
|
|
||||||
this._throttleUnknownValue();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +255,6 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
|
|||||||
return html`
|
return html`
|
||||||
<ha-picker-combo-box
|
<ha-picker-combo-box
|
||||||
id="combo-box"
|
id="combo-box"
|
||||||
.hass=${this.hass}
|
|
||||||
.allowCustomValue=${this.allowCustomValue}
|
.allowCustomValue=${this.allowCustomValue}
|
||||||
.label=${this.searchLabel}
|
.label=${this.searchLabel}
|
||||||
.value=${this._selectedValue ?? this.value}
|
.value=${this._selectedValue ?? this.value}
|
||||||
@@ -296,13 +293,6 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
private _throttleUnknownValue = throttle(
|
|
||||||
this._setUnknownValue,
|
|
||||||
1000,
|
|
||||||
true,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
private _renderHelper() {
|
private _renderHelper() {
|
||||||
const showError = this.invalid && this.errorMessage;
|
const showError = this.invalid && this.errorMessage;
|
||||||
const showHelper = !showError && this.helper;
|
const showHelper = !showError && this.helper;
|
||||||
@@ -326,8 +316,8 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
|
|||||||
this._comboBox?.setFieldValue(this._initialFieldValue);
|
this._comboBox?.setFieldValue(this._initialFieldValue);
|
||||||
this._initialFieldValue = undefined;
|
this._initialFieldValue = undefined;
|
||||||
}
|
}
|
||||||
if (this.hass && isIosApp(this.hass)) {
|
if (this.auth?.external && isIosApp(this.auth.external)) {
|
||||||
this.hass.auth.external!.fireMessage({
|
this.auth.external.fireMessage({
|
||||||
type: "focus_element",
|
type: "focus_element",
|
||||||
payload: {
|
payload: {
|
||||||
element_id: "combo-box",
|
element_id: "combo-box",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { customElement, property } from "lit/decorators";
|
|||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import { customIcons } from "../data/custom_icons";
|
import { customIcons } from "../data/custom_icons";
|
||||||
import type { HomeAssistant, ValueChangedEvent } from "../types";
|
import type { ValueChangedEvent } from "../types";
|
||||||
import "./ha-combo-box-item";
|
import "./ha-combo-box-item";
|
||||||
import "./ha-generic-picker";
|
import "./ha-generic-picker";
|
||||||
import "./ha-icon";
|
import "./ha-icon";
|
||||||
@@ -88,8 +88,6 @@ const rowRenderer: RenderItemFunction<PickerComboBoxItem> = (item) => html`
|
|||||||
|
|
||||||
@customElement("ha-icon-picker")
|
@customElement("ha-icon-picker")
|
||||||
export class HaIconPicker extends LitElement {
|
export class HaIconPicker extends LitElement {
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
|
||||||
|
|
||||||
@property() public value?: string;
|
@property() public value?: string;
|
||||||
|
|
||||||
@property() public label?: string;
|
@property() public label?: string;
|
||||||
@@ -111,7 +109,6 @@ export class HaIconPicker extends LitElement {
|
|||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-generic-picker
|
<ha-generic-picker
|
||||||
.hass=${this.hass}
|
|
||||||
allow-custom-value
|
allow-custom-value
|
||||||
.getItems=${this._getIconPickerItems}
|
.getItems=${this._getIconPickerItems}
|
||||||
.helper=${this.helper}
|
.helper=${this.helper}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { LitVirtualizer } from "@lit-labs/virtualizer";
|
import type { LitVirtualizer } from "@lit-labs/virtualizer";
|
||||||
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
|
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
|
||||||
|
import { consume, type ContextType } from "@lit/context";
|
||||||
import { mdiClose, mdiMagnify, mdiMinusBoxOutline, mdiPlus } from "@mdi/js";
|
import { mdiClose, mdiMagnify, mdiMinusBoxOutline, mdiPlus } from "@mdi/js";
|
||||||
import Fuse from "fuse.js";
|
import Fuse from "fuse.js";
|
||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
@@ -14,6 +15,7 @@ import memoizeOne from "memoize-one";
|
|||||||
import { tinykeys } from "tinykeys";
|
import { tinykeys } from "tinykeys";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import { caseInsensitiveStringCompare } from "../common/string/compare";
|
import { caseInsensitiveStringCompare } from "../common/string/compare";
|
||||||
|
import { localeContext, localizeContext } from "../data/context";
|
||||||
import { ScrollableFadeMixin } from "../mixins/scrollable-fade-mixin";
|
import { ScrollableFadeMixin } from "../mixins/scrollable-fade-mixin";
|
||||||
import {
|
import {
|
||||||
multiTermSortedSearch,
|
multiTermSortedSearch,
|
||||||
@@ -21,7 +23,6 @@ import {
|
|||||||
} from "../resources/fuseMultiTerm";
|
} from "../resources/fuseMultiTerm";
|
||||||
import { haStyleScrollbar } from "../resources/styles";
|
import { haStyleScrollbar } from "../resources/styles";
|
||||||
import { loadVirtualizer } from "../resources/virtualizer";
|
import { loadVirtualizer } from "../resources/virtualizer";
|
||||||
import type { HomeAssistant } from "../types";
|
|
||||||
import { isTouch } from "../util/is_touch";
|
import { isTouch } from "../util/is_touch";
|
||||||
import "./chips/ha-chip-set";
|
import "./chips/ha-chip-set";
|
||||||
import "./chips/ha-filter-chip";
|
import "./chips/ha-filter-chip";
|
||||||
@@ -90,8 +91,6 @@ export type PickerComboBoxSearchFn<T extends PickerComboBoxItem> = (
|
|||||||
|
|
||||||
@customElement("ha-picker-combo-box")
|
@customElement("ha-picker-combo-box")
|
||||||
export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
|
||||||
|
|
||||||
// eslint-disable-next-line lit/no-native-attributes
|
// eslint-disable-next-line lit/no-native-attributes
|
||||||
@property({ type: Boolean }) public autofocus = false;
|
@property({ type: Boolean }) public autofocus = false;
|
||||||
|
|
||||||
@@ -162,6 +161,14 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
|||||||
|
|
||||||
@query("ha-textfield") private _searchFieldElement?: HaTextField;
|
@query("ha-textfield") private _searchFieldElement?: HaTextField;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
@consume({ context: localizeContext, subscribe: true })
|
||||||
|
private localize!: ContextType<typeof localizeContext>;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
@consume({ context: localeContext, subscribe: true })
|
||||||
|
private locale!: ContextType<typeof localeContext>;
|
||||||
|
|
||||||
@state() private _items: PickerComboBoxItem[] = [];
|
@state() private _items: PickerComboBoxItem[] = [];
|
||||||
|
|
||||||
@state() private _selectedSection?: string;
|
@state() private _selectedSection?: string;
|
||||||
@@ -215,9 +222,9 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
|||||||
const searchLabel =
|
const searchLabel =
|
||||||
this.label ??
|
this.label ??
|
||||||
(this.allowCustomValue
|
(this.allowCustomValue
|
||||||
? (this.hass?.localize("ui.components.combo-box.search_or_custom") ??
|
? (this.localize?.("ui.components.combo-box.search_or_custom") ??
|
||||||
"Search | Add custom value")
|
"Search | Add custom value")
|
||||||
: (this.hass?.localize("ui.common.search") ?? "Search"));
|
: (this.localize?.("ui.common.search") ?? "Search"));
|
||||||
|
|
||||||
return html`<ha-textfield
|
return html`<ha-textfield
|
||||||
.label=${searchLabel}
|
.label=${searchLabel}
|
||||||
@@ -228,7 +235,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
|||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
@click=${this._clearSearch}
|
@click=${this._clearSearch}
|
||||||
slot="trailingIcon"
|
slot="trailingIcon"
|
||||||
.label=${this.hass?.localize("ui.common.clear") || "Clear"}
|
.label=${this.localize?.("ui.common.clear") || "Clear"}
|
||||||
.path=${mdiClose}
|
.path=${mdiClose}
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
</ha-textfield>
|
</ha-textfield>
|
||||||
@@ -350,7 +357,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
|||||||
return caseInsensitiveStringCompare(
|
return caseInsensitiveStringCompare(
|
||||||
sortLabelA,
|
sortLabelA,
|
||||||
sortLabelB,
|
sortLabelB,
|
||||||
this.hass?.locale.language ?? navigator.language
|
this.locale?.language ?? navigator.language
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -367,7 +374,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
|||||||
id: this._search,
|
id: this._search,
|
||||||
primary:
|
primary:
|
||||||
this.customValueLabel ??
|
this.customValueLabel ??
|
||||||
this.hass?.localize("ui.components.combo-box.add_custom_item") ??
|
this.localize?.("ui.components.combo-box.add_custom_item") ??
|
||||||
"Add custom item",
|
"Add custom item",
|
||||||
secondary: `"${this._search}"`,
|
secondary: `"${this._search}"`,
|
||||||
icon_path: mdiPlus,
|
icon_path: mdiPlus,
|
||||||
@@ -401,10 +408,10 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
|||||||
? typeof this.notFoundLabel === "function"
|
? typeof this.notFoundLabel === "function"
|
||||||
? this.notFoundLabel(this._search)
|
? this.notFoundLabel(this._search)
|
||||||
: this.notFoundLabel ||
|
: this.notFoundLabel ||
|
||||||
this.hass?.localize("ui.components.combo-box.no_match") ||
|
this.localize?.("ui.components.combo-box.no_match") ||
|
||||||
"No matching items found"
|
"No matching items found"
|
||||||
: this.emptyLabel ||
|
: this.emptyLabel ||
|
||||||
this.hass?.localize("ui.components.combo-box.no_items") ||
|
this.localize?.("ui.components.combo-box.no_items") ||
|
||||||
"No items available"}</span
|
"No items available"}</span
|
||||||
>
|
>
|
||||||
</ha-combo-box-item>
|
</ha-combo-box-item>
|
||||||
@@ -503,7 +510,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
|||||||
id: searchString,
|
id: searchString,
|
||||||
primary:
|
primary:
|
||||||
this.customValueLabel ??
|
this.customValueLabel ??
|
||||||
this.hass?.localize("ui.components.combo-box.add_custom_item") ??
|
this.localize?.("ui.components.combo-box.add_custom_item") ??
|
||||||
"Add custom item",
|
"Add custom item",
|
||||||
secondary: `"${searchString}"`,
|
secondary: `"${searchString}"`,
|
||||||
icon_path: mdiPlus,
|
icon_path: mdiPlus,
|
||||||
|
|||||||
@@ -34,3 +34,5 @@ export const labelsContext = createContext<LabelRegistryEntry[]>("labels");
|
|||||||
|
|
||||||
export const configEntriesContext =
|
export const configEntriesContext =
|
||||||
createContext<ConfigEntry[]>("configEntries");
|
createContext<ConfigEntry[]>("configEntries");
|
||||||
|
|
||||||
|
export const authContext = createContext<HomeAssistant["auth"]>("auth");
|
||||||
|
|||||||
55
src/dialogs/dialog-mixin.ts
Normal file
55
src/dialogs/dialog-mixin.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import type { LitElement } from "lit";
|
||||||
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import type { HaDialog } from "../components/ha-dialog";
|
||||||
|
import type { Constructor } from "../types";
|
||||||
|
import type { HassDialogNext } from "./make-dialog-manager";
|
||||||
|
|
||||||
|
export const DialogMixin = <
|
||||||
|
P = unknown,
|
||||||
|
T extends Constructor<LitElement> = Constructor<LitElement>,
|
||||||
|
>(
|
||||||
|
superClass: T
|
||||||
|
) =>
|
||||||
|
class extends superClass implements HassDialogNext<P> {
|
||||||
|
declare public params?: P;
|
||||||
|
|
||||||
|
private _closePromise?: Promise<boolean>;
|
||||||
|
|
||||||
|
private _closeResolve?: (value: boolean) => void;
|
||||||
|
|
||||||
|
public closeDialog(_historyState?: any): Promise<boolean> | boolean {
|
||||||
|
if (this._closePromise) {
|
||||||
|
return this._closePromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dialogElement = this.shadowRoot?.querySelector(
|
||||||
|
"ha-dialog"
|
||||||
|
) as HaDialog | null;
|
||||||
|
if (dialogElement) {
|
||||||
|
this._closePromise = new Promise<boolean>((resolve) => {
|
||||||
|
this._closeResolve = resolve;
|
||||||
|
});
|
||||||
|
dialogElement.open = false;
|
||||||
|
}
|
||||||
|
return this._closePromise || true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _removeDialog = (ev) => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this._closeResolve?.(true);
|
||||||
|
this._closePromise = undefined;
|
||||||
|
this._closeResolve = undefined;
|
||||||
|
this.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.addEventListener("closed", this._removeDialog, { once: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
|
this.removeEventListener("closed", this._removeDialog);
|
||||||
|
super.disconnectedCallback();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import type { LitElement } from "lit";
|
||||||
import { ancestorsWithProperty } from "../common/dom/ancestors-with-property";
|
import { ancestorsWithProperty } from "../common/dom/ancestors-with-property";
|
||||||
import { deepActiveElement } from "../common/dom/deep-active-element";
|
import { deepActiveElement } from "../common/dom/deep-active-element";
|
||||||
import type { HASSDomEvent, ValidHassDomEvent } from "../common/dom/fire_event";
|
import type { HASSDomEvent } from "../common/dom/fire_event";
|
||||||
import { mainWindow } from "../common/dom/get_main_window";
|
import { mainWindow } from "../common/dom/get_main_window";
|
||||||
import { nextRender } from "../common/util/render-status";
|
import { nextRender } from "../common/util/render-status";
|
||||||
import type { ProvideHassElement } from "../mixins/provide-hass-lit-mixin";
|
import type { ProvideHassElement } from "../mixins/provide-hass-lit-mixin";
|
||||||
@@ -19,18 +20,22 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HassDialog<
|
export interface HassDialog<T = unknown> extends HTMLElement {
|
||||||
T = HASSDomEvents[ValidHassDomEvent],
|
|
||||||
> extends HTMLElement {
|
|
||||||
showDialog(params: T);
|
showDialog(params: T);
|
||||||
closeDialog?: (historyState?: any) => boolean;
|
closeDialog?: (historyState?: any) => Promise<boolean> | boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ShowDialogParams<T> {
|
export interface HassDialogNext<T = unknown> extends HTMLElement {
|
||||||
|
params?: T;
|
||||||
|
closeDialog?: (historyState?: any) => Promise<boolean> | boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ShowDialogParams<T> {
|
||||||
dialogTag: keyof HTMLElementTagNameMap;
|
dialogTag: keyof HTMLElementTagNameMap;
|
||||||
dialogImport: () => Promise<unknown>;
|
dialogImport: () => Promise<unknown>;
|
||||||
dialogParams: T;
|
dialogParams?: T;
|
||||||
addHistory?: boolean;
|
addHistory?: boolean;
|
||||||
|
parentElement?: LitElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DialogClosedParams {
|
export interface DialogClosedParams {
|
||||||
@@ -39,7 +44,6 @@ export interface DialogClosedParams {
|
|||||||
|
|
||||||
export interface DialogState {
|
export interface DialogState {
|
||||||
element: HTMLElement & ProvideHassElement;
|
element: HTMLElement & ProvideHassElement;
|
||||||
root: ShadowRoot | HTMLElement;
|
|
||||||
dialogTag: string;
|
dialogTag: string;
|
||||||
dialogParams: unknown;
|
dialogParams: unknown;
|
||||||
dialogImport?: () => Promise<unknown>;
|
dialogImport?: () => Promise<unknown>;
|
||||||
@@ -47,7 +51,7 @@ export interface DialogState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface LoadedDialogInfo {
|
interface LoadedDialogInfo {
|
||||||
element: Promise<HassDialog>;
|
element: Promise<HassDialogNext | HassDialog> | null;
|
||||||
closedFocusTargets?: Set<Element>;
|
closedFocusTargets?: Set<Element>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,12 +61,24 @@ const LOADED: LoadedDialogsDict = {};
|
|||||||
const OPEN_DIALOG_STACK: DialogState[] = [];
|
const OPEN_DIALOG_STACK: DialogState[] = [];
|
||||||
export const FOCUS_TARGET = Symbol.for("HA focus target");
|
export const FOCUS_TARGET = Symbol.for("HA focus target");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a dialog element, lazy-loading it if needed, and optionally integrates
|
||||||
|
* dialog open/close behavior with browser history.
|
||||||
|
*
|
||||||
|
* @param element The host element that can provide `hass` and receives the dialog by default.
|
||||||
|
* @param dialogTag The custom element tag name of the dialog.
|
||||||
|
* @param dialogParams The params passed to the dialog via `showDialog()` or `params`.
|
||||||
|
* @param dialogImport Optional lazy import used when the dialog has not been loaded yet.
|
||||||
|
* @param parentElement Optional parent to append the dialog to instead of root element.
|
||||||
|
* @param addHistory Whether to add/update browser history so back navigation closes dialogs.
|
||||||
|
* @returns `true` if the dialog was shown (or could be shown), `false` if it could not be loaded.
|
||||||
|
*/
|
||||||
export const showDialog = async (
|
export const showDialog = async (
|
||||||
element: HTMLElement & ProvideHassElement,
|
element: LitElement & ProvideHassElement,
|
||||||
root: ShadowRoot | HTMLElement,
|
|
||||||
dialogTag: string,
|
dialogTag: string,
|
||||||
dialogParams: unknown,
|
dialogParams: unknown,
|
||||||
dialogImport?: () => Promise<unknown>,
|
dialogImport?: () => Promise<unknown>,
|
||||||
|
parentElement?: LitElement,
|
||||||
addHistory = true
|
addHistory = true
|
||||||
): Promise<boolean> => {
|
): Promise<boolean> => {
|
||||||
if (!(dialogTag in LOADED)) {
|
if (!(dialogTag in LOADED)) {
|
||||||
@@ -77,10 +93,18 @@ export const showDialog = async (
|
|||||||
}
|
}
|
||||||
LOADED[dialogTag] = {
|
LOADED[dialogTag] = {
|
||||||
element: dialogImport().then(() => {
|
element: dialogImport().then(() => {
|
||||||
const dialogEl = document.createElement(dialogTag) as HassDialog;
|
const dialogEl = document.createElement(dialogTag) as
|
||||||
element.provideHass(dialogEl);
|
| HassDialogNext
|
||||||
|
| HassDialog;
|
||||||
|
|
||||||
|
if ("showDialog" in dialogEl) {
|
||||||
|
// provide hass for legacy persistent dialogs
|
||||||
|
element.provideHass(dialogEl);
|
||||||
|
}
|
||||||
|
|
||||||
dialogEl.addEventListener("dialog-closed", _handleClosed);
|
dialogEl.addEventListener("dialog-closed", _handleClosed);
|
||||||
dialogEl.addEventListener("dialog-closed", _handleClosedFocus);
|
dialogEl.addEventListener("dialog-closed", _handleClosedFocus);
|
||||||
|
|
||||||
return dialogEl;
|
return dialogEl;
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@@ -96,10 +120,10 @@ export const showDialog = async (
|
|||||||
});
|
});
|
||||||
return showDialog(
|
return showDialog(
|
||||||
element,
|
element,
|
||||||
root,
|
|
||||||
dialogTag,
|
dialogTag,
|
||||||
dialogParams,
|
dialogParams,
|
||||||
dialogImport,
|
dialogImport,
|
||||||
|
parentElement,
|
||||||
addHistory
|
addHistory
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -111,7 +135,6 @@ export const showDialog = async (
|
|||||||
}
|
}
|
||||||
OPEN_DIALOG_STACK.push({
|
OPEN_DIALOG_STACK.push({
|
||||||
element,
|
element,
|
||||||
root,
|
|
||||||
dialogTag,
|
dialogTag,
|
||||||
dialogParams,
|
dialogParams,
|
||||||
dialogImport,
|
dialogImport,
|
||||||
@@ -134,12 +157,24 @@ export const showDialog = async (
|
|||||||
FOCUS_TARGET
|
FOCUS_TARGET
|
||||||
);
|
);
|
||||||
|
|
||||||
const dialogElement = await LOADED[dialogTag].element;
|
let dialogElement: HassDialogNext | HassDialog | null;
|
||||||
|
|
||||||
// Append it again so it's the last element in the root,
|
if (LOADED[dialogTag] && LOADED[dialogTag].element === null) {
|
||||||
// so it's guaranteed to be on top of the other elements
|
dialogElement = document.createElement(dialogTag) as HassDialogNext;
|
||||||
root.appendChild(dialogElement);
|
dialogElement.addEventListener("dialog-closed", _handleClosed);
|
||||||
dialogElement.showDialog(dialogParams);
|
dialogElement.addEventListener("dialog-closed", _handleClosedFocus);
|
||||||
|
LOADED[dialogTag].element = Promise.resolve(dialogElement);
|
||||||
|
} else {
|
||||||
|
dialogElement = await LOADED[dialogTag].element;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("showDialog" in dialogElement!) {
|
||||||
|
dialogElement.showDialog(dialogParams);
|
||||||
|
} else {
|
||||||
|
dialogElement!.params = dialogParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
(parentElement || element).shadowRoot!.appendChild(dialogElement!);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -152,7 +187,7 @@ export const closeDialog = async (
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const dialogElement = await LOADED[dialogTag].element;
|
const dialogElement = await LOADED[dialogTag].element;
|
||||||
if (dialogElement.closeDialog) {
|
if (dialogElement && dialogElement.closeDialog) {
|
||||||
return dialogElement.closeDialog(historyState) !== false;
|
return dialogElement.closeDialog(historyState) !== false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -214,22 +249,34 @@ const _handleClosed = (ev: HASSDomEvent<DialogClosedParams>) => {
|
|||||||
mainWindow.history.back();
|
mainWindow.history.back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cleanup element
|
||||||
|
if (ev.currentTarget && "params" in ev.currentTarget) {
|
||||||
|
const dialogElement = ev.currentTarget as HassDialogNext;
|
||||||
|
dialogElement.removeEventListener("dialog-closed", _handleClosed);
|
||||||
|
dialogElement.removeEventListener("dialog-closed", _handleClosedFocus);
|
||||||
|
LOADED[ev.detail.dialog].element = null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const makeDialogManager = (
|
export const makeDialogManager = (element: LitElement & ProvideHassElement) => {
|
||||||
element: HTMLElement & ProvideHassElement,
|
|
||||||
root: ShadowRoot | HTMLElement
|
|
||||||
) => {
|
|
||||||
element.addEventListener(
|
element.addEventListener(
|
||||||
"show-dialog",
|
"show-dialog",
|
||||||
(e: HASSDomEvent<ShowDialogParams<unknown>>) => {
|
(e: HASSDomEvent<ShowDialogParams<unknown>>) => {
|
||||||
const { dialogTag, dialogImport, dialogParams, addHistory } = e.detail;
|
const {
|
||||||
|
dialogTag,
|
||||||
|
dialogImport,
|
||||||
|
dialogParams,
|
||||||
|
addHistory,
|
||||||
|
parentElement,
|
||||||
|
} = e.detail;
|
||||||
|
|
||||||
showDialog(
|
showDialog(
|
||||||
element,
|
element,
|
||||||
root,
|
|
||||||
dialogTag,
|
dialogTag,
|
||||||
dialogParams,
|
dialogParams,
|
||||||
dialogImport,
|
dialogImport,
|
||||||
|
parentElement,
|
||||||
addHistory
|
addHistory
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ export interface MoreInfoDialogParams {
|
|||||||
tab?: View;
|
tab?: View;
|
||||||
large?: boolean;
|
large?: boolean;
|
||||||
data?: Record<string, any>;
|
data?: Record<string, any>;
|
||||||
|
parentElement?: LitElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
type View = "info" | "history" | "settings" | "related" | "add_to";
|
type View = "info" | "history" | "settings" | "related" | "add_to";
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ export class QuickBar extends LitElement {
|
|||||||
private _dialogOpened = async () => {
|
private _dialogOpened = async () => {
|
||||||
this._opened = true;
|
this._opened = true;
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
if (this.hass && isIosApp(this.hass)) {
|
if (this.hass && isIosApp(this.hass.auth.external)) {
|
||||||
this.hass.auth.external!.fireMessage({
|
this.hass.auth.external!.fireMessage({
|
||||||
type: "focus_element",
|
type: "focus_element",
|
||||||
payload: {
|
payload: {
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
|
import { consume, type ContextType } from "@lit/context";
|
||||||
import { css, html, LitElement } from "lit";
|
import { css, html, LitElement } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
|
||||||
import type { LocalizeKeys } from "../../common/translations/localize";
|
import type { LocalizeKeys } from "../../common/translations/localize";
|
||||||
import "../../components/ha-alert";
|
import "../../components/ha-alert";
|
||||||
import "../../components/ha-svg-icon";
|
|
||||||
import "../../components/ha-dialog";
|
import "../../components/ha-dialog";
|
||||||
import type { HomeAssistant } from "../../types";
|
import "../../components/ha-svg-icon";
|
||||||
|
import { localizeContext } from "../../data/context";
|
||||||
import { isMac } from "../../util/is_mac";
|
import { isMac } from "../../util/is_mac";
|
||||||
|
import { DialogMixin } from "../dialog-mixin";
|
||||||
|
|
||||||
interface Text {
|
interface Text {
|
||||||
textTranslationKey: LocalizeKeys;
|
textTranslationKey: LocalizeKeys;
|
||||||
@@ -165,24 +166,10 @@ const _SHORTCUTS: Section[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
@customElement("dialog-shortcuts")
|
@customElement("dialog-shortcuts")
|
||||||
class DialogShortcuts extends LitElement {
|
class DialogShortcuts extends DialogMixin(LitElement) {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@state()
|
||||||
|
@consume({ context: localizeContext, subscribe: true })
|
||||||
@state() private _open = false;
|
private localize!: ContextType<typeof localizeContext>;
|
||||||
|
|
||||||
public async showDialog(): Promise<void> {
|
|
||||||
this._open = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _dialogClosed() {
|
|
||||||
this._open = false;
|
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
|
||||||
}
|
|
||||||
|
|
||||||
public async closeDialog() {
|
|
||||||
this._open = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _renderShortcut(
|
private _renderShortcut(
|
||||||
shortcutKeys: ShortcutString[],
|
shortcutKeys: ShortcutString[],
|
||||||
@@ -196,15 +183,13 @@ class DialogShortcuts extends LitElement {
|
|||||||
>${shortcutKey === CTRL_CMD
|
>${shortcutKey === CTRL_CMD
|
||||||
? isMac
|
? isMac
|
||||||
? "⌘"
|
? "⌘"
|
||||||
: this.hass.localize("ui.dialogs.shortcuts.keys.ctrl")
|
: this.localize("ui.dialogs.shortcuts.keys.ctrl")
|
||||||
: typeof shortcutKey === "string"
|
: typeof shortcutKey === "string"
|
||||||
? shortcutKey
|
? shortcutKey
|
||||||
: this.hass.localize(
|
: this.localize(shortcutKey.shortcutTranslationKey)}</span
|
||||||
shortcutKey.shortcutTranslationKey
|
|
||||||
)}</span
|
|
||||||
>`
|
>`
|
||||||
)}
|
)}
|
||||||
${this.hass.localize(descriptionKey)}
|
${this.localize(descriptionKey)}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -212,14 +197,13 @@ class DialogShortcuts extends LitElement {
|
|||||||
protected render() {
|
protected render() {
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
<ha-dialog
|
||||||
.open=${this._open}
|
open
|
||||||
@closed=${this._dialogClosed}
|
.headerTitle=${this.localize("ui.dialogs.shortcuts.title")}
|
||||||
.headerTitle=${this.hass.localize("ui.dialogs.shortcuts.title")}
|
|
||||||
>
|
>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
${_SHORTCUTS.map(
|
${_SHORTCUTS.map(
|
||||||
(section) => html`
|
(section) => html`
|
||||||
<h3>${this.hass.localize(section.titleTranslationKey)}</h3>
|
<h3>${this.localize(section.titleTranslationKey)}</h3>
|
||||||
<div class="items">
|
<div class="items">
|
||||||
${section.items.map((item) => {
|
${section.items.map((item) => {
|
||||||
if ("shortcut" in item) {
|
if ("shortcut" in item) {
|
||||||
@@ -229,7 +213,7 @@ class DialogShortcuts extends LitElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return html`<p>
|
return html`<p>
|
||||||
${this.hass.localize((item as Text).textTranslationKey)}
|
${this.localize((item as Text).textTranslationKey)}
|
||||||
</p>`;
|
</p>`;
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
@@ -238,9 +222,9 @@ class DialogShortcuts extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ha-alert slot="footer">
|
<ha-alert slot="footer">
|
||||||
${this.hass.localize("ui.dialogs.shortcuts.enable_shortcuts_hint", {
|
${this.localize("ui.dialogs.shortcuts.enable_shortcuts_hint", {
|
||||||
user_profile: html`<a href="/profile/general#shortcuts"
|
user_profile: html`<a href="/profile/general#shortcuts"
|
||||||
>${this.hass.localize(
|
>${this.localize(
|
||||||
"ui.dialogs.shortcuts.enable_shortcuts_hint_user_profile"
|
"ui.dialogs.shortcuts.enable_shortcuts_hint_user_profile"
|
||||||
)}</a
|
)}</a
|
||||||
>`,
|
>`,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import type { LitElement } from "lit";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
|
|
||||||
export const showShortcutsDialog = (element: HTMLElement) =>
|
export const showShortcutsDialog = (element: LitElement) =>
|
||||||
fireEvent(element, "show-dialog", {
|
fireEvent(element, "show-dialog", {
|
||||||
dialogTag: "dialog-shortcuts",
|
dialogTag: "dialog-shortcuts",
|
||||||
dialogImport: () => import("./dialog-shortcuts"),
|
dialogImport: () => import("./dialog-shortcuts"),
|
||||||
dialogParams: {},
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) {
|
|||||||
) {
|
) {
|
||||||
import("../resources/particles");
|
import("../resources/particles");
|
||||||
}
|
}
|
||||||
makeDialogManager(this, this.shadowRoot!);
|
makeDialogManager(this);
|
||||||
import("../components/ha-language-picker");
|
import("../components/ha-language-picker");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
|
import { consume, type ContextType } from "@lit/context";
|
||||||
import type { CSSResultGroup } from "lit";
|
import type { CSSResultGroup } from "lit";
|
||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
|
||||||
import "../../../components/ha-alert";
|
import "../../../components/ha-alert";
|
||||||
|
import "../../../components/ha-button";
|
||||||
import "../../../components/ha-dialog";
|
import "../../../components/ha-dialog";
|
||||||
import "../../../components/ha-dialog-footer";
|
import "../../../components/ha-dialog-footer";
|
||||||
import "../../../components/ha-icon-picker";
|
import "../../../components/ha-icon-picker";
|
||||||
import "../../../components/ha-button";
|
|
||||||
import "../../../components/ha-textfield";
|
import "../../../components/ha-textfield";
|
||||||
import type {
|
import type {
|
||||||
CategoryRegistryEntry,
|
CategoryRegistryEntry,
|
||||||
CategoryRegistryEntryMutableParams,
|
CategoryRegistryEntryMutableParams,
|
||||||
} from "../../../data/category_registry";
|
} from "../../../data/category_registry";
|
||||||
|
import { localizeContext } from "../../../data/context";
|
||||||
|
import { DialogMixin } from "../../../dialogs/dialog-mixin";
|
||||||
import { haStyleDialog } from "../../../resources/styles";
|
import { haStyleDialog } from "../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../types";
|
|
||||||
import type { CategoryRegistryDetailDialogParams } from "./show-dialog-category-registry-detail";
|
import type { CategoryRegistryDetailDialogParams } from "./show-dialog-category-registry-detail";
|
||||||
|
|
||||||
@customElement("dialog-category-registry-detail")
|
@customElement("dialog-category-registry-detail")
|
||||||
class DialogCategoryDetail extends LitElement {
|
class DialogCategoryDetail extends DialogMixin<CategoryRegistryDetailDialogParams>(
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
LitElement
|
||||||
|
) {
|
||||||
|
@state()
|
||||||
|
@consume({ context: localizeContext, subscribe: true })
|
||||||
|
private localize!: ContextType<typeof localizeContext>;
|
||||||
|
|
||||||
@state() private _name!: string;
|
@state() private _name!: string;
|
||||||
|
|
||||||
@@ -26,53 +31,32 @@ class DialogCategoryDetail extends LitElement {
|
|||||||
|
|
||||||
@state() private _error?: string;
|
@state() private _error?: string;
|
||||||
|
|
||||||
@state() private _params?: CategoryRegistryDetailDialogParams;
|
|
||||||
|
|
||||||
@state() private _submitting?: boolean;
|
@state() private _submitting?: boolean;
|
||||||
|
|
||||||
@state() private _open = false;
|
public connectedCallback(): void {
|
||||||
|
super.connectedCallback();
|
||||||
public async showDialog(
|
if (this.params?.entry) {
|
||||||
params: CategoryRegistryDetailDialogParams
|
this._name = this.params.entry.name || "";
|
||||||
): Promise<void> {
|
this._icon = this.params.entry.icon || null;
|
||||||
this._params = params;
|
|
||||||
this._error = undefined;
|
|
||||||
this._open = true;
|
|
||||||
if (this._params.entry) {
|
|
||||||
this._name = this._params.entry.name || "";
|
|
||||||
this._icon = this._params.entry.icon || null;
|
|
||||||
} else {
|
} else {
|
||||||
this._name = this._params.suggestedName || "";
|
this._name = this.params?.suggestedName || "";
|
||||||
this._icon = null;
|
this._icon = null;
|
||||||
}
|
}
|
||||||
await this.updateComplete;
|
|
||||||
}
|
|
||||||
|
|
||||||
public closeDialog(): void {
|
|
||||||
this._open = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _dialogClosed(): void {
|
|
||||||
this._error = "";
|
|
||||||
this._params = undefined;
|
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
if (!this._params) {
|
if (!this.params) {
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
const entry = this._params.entry;
|
const entry = this.params.entry;
|
||||||
const nameInvalid = !this._isNameValid();
|
const nameInvalid = !this._isNameValid();
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
<ha-dialog
|
||||||
.hass=${this.hass}
|
open
|
||||||
.open=${this._open}
|
|
||||||
header-title=${entry
|
header-title=${entry
|
||||||
? this.hass.localize("ui.panel.config.category.editor.edit")
|
? this.localize("ui.panel.config.category.editor.edit")
|
||||||
: this.hass.localize("ui.panel.config.category.editor.create")}
|
: this.localize("ui.panel.config.category.editor.create")}
|
||||||
prevent-scrim-close
|
prevent-scrim-close
|
||||||
@closed=${this._dialogClosed}
|
|
||||||
>
|
>
|
||||||
${this._error
|
${this._error
|
||||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
@@ -81,8 +65,8 @@ class DialogCategoryDetail extends LitElement {
|
|||||||
<ha-textfield
|
<ha-textfield
|
||||||
.value=${this._name}
|
.value=${this._name}
|
||||||
@input=${this._nameChanged}
|
@input=${this._nameChanged}
|
||||||
.label=${this.hass.localize("ui.panel.config.category.editor.name")}
|
.label=${this.localize("ui.panel.config.category.editor.name")}
|
||||||
.validationMessage=${this.hass.localize(
|
.validationMessage=${this.localize(
|
||||||
"ui.panel.config.category.editor.required_error_msg"
|
"ui.panel.config.category.editor.required_error_msg"
|
||||||
)}
|
)}
|
||||||
required
|
required
|
||||||
@@ -90,10 +74,9 @@ class DialogCategoryDetail extends LitElement {
|
|||||||
></ha-textfield>
|
></ha-textfield>
|
||||||
|
|
||||||
<ha-icon-picker
|
<ha-icon-picker
|
||||||
.hass=${this.hass}
|
.value=${this._icon ?? undefined}
|
||||||
.value=${this._icon}
|
|
||||||
@value-changed=${this._iconChanged}
|
@value-changed=${this._iconChanged}
|
||||||
.label=${this.hass.localize("ui.panel.config.category.editor.icon")}
|
.label=${this.localize("ui.panel.config.category.editor.icon")}
|
||||||
></ha-icon-picker>
|
></ha-icon-picker>
|
||||||
</div>
|
</div>
|
||||||
<ha-dialog-footer slot="footer">
|
<ha-dialog-footer slot="footer">
|
||||||
@@ -102,7 +85,7 @@ class DialogCategoryDetail extends LitElement {
|
|||||||
appearance="plain"
|
appearance="plain"
|
||||||
@click=${this.closeDialog}
|
@click=${this.closeDialog}
|
||||||
>
|
>
|
||||||
${this.hass.localize("ui.common.cancel")}
|
${this.localize("ui.common.cancel")}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
<ha-button
|
<ha-button
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
@@ -110,8 +93,8 @@ class DialogCategoryDetail extends LitElement {
|
|||||||
.disabled=${nameInvalid || !!this._submitting}
|
.disabled=${nameInvalid || !!this._submitting}
|
||||||
>
|
>
|
||||||
${entry
|
${entry
|
||||||
? this.hass.localize("ui.common.save")
|
? this.localize("ui.common.save")
|
||||||
: this.hass.localize("ui.common.add")}
|
: this.localize("ui.common.add")}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
</ha-dialog-footer>
|
</ha-dialog-footer>
|
||||||
</ha-dialog>
|
</ha-dialog>
|
||||||
@@ -133,7 +116,7 @@ class DialogCategoryDetail extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _updateEntry() {
|
private async _updateEntry() {
|
||||||
const create = !this._params!.entry;
|
const create = !this.params!.entry;
|
||||||
this._submitting = true;
|
this._submitting = true;
|
||||||
let newValue: CategoryRegistryEntry | undefined;
|
let newValue: CategoryRegistryEntry | undefined;
|
||||||
try {
|
try {
|
||||||
@@ -142,15 +125,15 @@ class DialogCategoryDetail extends LitElement {
|
|||||||
icon: this._icon || (create ? undefined : null),
|
icon: this._icon || (create ? undefined : null),
|
||||||
};
|
};
|
||||||
if (create) {
|
if (create) {
|
||||||
newValue = await this._params!.createEntry!(values);
|
newValue = await this.params!.createEntry!(values);
|
||||||
} else {
|
} else {
|
||||||
newValue = await this._params!.updateEntry!(values);
|
newValue = await this.params!.updateEntry!(values);
|
||||||
}
|
}
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error =
|
this._error =
|
||||||
err.message ||
|
err.message ||
|
||||||
this.hass.localize("ui.panel.config.category.editor.unknown_error");
|
this.localize("ui.panel.config.category.editor.unknown_error");
|
||||||
} finally {
|
} finally {
|
||||||
this._submitting = false;
|
this._submitting = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,29 @@
|
|||||||
|
import { consume, type ContextType } from "@lit/context";
|
||||||
import type { CSSResultGroup } from "lit";
|
import type { CSSResultGroup } from "lit";
|
||||||
import { LitElement, css, html, nothing } from "lit";
|
import { LitElement, css, html, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
|
||||||
import "../../../components/ha-alert";
|
import "../../../components/ha-alert";
|
||||||
import "../../../components/ha-button";
|
import "../../../components/ha-button";
|
||||||
import "../../../components/ha-color-picker";
|
import "../../../components/ha-color-picker";
|
||||||
|
import "../../../components/ha-dialog";
|
||||||
import "../../../components/ha-dialog-footer";
|
import "../../../components/ha-dialog-footer";
|
||||||
import "../../../components/ha-icon-picker";
|
import "../../../components/ha-icon-picker";
|
||||||
import "../../../components/ha-switch";
|
import "../../../components/ha-switch";
|
||||||
import "../../../components/ha-dialog";
|
|
||||||
import "../../../components/ha-textarea";
|
import "../../../components/ha-textarea";
|
||||||
import "../../../components/ha-textfield";
|
import "../../../components/ha-textfield";
|
||||||
|
import { localizeContext } from "../../../data/context";
|
||||||
import type { LabelRegistryEntryMutableParams } from "../../../data/label/label_registry";
|
import type { LabelRegistryEntryMutableParams } from "../../../data/label/label_registry";
|
||||||
import type { HassDialog } from "../../../dialogs/make-dialog-manager";
|
import { DialogMixin } from "../../../dialogs/dialog-mixin";
|
||||||
import { haStyleDialog } from "../../../resources/styles";
|
import { haStyleDialog } from "../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../types";
|
|
||||||
import type { LabelDetailDialogParams } from "./show-dialog-label-detail";
|
import type { LabelDetailDialogParams } from "./show-dialog-label-detail";
|
||||||
|
|
||||||
@customElement("dialog-label-detail")
|
@customElement("dialog-label-detail")
|
||||||
class DialogLabelDetail
|
class DialogLabelDetail extends DialogMixin<LabelDetailDialogParams>(
|
||||||
extends LitElement
|
LitElement
|
||||||
implements HassDialog<LabelDetailDialogParams>
|
) {
|
||||||
{
|
@state()
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@consume({ context: localizeContext, subscribe: true })
|
||||||
|
private localize!: ContextType<typeof localizeContext>;
|
||||||
|
|
||||||
@state() private _name!: string;
|
@state() private _name!: string;
|
||||||
|
|
||||||
@@ -34,53 +35,35 @@ class DialogLabelDetail
|
|||||||
|
|
||||||
@state() private _error?: string;
|
@state() private _error?: string;
|
||||||
|
|
||||||
@state() private _params?: LabelDetailDialogParams;
|
|
||||||
|
|
||||||
@state() private _submitting = false;
|
@state() private _submitting = false;
|
||||||
|
|
||||||
@state() private _open = false;
|
public connectedCallback(): void {
|
||||||
|
super.connectedCallback();
|
||||||
public showDialog(params: LabelDetailDialogParams): void {
|
if (this.params?.entry) {
|
||||||
this._params = params;
|
this._name = this.params.entry.name || "";
|
||||||
this._error = undefined;
|
this._icon = this.params.entry.icon || "";
|
||||||
if (this._params.entry) {
|
this._color = this.params.entry.color || "";
|
||||||
this._name = this._params.entry.name || "";
|
this._description = this.params.entry.description || "";
|
||||||
this._icon = this._params.entry.icon || "";
|
|
||||||
this._color = this._params.entry.color || "";
|
|
||||||
this._description = this._params.entry.description || "";
|
|
||||||
} else {
|
} else {
|
||||||
this._name = this._params.suggestedName || "";
|
this._name = this.params?.suggestedName || "";
|
||||||
this._icon = "";
|
this._icon = "";
|
||||||
this._color = "";
|
this._color = "";
|
||||||
this._description = "";
|
this._description = "";
|
||||||
}
|
}
|
||||||
this._open = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public closeDialog() {
|
|
||||||
this._open = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _dialogClosed(): void {
|
|
||||||
this._params = undefined;
|
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
if (!this._params) {
|
if (!this.params) {
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
<ha-dialog
|
||||||
.hass=${this.hass}
|
open
|
||||||
.open=${this._open}
|
header-title=${this.params.entry
|
||||||
header-title=${this._params.entry
|
? this.params.entry.name || this.params.entry.label_id
|
||||||
? this._params.entry.name || this._params.entry.label_id
|
: this.localize("ui.dialogs.label-detail.new_label")}
|
||||||
: this.hass!.localize("ui.dialogs.label-detail.new_label")}
|
|
||||||
prevent-scrim-close
|
prevent-scrim-close
|
||||||
@closed=${this._dialogClosed}
|
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
${this._error
|
${this._error
|
||||||
@@ -92,39 +75,35 @@ class DialogLabelDetail
|
|||||||
.value=${this._name}
|
.value=${this._name}
|
||||||
.configValue=${"name"}
|
.configValue=${"name"}
|
||||||
@input=${this._input}
|
@input=${this._input}
|
||||||
.label=${this.hass!.localize("ui.dialogs.label-detail.name")}
|
.label=${this.localize("ui.dialogs.label-detail.name")}
|
||||||
.validationMessage=${this.hass!.localize(
|
.validationMessage=${this.localize(
|
||||||
"ui.dialogs.label-detail.required_error_msg"
|
"ui.dialogs.label-detail.required_error_msg"
|
||||||
)}
|
)}
|
||||||
required
|
required
|
||||||
></ha-textfield>
|
></ha-textfield>
|
||||||
<ha-icon-picker
|
<ha-icon-picker
|
||||||
.value=${this._icon}
|
.value=${this._icon}
|
||||||
.hass=${this.hass}
|
|
||||||
.configValue=${"icon"}
|
.configValue=${"icon"}
|
||||||
@value-changed=${this._valueChanged}
|
@value-changed=${this._valueChanged}
|
||||||
.label=${this.hass!.localize("ui.dialogs.label-detail.icon")}
|
.label=${this.localize("ui.dialogs.label-detail.icon")}
|
||||||
></ha-icon-picker>
|
></ha-icon-picker>
|
||||||
<ha-color-picker
|
<ha-color-picker
|
||||||
.value=${this._color}
|
.value=${this._color}
|
||||||
.configValue=${"color"}
|
.configValue=${"color"}
|
||||||
.hass=${this.hass}
|
|
||||||
@value-changed=${this._valueChanged}
|
@value-changed=${this._valueChanged}
|
||||||
.label=${this.hass!.localize("ui.dialogs.label-detail.color")}
|
.label=${this.localize("ui.dialogs.label-detail.color")}
|
||||||
></ha-color-picker>
|
></ha-color-picker>
|
||||||
<ha-textarea
|
<ha-textarea
|
||||||
.value=${this._description}
|
.value=${this._description}
|
||||||
.configValue=${"description"}
|
.configValue=${"description"}
|
||||||
@input=${this._input}
|
@input=${this._input}
|
||||||
.label=${this.hass!.localize(
|
.label=${this.localize("ui.dialogs.label-detail.description")}
|
||||||
"ui.dialogs.label-detail.description"
|
|
||||||
)}
|
|
||||||
></ha-textarea>
|
></ha-textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ha-dialog-footer slot="footer">
|
<ha-dialog-footer slot="footer">
|
||||||
${this._params.entry && this._params.removeEntry
|
${this.params.entry && this.params.removeEntry
|
||||||
? html`
|
? html`
|
||||||
<ha-button
|
<ha-button
|
||||||
slot="secondaryAction"
|
slot="secondaryAction"
|
||||||
@@ -133,7 +112,7 @@ class DialogLabelDetail
|
|||||||
@click=${this._deleteEntry}
|
@click=${this._deleteEntry}
|
||||||
.disabled=${this._submitting}
|
.disabled=${this._submitting}
|
||||||
>
|
>
|
||||||
${this.hass!.localize("ui.common.delete")}
|
${this.localize("ui.common.delete")}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
@@ -142,7 +121,7 @@ class DialogLabelDetail
|
|||||||
slot="secondaryAction"
|
slot="secondaryAction"
|
||||||
@click=${this.closeDialog}
|
@click=${this.closeDialog}
|
||||||
>
|
>
|
||||||
${this.hass.localize("ui.common.cancel")}
|
${this.localize("ui.common.cancel")}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
`}
|
`}
|
||||||
<ha-button
|
<ha-button
|
||||||
@@ -150,9 +129,9 @@ class DialogLabelDetail
|
|||||||
@click=${this._updateEntry}
|
@click=${this._updateEntry}
|
||||||
.disabled=${this._submitting || !this._name}
|
.disabled=${this._submitting || !this._name}
|
||||||
>
|
>
|
||||||
${this._params.entry
|
${this.params.entry
|
||||||
? this.hass!.localize("ui.common.update")
|
? this.localize("ui.common.update")
|
||||||
: this.hass!.localize("ui.common.create")}
|
: this.localize("ui.common.create")}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
</ha-dialog-footer>
|
</ha-dialog-footer>
|
||||||
</ha-dialog>
|
</ha-dialog>
|
||||||
@@ -184,10 +163,10 @@ class DialogLabelDetail
|
|||||||
color: this._color.trim() || null,
|
color: this._color.trim() || null,
|
||||||
description: this._description.trim() || null,
|
description: this._description.trim() || null,
|
||||||
};
|
};
|
||||||
if (this._params!.entry) {
|
if (this.params!.entry) {
|
||||||
await this._params!.updateEntry!(values);
|
await this.params!.updateEntry!(values);
|
||||||
} else {
|
} else {
|
||||||
await this._params!.createEntry!(values);
|
await this.params!.createEntry!(values);
|
||||||
}
|
}
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
@@ -200,8 +179,8 @@ class DialogLabelDetail
|
|||||||
private async _deleteEntry() {
|
private async _deleteEntry() {
|
||||||
this._submitting = true;
|
this._submitting = true;
|
||||||
try {
|
try {
|
||||||
if (await this._params!.removeEntry!()) {
|
if (await this.params!.removeEntry!()) {
|
||||||
this._params = undefined;
|
this.params = undefined;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this._submitting = false;
|
this._submitting = false;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ContextProvider } from "@lit/context";
|
|||||||
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import {
|
import {
|
||||||
areasContext,
|
areasContext,
|
||||||
|
authContext,
|
||||||
configContext,
|
configContext,
|
||||||
connectionContext,
|
connectionContext,
|
||||||
devicesContext,
|
devicesContext,
|
||||||
@@ -101,6 +102,10 @@ export const contextMixin = <T extends Constructor<HassBaseEl>>(
|
|||||||
context: labelsContext,
|
context: labelsContext,
|
||||||
initialValue: [],
|
initialValue: [],
|
||||||
}),
|
}),
|
||||||
|
auth: new ContextProvider(this, {
|
||||||
|
context: authContext,
|
||||||
|
initialValue: this.hass?.auth,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
protected hassConnected() {
|
protected hassConnected() {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export const dialogManagerMixin = <T extends Constructor<HassBaseEl>>(
|
|||||||
this.addEventListener("register-dialog", (e) =>
|
this.addEventListener("register-dialog", (e) =>
|
||||||
this.registerDialog(e.detail)
|
this.registerDialog(e.detail)
|
||||||
);
|
);
|
||||||
makeDialogManager(this, this.shadowRoot!);
|
makeDialogManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected registerDialog({
|
protected registerDialog({
|
||||||
@@ -44,10 +44,10 @@ export const dialogManagerMixin = <T extends Constructor<HassBaseEl>>(
|
|||||||
this.addEventListener(dialogShowEvent, (showEv) => {
|
this.addEventListener(dialogShowEvent, (showEv) => {
|
||||||
showDialog(
|
showDialog(
|
||||||
this,
|
this,
|
||||||
this.shadowRoot!,
|
|
||||||
dialogTag,
|
dialogTag,
|
||||||
(showEv as HASSDomEvent<unknown>).detail,
|
(showEv as HASSDomEvent<unknown>).detail,
|
||||||
dialogImport,
|
dialogImport,
|
||||||
|
undefined,
|
||||||
addHistory
|
addHistory
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
|||||||
private async _handleMoreInfo(ev: HASSDomEvent<MoreInfoDialogParams>) {
|
private async _handleMoreInfo(ev: HASSDomEvent<MoreInfoDialogParams>) {
|
||||||
showDialog(
|
showDialog(
|
||||||
this,
|
this,
|
||||||
this.shadowRoot!,
|
|
||||||
"ha-more-info-dialog",
|
"ha-more-info-dialog",
|
||||||
{
|
{
|
||||||
entityId: ev.detail.entityId,
|
entityId: ev.detail.entityId,
|
||||||
@@ -42,7 +41,8 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
|||||||
: false),
|
: false),
|
||||||
data: ev.detail.data,
|
data: ev.detail.data,
|
||||||
},
|
},
|
||||||
() => import("../dialogs/more-info/ha-more-info-dialog")
|
() => import("../dialogs/more-info/ha-more-info-dialog"),
|
||||||
|
ev.detail.parentElement
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
import { isSafari } from "./is_safari";
|
import { isSafari } from "./is_safari";
|
||||||
|
|
||||||
export const isIosApp = (hass: HomeAssistant): boolean =>
|
export const isIosApp = (
|
||||||
!!hass.auth.external && isSafari;
|
authExternal: HomeAssistant["auth"]["external"]
|
||||||
|
): boolean => !!authExternal && isSafari;
|
||||||
|
|||||||
Reference in New Issue
Block a user