From 117f5d6fdce4647864bdb05e740e3867e60e6246 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 13 Mar 2022 11:21:21 -0700 Subject: [PATCH 1/2] Restore menu to relative rendering. --- src/action-handler-directive.ts | 8 +-- src/components/submenu.ts | 89 +++++++++------------------------ src/scss/card.scss | 9 +++- src/scss/menu.scss | 8 +++ src/scss/submenu.scss | 4 -- 5 files changed, 44 insertions(+), 74 deletions(-) diff --git a/src/action-handler-directive.ts b/src/action-handler-directive.ts index d7d94027..f1d2a467 100644 --- a/src/action-handler-directive.ts +++ b/src/action-handler-directive.ts @@ -94,10 +94,12 @@ class ActionHandler extends HTMLElement implements ActionHandler { }; const end = (ev: Event): void => { - // This will ensure only 1 actionHandler is invoked for a given interaction. - stopEventFromActivatingCardWideActions(ev); - const options = element.actionHandlerOptions; + if (!options?.allowPropagation) { + // This will ensure only 1 actionHandler is invoked for a given interaction. + stopEventFromActivatingCardWideActions(ev); + } + if ( ['touchend', 'touchcancel'].includes(ev.type) && // This action handler by default relies on synthetic click events for diff --git a/src/components/submenu.ts b/src/components/submenu.ts index 030b3c2f..97a1d835 100644 --- a/src/components/submenu.ts +++ b/src/components/submenu.ts @@ -1,7 +1,7 @@ -import type { Corner, Menu } from '@material/mwc-menu'; +import type { Corner } from '@material/mwc-menu'; import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit'; import { HomeAssistant } from 'custom-card-helpers'; -import { customElement, property, query } from 'lit/decorators.js'; +import { customElement, property } from 'lit/decorators.js'; import { frigateCardHasAction, refreshDynamicStateParameters, @@ -26,8 +26,6 @@ export class FrigateCardSubmenu extends LitElement { @property({ attribute: false }) public corner?: Corner; - @query('mwc-menu') private _menu?: Menu; - protected _renderItem(item: MenuSubmenuItem): TemplateResult | void { if (!this.hass) { return; @@ -65,81 +63,40 @@ export class FrigateCardSubmenu extends LitElement { `; } - /** - * Get the fixed root element in which fixed elements are positioned against. - * @returns The fixed root element or null if not found. - */ - protected _getFixedRoot(): HTMLElement | null { - let n = this as Node | null; - while (n) { - if ( - n.nodeType === Node.ELEMENT_NODE && - (n as Element).tagName === 'HA-APP-LAYOUT' - ) { - return n as HTMLElement; - } - n = n.parentNode - ? n.parentNode - : n.nodeType === Node.DOCUMENT_FRAGMENT_NODE - ? (n as ShadowRoot).host - : null; - } - return null; - } - protected render(): TemplateResult { if (!this.submenu) { return html``; } return html` - { - if (this._menu) { - // Hack: This insanity is brought about by lack of MWCMenu playing - // nicely with the Home Assistant view/sidepanel. The menu must be - // rendered in fixed mode in order to allow the menu to render - // outside of the card boundaries (card has overflow as hidden). - // When in fixed mode, the menu anchoring refuses to get the - // placement correct -- it's always off by exactly the dimensions of - // the sidebar/header. To work around this we iterate up the DOM to - // find the main root (excl. the sidebar) and subtract those - // dimensions off wherever the menu believes it should render. - this._menu.anchor = this; - const root = this._getFixedRoot(); - if (root) { - const rootPosition = root.getBoundingClientRect(); - this._menu.x = -rootPosition.x; - this._menu.y = -rootPosition.y; - } else { - this._menu.x = 0; - this._menu.y = 0; - } - this._menu.show(); - } - stopEventFromActivatingCardWideActions(ev); - }} - > - - - ev.stopPropagation() } + @click=${(ev) => stopEventFromActivatingCardWideActions(ev)} > + trigger slot to open/close the menu. Further + // propagation is forbidden by the @click handler on + // . + allowPropagation: true, + hasHold: frigateCardHasAction(this.submenu.hold_action), + hasDoubleClick: frigateCardHasAction(this.submenu.double_tap_action), + })} + > + + ${this.submenu.items.map(this._renderItem.bind(this))} - + `; } diff --git a/src/scss/card.scss b/src/scss/card.scss index 1325188f..34f29ce7 100644 --- a/src/scss/card.scss +++ b/src/scss/card.scss @@ -13,6 +13,11 @@ margin: auto; display: flex; justify-content: center; + + // Need to apply the border radius on the container level, as the ha-card has + // overflow visible in order to allow a submenu to extend beyond the card + // boundary. + border-radius: var(--ha-card-border-radius, 4px); } .frigate-card-contents { @@ -58,7 +63,9 @@ ha-card { display: flex; flex-direction: column; margin: auto; - overflow: hidden; + + // Some elements (such as submenus) may need to extend beyond the card boundary. + overflow: visible; width: 100%; height: 100%; position: static; diff --git a/src/scss/menu.scss b/src/scss/menu.scss index 65a65e74..45063aa3 100644 --- a/src/scss/menu.scss +++ b/src/scss/menu.scss @@ -18,6 +18,14 @@ width: 100%; background: var(--secondary-background-color); } +:host([data-mode="above"]) { + border-top-left-radius: var(--ha-card-border-radius, 4px); + border-top-right-radius: var(--ha-card-border-radius, 4px); +} +:host([data-mode="below"]) { + border-bottom-left-radius: var(--ha-card-border-radius, 4px); + border-bottom-right-radius: var(--ha-card-border-radius, 4px); +} :host([data-mode$="-left"]) { left: 0px; diff --git a/src/scss/submenu.scss b/src/scss/submenu.scss index f4539d6b..fe2042a5 100644 --- a/src/scss/submenu.scss +++ b/src/scss/submenu.scss @@ -7,7 +7,3 @@ mwc-list-item { z-index: 20; } - -mwc-list-item[disabled] { - color: var(--disabled-text-color); -} \ No newline at end of file From 25cc03276ff9ce79399adfecf826bc4a5ceab609 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 13 Mar 2022 11:29:27 -0700 Subject: [PATCH 2/2] Add allowPropagation option. --- src/action-handler-directive.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/action-handler-directive.ts b/src/action-handler-directive.ts index f1d2a467..a79a8fc9 100644 --- a/src/action-handler-directive.ts +++ b/src/action-handler-directive.ts @@ -18,7 +18,7 @@ interface ActionHandler extends HTMLElement { bind(element: Element, options): void; } interface ActionHandlerElement extends HTMLElement { - actionHandlerOptions?: ActionHandlerOptions; + actionHandlerOptions?: FrigateCardActionHandlerOptions; } declare global { @@ -27,6 +27,10 @@ declare global { } } +interface FrigateCardActionHandlerOptions extends ActionHandlerOptions { + allowPropagation?: boolean; +} + class ActionHandler extends HTMLElement implements ActionHandler { public holdTime = 400; @@ -171,7 +175,7 @@ const getActionHandler = (): ActionHandler => { export const actionHandlerBind = ( element: ActionHandlerElement, - options?: ActionHandlerOptions, + options?: FrigateCardActionHandlerOptions, ): void => { const actionhandler: ActionHandler = getActionHandler(); if (!actionhandler) { @@ -188,6 +192,6 @@ export const actionHandler = directive( } // eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars - render(_options?: ActionHandlerOptions) {} + render(_options?: FrigateCardActionHandlerOptions) {} }, );