Skip to content

Commit

Permalink
Add support for state content customization in tile card (#18180)
Browse files Browse the repository at this point in the history
* Add support for state content customization

* Add reorder option

* Do not display null attributes

* Always return a value

* Add hide state option

* Add missing attribute unit

* Fix sortable create and destroy
  • Loading branch information
piitaya authored Oct 24, 2023
1 parent c9f5d16 commit 6ffc062
Show file tree
Hide file tree
Showing 7 changed files with 348 additions and 113 deletions.
155 changes: 122 additions & 33 deletions src/components/ha-selector/ha-selector-select.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import "@material/mwc-list/mwc-list-item";
import { mdiClose } from "@mdi/js";
import { css, html, LitElement } from "lit";
import { mdiClose, mdiDrag } from "@mdi/js";
import { LitElement, PropertyValues, css, html, nothing } from "lit";
import { customElement, property, query } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import { SortableEvent } from "sortablejs";
import { ensureArray } from "../../common/array/ensure-array";
import { fireEvent } from "../../common/dom/fire_event";
import { stopPropagation } from "../../common/dom/stop_propagation";
import { caseInsensitiveStringCompare } from "../../common/string/compare";
import type { SelectOption, SelectSelector } from "../../data/selector";
import { sortableStyles } from "../../resources/ha-sortable-style";
import { SortableInstance } from "../../resources/sortable";
import type { HomeAssistant } from "../../types";
import "../ha-checkbox";
import "../ha-chip";
Expand Down Expand Up @@ -38,6 +42,68 @@ export class HaSelectSelector extends LitElement {

@query("ha-combo-box", true) private comboBox!: HaComboBox;

private _sortable?: SortableInstance;

protected updated(changedProps: PropertyValues): void {
if (changedProps.has("value") || changedProps.has("selector")) {
const sortableNeeded =
this.selector.select?.multiple &&
this.selector.select.reorder &&
this.value?.length;
if (!this._sortable && sortableNeeded) {
this._createSortable();
} else if (this._sortable && !sortableNeeded) {
this._destroySortable();
}
}
}

private async _createSortable() {
const Sortable = (await import("../../resources/sortable")).default;
this._sortable = new Sortable(
this.shadowRoot!.querySelector("ha-chip-set")!,
{
animation: 150,
fallbackClass: "sortable-fallback",
draggable: "ha-chip",
onChoose: (evt: SortableEvent) => {
(evt.item as any).placeholder =
document.createComment("sort-placeholder");
evt.item.after((evt.item as any).placeholder);
},
onEnd: (evt: SortableEvent) => {
// put back in original location
if ((evt.item as any).placeholder) {
(evt.item as any).placeholder.replaceWith(evt.item);
delete (evt.item as any).placeholder;
}
this._dragged(evt);
},
}
);
}

private _dragged(ev: SortableEvent): void {
if (ev.oldIndex === ev.newIndex) return;
this._move(ev.oldIndex!, ev.newIndex!);
}

private _move(index: number, newIndex: number) {
const value = this.value as string[];
const newValue = value.concat();
const element = newValue.splice(index, 1)[0];
newValue.splice(newIndex, 0, element);
this.value = newValue;
fireEvent(this, "value-changed", {
value: newValue,
});
}

private _destroySortable() {
this._sortable?.destroy();
this._sortable = undefined;
}

private _filter = "";

protected render() {
Expand Down Expand Up @@ -71,7 +137,11 @@ export class HaSelectSelector extends LitElement {
);
}

if (!this.selector.select?.custom_value && this._mode === "list") {
if (
!this.selector.select?.custom_value &&
!this.selector.select?.reorder &&
this._mode === "list"
) {
if (!this.selector.select?.multiple) {
return html`
<div>
Expand Down Expand Up @@ -124,23 +194,39 @@ export class HaSelectSelector extends LitElement {

return html`
${value?.length
? html`<ha-chip-set>
${value.map(
(item, idx) => html`
<ha-chip hasTrailingIcon>
${options.find((option) => option.value === item)?.label ||
item}
<ha-svg-icon
slot="trailing-icon"
.path=${mdiClose}
.idx=${idx}
@click=${this._removeItem}
></ha-svg-icon>
</ha-chip>
`
)}
</ha-chip-set>`
: ""}
? html`
<ha-chip-set>
${repeat(
value,
(item) => item,
(item, idx) => html`
<ha-chip
hasTrailingIcon
.hasIcon=${this.selector.select?.reorder}
>
${this.selector.select?.reorder
? html`
<ha-svg-icon
slot="icon"
.path=${mdiDrag}
data-handle
></ha-svg-icon>
`
: nothing}
${options.find((option) => option.value === item)
?.label || item}
<ha-svg-icon
slot="trailing-icon"
.path=${mdiClose}
.idx=${idx}
@click=${this._removeItem}
></ha-svg-icon>
</ha-chip>
`
)}
</ha-chip-set>
`
: nothing}
<ha-combo-box
item-value-path="value"
Expand Down Expand Up @@ -331,19 +417,22 @@ export class HaSelectSelector extends LitElement {
this.comboBox.filteredItems = filteredItems;
}

static styles = css`
:host {
position: relative;
}
ha-select,
mwc-formfield,
ha-formfield {
display: block;
}
mwc-list-item[disabled] {
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
}
`;
static styles = [
sortableStyles,
css`
:host {
position: relative;
}
ha-select,
mwc-formfield,
ha-formfield {
display: block;
}
mwc-list-item[disabled] {
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
}
`,
];
}

declare global {
Expand Down
4 changes: 4 additions & 0 deletions src/data/entity_attributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const TEMPERATURE_ATTRIBUTES = new Set([
"target_temperature",
"target_temp_temp",
"target_temp_high",
"target_temp_low",
"target_temp_step",
"min_temp",
"max_temp",
Expand Down Expand Up @@ -70,4 +71,7 @@ export const DOMAIN_ATTRIBUTES_UNITS: Record<string, Record<string, string>> = {
vacuum: {
battery_level: "%",
},
sensor: {
battery_level: "%",
},
};
1 change: 1 addition & 0 deletions src/data/selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ export interface SelectSelector {
options: readonly string[] | readonly SelectOption[];
translation_key?: string;
sort?: boolean;
reorder?: boolean;
} | null;
}

Expand Down
Loading

0 comments on commit 6ffc062

Please sign in to comment.