Files
advanced-camera-card/src/components/submenu/index.ts
T
Dermot Duffy 0432eea4b8 feat: Add UI support for PTZ presets (#1920)
- Closes #1889

Whilst a simple change theoretically, the card has such a collection of
surfaces that can overlap other surfaces, it's challenging to get this
to work right! There's a real chance this will have broken something
z-index related (e.g. X overlaps Y when it should not), or (for related
reasons) broken curver corners on the card.
2025-02-27 20:22:12 -08:00

96 lines
3.1 KiB
TypeScript

import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { styleMap } from 'lit/directives/style-map.js';
import { actionHandler } from '../../action-handler-directive.js';
import submenuStyle from '../../scss/submenu.scss';
import {
hasAction,
stopEventFromActivatingCardWideActions,
} from '../../utils/action.js';
import { getEntityTitle } from '../../utils/ha';
import '../icon.js';
import { SubmenuInteraction, SubmenuItem } from './types.js';
@customElement('advanced-camera-card-submenu')
export class AdvancedCameraCardSubmenu extends LitElement {
@property({ attribute: false })
public hass?: HomeAssistant;
@property({ attribute: false })
public items?: SubmenuItem[];
protected _renderItem(item: SubmenuItem): TemplateResult | void {
if (!this.hass) {
return;
}
const title = item.title ?? getEntityTitle(this.hass, item.entity);
const style = styleMap(item.style || {});
return html`
<mwc-list-item
graphic=${ifDefined(item.icon || item.entity ? 'icon' : undefined)}
?twoline=${!!item.subtitle}
?selected=${item.selected}
?activated=${item.selected}
?disabled=${item.enabled === false}
aria-label="${title ?? ''}"
@action=${(ev: CustomEvent<SubmenuInteraction>) => {
// Attach the item so ascendants have access to it.
ev.detail.item = item;
}}
.actionHandler=${actionHandler({
allowPropagation: true,
hasHold: hasAction(item.hold_action),
hasDoubleClick: hasAction(item.double_tap_action),
})}
>
<span style="${style}">${title ?? ''}</span>
${item.subtitle
? html`<span slot="secondary" style="${style}">${item.subtitle}</span>`
: ''}
<advanced-camera-card-icon
slot="graphic"
.hass=${this.hass}
.icon=${{
icon: item.icon,
entity: item.entity,
}}
style="${style}"
></advanced-camera-card-icon>
</mwc-list-item>
`;
}
protected render(): TemplateResult {
return html`
<ha-button-menu
fixed
corner=${'BOTTOM_LEFT'}
@closed=${
// Prevent the submenu closing from closing anything upstream (e.g.
// selecting a submenu in the editor dialog should not close the
// editor, see https://github.com/dermotduffy/advanced-camera-card/issues/377).
(ev) => ev.stopPropagation()
}
@click=${(ev: Event) => stopEventFromActivatingCardWideActions(ev)}
>
<slot slot="trigger"></slot>
${this.items?.map(this._renderItem.bind(this))}
</ha-button-menu>
`;
}
static get styles(): CSSResultGroup {
return unsafeCSS(submenuStyle);
}
}
declare global {
interface HTMLElementTagNameMap {
'advanced-camera-card-submenu': AdvancedCameraCardSubmenu;
}
}