Add leading icon slot to expansion panel and fix left-chevron property (#24635)

* Add leading icon slot to expansion panel and fix left chevron

* Update components
This commit is contained in:
Paul Bottein 2025-03-17 20:23:20 +01:00 committed by GitHub
parent 4f7d5053ec
commit 3c11323ea4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 105 additions and 86 deletions

View File

@ -1,4 +1,4 @@
import { mdiPacMan } from "@mdi/js";
import { mdiLightbulbOn, mdiPacMan } from "@mdi/js";
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement } from "lit/decorators";
@ -125,6 +125,23 @@ const SAMPLES: {
`;
},
},
{
template(slot, leftChevron) {
return html`
<ha-expansion-panel
slot=${slot}
.leftChevron=${leftChevron}
header="Attr Header with actions"
>
<ha-svg-icon
slot="leading-icon"
.path=${mdiLightbulbOn}
></ha-svg-icon>
${SHORT_TEXT}
</ha-expansion-panel>
`;
},
},
];
@customElement("demo-components-ha-expansion-panel")

View File

@ -1,6 +1,6 @@
import { mdiChevronDown } from "@mdi/js";
import type { PropertyValues, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { fireEvent } from "../common/dom/fire_event";
@ -13,11 +13,11 @@ export class HaExpansionPanel extends LitElement {
@property({ type: Boolean, reflect: true }) outlined = false;
@property({ attribute: false, type: Boolean, reflect: true }) leftChevron =
false;
@property({ attribute: "left-chevron", type: Boolean, reflect: true })
public leftChevron = false;
@property({ attribute: false, type: Boolean, reflect: true }) noCollapse =
false;
@property({ attribute: "no-collapse", type: Boolean, reflect: true })
public noCollapse = false;
@property() header?: string;
@ -28,6 +28,14 @@ export class HaExpansionPanel extends LitElement {
@query(".container") private _container!: HTMLDivElement;
protected render(): TemplateResult {
const chevronIcon = this.noCollapse
? nothing
: html`
<ha-svg-icon
.path=${mdiChevronDown}
class="summary-icon ${classMap({ expanded: this.expanded })}"
></ha-svg-icon>
`;
return html`
<div class="top ${classMap({ expanded: this.expanded })}">
<div
@ -42,28 +50,15 @@ export class HaExpansionPanel extends LitElement {
aria-expanded=${this.expanded}
aria-controls="sect1"
>
${this.leftChevron && !this.noCollapse
? html`
<ha-svg-icon
.path=${mdiChevronDown}
class="summary-icon ${classMap({ expanded: this.expanded })}"
></ha-svg-icon>
`
: ""}
${this.leftChevron ? chevronIcon : nothing}
<slot name="leading-icon"></slot>
<slot name="header">
<div class="header">
${this.header}
<slot class="secondary" name="secondary">${this.secondary}</slot>
</div>
</slot>
${!this.leftChevron && !this.noCollapse
? html`
<ha-svg-icon
.path=${mdiChevronDown}
class="summary-icon ${classMap({ expanded: this.expanded })}"
></ha-svg-icon>
`
: ""}
${!this.leftChevron ? chevronIcon : nothing}
<slot name="icons"></slot>
</div>
</div>
@ -177,7 +172,8 @@ export class HaExpansionPanel extends LitElement {
margin-inline-end: initial;
}
:host([leftchevron]) .summary-icon {
:host([left-chevron]) .summary-icon,
::slotted([slot="leading-icon"]) {
margin-left: 0;
margin-right: 8px;
margin-inline-start: 0;

View File

@ -45,7 +45,7 @@ export class HaFilterBlueprints extends LitElement {
protected render() {
return html`
<ha-expansion-panel
leftChevron
left-chevron
.expanded=${this.expanded}
@expanded-will-change=${this._expandedWillChange}
@expanded-changed=${this._expandedChanged}

View File

@ -65,7 +65,7 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) {
protected render() {
return html`
<ha-expansion-panel
leftChevron
left-chevron
.expanded=${this.expanded}
@expanded-will-change=${this._expandedWillChange}
@expanded-changed=${this._expandedChanged}

View File

@ -46,7 +46,7 @@ export class HaFilterDevices extends LitElement {
protected render() {
return html`
<ha-expansion-panel
leftChevron
left-chevron
.expanded=${this.expanded}
@expanded-will-change=${this._expandedWillChange}
@expanded-changed=${this._expandedChanged}

View File

@ -33,7 +33,7 @@ export class HaFilterDomains extends LitElement {
protected render() {
return html`
<ha-expansion-panel
leftChevron
left-chevron
.expanded=${this.expanded}
@expanded-will-change=${this._expandedWillChange}
@expanded-changed=${this._expandedChanged}

View File

@ -48,7 +48,7 @@ export class HaFilterEntities extends LitElement {
protected render() {
return html`
<ha-expansion-panel
leftChevron
left-chevron
.expanded=${this.expanded}
@expanded-will-change=${this._expandedWillChange}
@expanded-changed=${this._expandedChanged}

View File

@ -54,7 +54,7 @@ export class HaFilterFloorAreas extends LitElement {
return html`
<ha-expansion-panel
leftChevron
left-chevron
.expanded=${this.expanded}
@expanded-will-change=${this._expandedWillChange}
@expanded-changed=${this._expandedChanged}

View File

@ -35,7 +35,7 @@ export class HaFilterIntegrations extends LitElement {
protected render() {
return html`
<ha-expansion-panel
leftChevron
left-chevron
.expanded=${this.expanded}
@expanded-will-change=${this._expandedWillChange}
@expanded-changed=${this._expandedChanged}

View File

@ -71,7 +71,7 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) {
protected render() {
return html`
<ha-expansion-panel
leftChevron
left-chevron
.expanded=${this.expanded}
@expanded-will-change=${this._expandedWillChange}
@expanded-changed=${this._expandedChanged}

View File

@ -41,7 +41,7 @@ export class HaFilterStates extends LitElement {
const hasIcon = this.states.find((item) => item.icon);
return html`
<ha-expansion-panel
leftChevron
left-chevron
.expanded=${this.expanded}
@expanded-will-change=${this._expandedWillChange}
@expanded-changed=${this._expandedChanged}

View File

@ -67,18 +67,23 @@ export class HaFormExpendable extends LitElement implements HaFormElement {
protected render() {
return html`
<ha-expansion-panel outlined .expanded=${Boolean(this.schema.expanded)}>
${this.schema.icon
? html`
<ha-icon slot="leading-icon" .icon=${this.schema.icon}></ha-icon>
`
: this.schema.iconPath
? html`
<ha-svg-icon
slot="leading-icon"
.path=${this.schema.iconPath}
></ha-svg-icon>
`
: nothing}
<div
slot="header"
role="heading"
aria-level=${this.schema.headingLevel?.toString() ?? "3"}
>
${this.schema.icon
? html` <ha-icon .icon=${this.schema.icon}></ha-icon> `
: this.schema.iconPath
? html`
<ha-svg-icon .path=${this.schema.iconPath}></ha-svg-icon>
`
: nothing}
${this.schema.title || this.computeLabel?.(this.schema)}
</div>
<div class="content">

View File

@ -523,7 +523,7 @@ export class HaServiceControl extends LitElement {
return fields.length &&
this._hasFilteredFields(fields, targetEntities)
? html`<ha-expansion-panel
leftChevron
left-chevron
.expanded=${!dataField.collapsed}
.header=${this.hass.localize(
`component.${domain}.services.${serviceName}.sections.${dataField.key}.name`

View File

@ -203,20 +203,24 @@ export default class HaAutomationActionRow extends LitElement {
</div>
`
: nothing}
<ha-expansion-panel leftChevron>
<h3 slot="header">
${type === "service" &&
"action" in this.action &&
this.action.action
? html`<ha-service-icon
<ha-expansion-panel left-chevron>
${type === "service" && "action" in this.action && this.action.action
? html`
<ha-service-icon
slot="leading-icon"
class="action-icon"
.hass=${this.hass}
.service=${this.action.action}
></ha-service-icon>`
: html`<ha-svg-icon
></ha-service-icon>
`
: html`
<ha-svg-icon
slot="leading-icon"
class="action-icon"
.path=${ACTION_ICONS[type!]}
></ha-svg-icon>`}
></ha-svg-icon>
`}
<h3 slot="header">
${capitalizeFirstLetter(
describeAction(
this.hass,
@ -640,9 +644,6 @@ export default class HaAutomationActionRow extends LitElement {
display: inline-block;
color: var(--secondary-text-color);
opacity: 0.9;
margin-right: 8px;
margin-inline-end: 8px;
margin-inline-start: initial;
}
}
.card-content {

View File

@ -128,12 +128,13 @@ export default class HaAutomationConditionRow extends LitElement {
`
: ""}
<ha-expansion-panel leftChevron>
<h3 slot="header">
<ha-expansion-panel left-chevron>
<ha-svg-icon
slot="leading-icon"
class="condition-icon"
.path=${CONDITION_ICONS[this.condition.condition]}
></ha-svg-icon>
<h3 slot="header">
${capitalizeFirstLetter(
describeCondition(this.condition, this.hass, this._entityReg)
)}
@ -526,9 +527,6 @@ export default class HaAutomationConditionRow extends LitElement {
display: inline-block;
color: var(--secondary-text-color);
opacity: 0.9;
margin-right: 8px;
margin-inline-end: 8px;
margin-inline-start: initial;
}
}
.card-content {

View File

@ -92,7 +92,7 @@ export default class HaAutomationOptionRow extends LitElement {
return html`
<ha-card outlined>
<ha-expansion-panel
leftChevron
left-chevron
@expanded-changed=${this._expandedChanged}
id="option"
>

View File

@ -159,12 +159,13 @@ export default class HaAutomationTriggerRow extends LitElement {
`
: nothing}
<ha-expansion-panel leftChevron>
<h3 slot="header">
<ha-expansion-panel left-chevron>
<ha-svg-icon
slot="leading-icon"
class="trigger-icon"
.path=${TRIGGER_ICONS[type]}
></ha-svg-icon>
<h3 slot="header">
${describeTrigger(this.trigger, this.hass, this._entityReg)}
</h3>
@ -672,9 +673,6 @@ export default class HaAutomationTriggerRow extends LitElement {
display: inline-block;
color: var(--secondary-text-color);
opacity: 0.9;
margin-right: 8px;
margin-inline-end: 8px;
margin-inline-start: initial;
}
}
.card-content {

View File

@ -130,13 +130,16 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
.expanded=${expanded}
.noCollapse=${anyRequired}
>
<div slot="header" role="heading" aria-level="3" class="section-header">
${section?.icon
? html`<ha-icon
? html`
<ha-icon
slot="leading-icon"
class="section-header"
.icon=${section.icon}
></ha-icon>`
></ha-icon>
`
: nothing}
<div slot="header" role="heading" aria-level="3" class="section-header">
<ha-markdown .content=${title}></ha-markdown>
</div>
<div class="content">

View File

@ -82,7 +82,7 @@ export default class HaScriptFieldRow extends LitElement {
return html`
<ha-card outlined>
<ha-expansion-panel leftChevron>
<ha-expansion-panel left-chevron>
<h3 slot="header">${this.key}</h3>
<slot name="icons" slot="icons"></slot>

View File

@ -97,12 +97,13 @@ export class HaCardConditionEditor extends LitElement {
return html`
<div class="container">
<ha-expansion-panel leftChevron>
<h3 slot="header">
<ha-expansion-panel left-chevron>
<ha-svg-icon
slot="leading-icon"
class="condition-icon"
.path=${ICON_CONDITION[condition.condition]}
></ha-svg-icon>
<h3 slot="header">
${this.hass.localize(
`ui.panel.lovelace.editor.condition-editor.condition.${condition.condition}.label`
) || condition.condition}

View File

@ -43,7 +43,7 @@ export const configElementStyle = css`
ha-expansion-panel .content {
padding: 12px;
}
ha-expansion-panel > * {
ha-expansion-panel > *[slot="header"] {
margin: 0;
font-size: inherit;
font-weight: inherit;

View File

@ -137,8 +137,8 @@ export class HuiHeadingCardEditor
@value-changed=${this._valueChanged}
></ha-form>
<ha-expansion-panel outlined>
<ha-svg-icon slot="leading-icon" .path=${mdiListBox}></ha-svg-icon>
<h3 slot="header">
<ha-svg-icon .path=${mdiListBox}></ha-svg-icon>
${this.hass!.localize(
"ui.panel.lovelace.editor.card.heading.entities"
)}

View File

@ -102,8 +102,8 @@ export class HuiHumidifierCardEditor
@value-changed=${this._valueChanged}
></ha-form>
<ha-expansion-panel outlined>
<ha-svg-icon slot="leading-icon" .path=${mdiListBox}></ha-svg-icon>
<h3 slot="header">
<ha-svg-icon .path=${mdiListBox}></ha-svg-icon>
${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.features"
)}

View File

@ -101,8 +101,8 @@ export class HuiThermostatCardEditor
@value-changed=${this._valueChanged}
></ha-form>
<ha-expansion-panel outlined>
<ha-svg-icon slot="leading-icon" .path=${mdiListBox}></ha-svg-icon>
<h3 slot="header">
<ha-svg-icon .path=${mdiListBox}></ha-svg-icon>
${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.features"
)}

View File

@ -310,8 +310,8 @@ export class HuiTileCardEditor
@value-changed=${this._valueChanged}
></ha-form>
<ha-expansion-panel outlined>
<ha-svg-icon slot="leading-icon" .path=${mdiListBox}></ha-svg-icon>
<h3 slot="header">
<ha-svg-icon .path=${mdiListBox}></ha-svg-icon>
${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.features"
)}

View File

@ -191,8 +191,8 @@ export class HuiHeadingEntityEditor
@value-changed=${this._valueChanged}
></ha-form>
<ha-expansion-panel outlined>
<ha-svg-icon slot="leading-icon" .path=${mdiEye}></ha-svg-icon>
<h3 slot="header">
<ha-svg-icon .path=${mdiEye}></ha-svg-icon>
${this.hass!.localize(
"ui.panel.lovelace.editor.card.heading.entity_config.visibility"
)}