Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions src/components/ha-form/ha-form-multi_select.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import "@polymer/paper-checkbox/paper-checkbox";
import "@polymer/paper-menu-button/paper-menu-button";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-icon-item";
import "@polymer/paper-listbox/paper-listbox";
import "@polymer/paper-ripple/paper-ripple";
import {
customElement,
html,
LitElement,
property,
query,
TemplateResult,
CSSResult,
css,
} from "lit-element";
import { fireEvent } from "../../common/dom/fire_event";
import {
HaFormElement,
HaFormMultiSelectData,
HaFormMultiSelectSchema,
} from "./ha-form";

@customElement("ha-form-multi_select")
export class HaFormMultiSelect extends LitElement implements HaFormElement {
@property() public schema!: HaFormMultiSelectSchema;
@property() public data!: HaFormMultiSelectData;
@property() public label!: string;
@property() public suffix!: string;
@property() private _init = false;
@query("paper-menu-button") private _input?: HTMLElement;

public focus(): void {
if (this._input) {
this._input.focus();
}
}

protected render(): TemplateResult {
const options = Array.isArray(this.schema.options)
? this.schema.options
: Object.entries(this.schema.options!);

return html`
<paper-menu-button horizontal-align="right" vertical-offset="8">
<div class="dropdown-trigger" slot="dropdown-trigger">
<paper-ripple></paper-ripple>
<paper-input
id="input"
type="text"
readonly
value=${this.data
.map((value) => this.schema.options![value] || value)
.join(", ")}
label=${this.label}
input-role="button"
input-aria-haspopup="listbox"
autocomplete="off"
>
<iron-icon
icon="paper-dropdown-menu:arrow-drop-down"
suffix
slot="suffix"
></iron-icon>
</paper-input>
</div>
<paper-listbox
multi
slot="dropdown-content"
attr-for-selected="item-value"
.selectedValues=${this.data}
@selected-items-changed=${this._valueChanged}
@iron-select=${this._onSelect}
>
${// TS doesn't work with union array types https://github.com/microsoft/TypeScript/issues/36390
// @ts-ignore
options.map((item: string | [string, string]) => {
const value = this._optionValue(item);
return html`
<paper-icon-item .itemValue=${value}>
<paper-checkbox
.checked=${this.data.includes(value)}
slot="item-icon"
></paper-checkbox>
${this._optionLabel(item)}
</paper-icon-item>
`;
})}
</paper-listbox>
</paper-menu-button>
`;
}

protected firstUpdated() {
this.updateComplete.then(() => {
const input = (this.shadowRoot?.querySelector("paper-input")
?.inputElement as any)?.inputElement;
if (input) {
input.style.textOverflow = "ellipsis";
}
});
}

private _optionValue(item: string | string[]): string {
return Array.isArray(item) ? item[0] : item;
}

private _optionLabel(item: string | string[]): string {
return Array.isArray(item) ? item[1] || item[0] : item;
}

private _onSelect(ev: Event) {
ev.stopPropagation();
}

private _valueChanged(ev: CustomEvent): void {
if (!ev.detail.value || !this._init) {
// ignore first call because that is the init of the component
this._init = true;
return;
}

fireEvent(
this,
"value-changed",
{
value: ev.detail.value.map((element) => element.itemValue),
},
{ bubbles: false }
);
}

static get styles(): CSSResult {
return css`
paper-menu-button {
display: block;
padding: 0;
--paper-item-icon-width: 34px;
}
paper-ripple {
top: 12px;
left: 0px;
bottom: 8px;
right: 0px;
}
paper-input {
text-overflow: ellipsis;
}
`;
}
}

declare global {
interface HTMLElementTagNameMap {
"ha-form-multi_select": HaFormMultiSelect;
}
}
22 changes: 17 additions & 5 deletions src/components/ha-form/ha-form-select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
property,
TemplateResult,
query,
CSSResult,
css,
} from "lit-element";
import { HaFormElement, HaFormSelectData, HaFormSelectSchema } from "./ha-form";
import { fireEvent } from "../../common/dom/fire_event";
Expand Down Expand Up @@ -36,8 +38,10 @@ export class HaFormSelect extends LitElement implements HaFormElement {
.selected=${this.data}
@selected-item-changed=${this._valueChanged}
>
${this.schema.options!.map(
(item) => html`
${// TS doesn't work with union array types https://github.com/microsoft/TypeScript/issues/36390
// @ts-ignore
this.schema.options!.map(
(item: string | [string, string]) => html`
<paper-item .itemValue=${this._optionValue(item)}>
${this._optionLabel(item)}
</paper-item>
Expand All @@ -48,12 +52,12 @@ export class HaFormSelect extends LitElement implements HaFormElement {
`;
}

private _optionValue(item) {
private _optionValue(item: string | [string, string]) {
return Array.isArray(item) ? item[0] : item;
}

private _optionLabel(item) {
return Array.isArray(item) ? item[1] : item;
private _optionLabel(item: string | [string, string]) {
return Array.isArray(item) ? item[1] || item[0] : item;
}

private _valueChanged(ev: CustomEvent) {
Expand All @@ -64,6 +68,14 @@ export class HaFormSelect extends LitElement implements HaFormElement {
value: ev.detail.value.itemValue,
});
}

static get styles(): CSSResult {
return css`
paper-dropdown-menu {
display: block;
}
`;
}
}

declare global {
Expand Down
11 changes: 10 additions & 1 deletion src/components/ha-form/ha-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import "./ha-form-integer";
import "./ha-form-float";
import "./ha-form-boolean";
import "./ha-form-select";
import "./ha-form-multi_select";
import "./ha-form-positive_time_period_dict";
import { fireEvent } from "../../common/dom/fire_event";
import { dynamicElement } from "../../common/dom/dynamic-element-directive";
Expand All @@ -22,6 +23,7 @@ export type HaFormSchema =
| HaFormFloatSchema
| HaFormBooleanSchema
| HaFormSelectSchema
| HaFormMultiSelectSchema
| HaFormTimeSchema;

export interface HaFormBaseSchema {
Expand All @@ -41,7 +43,12 @@ export interface HaFormIntegerSchema extends HaFormBaseSchema {

export interface HaFormSelectSchema extends HaFormBaseSchema {
type: "select";
options?: string[];
options?: string[] | Array<[string, string]>;
}

export interface HaFormMultiSelectSchema extends HaFormBaseSchema {
type: "multi_select";
Comment thread
balloob marked this conversation as resolved.
options?: { [key: string]: string } | string[] | Array<[string, string]>;
}

export interface HaFormFloatSchema extends HaFormBaseSchema {
Expand Down Expand Up @@ -71,13 +78,15 @@ export type HaFormData =
| HaFormFloatData
| HaFormBooleanData
| HaFormSelectData
| HaFormMultiSelectData
| HaFormTimeData;

export type HaFormStringData = string;
export type HaFormIntegerData = number;
export type HaFormFloatData = number;
export type HaFormBooleanData = boolean;
export type HaFormSelectData = string;
export type HaFormMultiSelectData = string[];
export interface HaFormTimeData {
hours?: number;
minutes?: number;
Expand Down
10 changes: 3 additions & 7 deletions src/data/data_entry_flow.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { HaFormSchema } from "../components/ha-form/ha-form";

export interface DataEntryFlowProgressedEvent {
type: "data_entry_flow_progressed";
data: {
Expand All @@ -7,12 +9,6 @@ export interface DataEntryFlowProgressedEvent {
};
}

export interface FieldSchema {
name: string;
default?: any;
optional: boolean;
}

export interface DataEntryFlowProgress {
flow_id: string;
handler: string;
Expand All @@ -27,7 +23,7 @@ export interface DataEntryFlowStepForm {
flow_id: string;
handler: string;
step_id: string;
data_schema: FieldSchema[];
data_schema: HaFormSchema[];
errors: { [key: string]: string };
description_placeholders: { [key: string]: string };
}
Expand Down
4 changes: 2 additions & 2 deletions src/dialogs/config-flow/show-dialog-data-entry-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {
DataEntryFlowStepForm,
DataEntryFlowStep,
DataEntryFlowStepAbort,
FieldSchema,
} from "../../data/data_entry_flow";
import { HaFormSchema } from "../../components/ha-form/ha-form";

export interface FlowConfig {
loadDevicesAndAreas: boolean;
Expand Down Expand Up @@ -45,7 +45,7 @@ export interface FlowConfig {
renderShowFormStepFieldLabel(
hass: HomeAssistant,
step: DataEntryFlowStepForm,
field: FieldSchema
field: HaFormSchema
): string;

renderShowFormStepFieldError(
Expand Down
6 changes: 4 additions & 2 deletions src/dialogs/config-flow/step-flow-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ import "../../resources/ha-style";
import { HomeAssistant } from "../../types";
import { fireEvent } from "../../common/dom/fire_event";
import { configFlowContentStyles } from "./styles";
import { DataEntryFlowStepForm, FieldSchema } from "../../data/data_entry_flow";
import { DataEntryFlowStepForm } from "../../data/data_entry_flow";
import { FlowConfig } from "./show-dialog-data-entry-flow";
// tslint:disable-next-line
import { HaFormSchema } from "../../components/ha-form/ha-form";

@customElement("step-flow-form")
class StepFlowForm extends LitElement {
Expand Down Expand Up @@ -176,7 +178,7 @@ class StepFlowForm extends LitElement {
this._stepData = ev.detail.value;
}

private _labelCallback = (field: FieldSchema): string =>
private _labelCallback = (field: HaFormSchema): string =>
this.flowConfig.renderShowFormStepFieldLabel(this.hass, this.step, field);

private _errorCallback = (error: string) =>
Expand Down