diff --git a/src/components/drawer.ts b/src/components/drawer.ts index f011dbf5..dfff296a 100644 --- a/src/components/drawer.ts +++ b/src/components/drawer.ts @@ -13,6 +13,7 @@ import { SideDrawer } from 'side-drawer'; import drawerInjectStyle from '../scss/drawer-inject.scss'; import drawerStyle from '../scss/drawer.scss'; import { stopEventFromActivatingCardWideActions } from '../utils/action'; +import { isHoverableDevice } from '../utils/basic'; @customElement('frigate-card-drawer') export class FrigateCardDrawer extends LitElement { @@ -37,6 +38,8 @@ export class FrigateCardDrawer extends LitElement { protected _resizeObserver = new ResizeObserver(() => this._hideDrawerIfNecessary()); + protected readonly _isHoverableDevice = isHoverableDevice(); + /** * Called on the first update. * @param changedProps The changed properties. @@ -110,7 +113,11 @@ export class FrigateCardDrawer extends LitElement { class="control" icon="${this.open ? 'mdi:menu-open' : 'mdi:menu'}" @mouseenter=${() => { - if (!this.open) { + // Only open the drawer on mousenter when the device + // supports hover (otherwise iOS may end up passing on + // subsequent click events to a different element, see: + // https://github.com/dermotduffy/frigate-hass-card/issues/801 + if (this._isHoverableDevice && !this.open) { this.open = true; } }} @@ -130,8 +137,8 @@ export class FrigateCardDrawer extends LitElement { } declare global { - interface HTMLElementTagNameMap { - "frigate-card-drawer": FrigateCardDrawer - "side-drawer": SideDrawer, - } + interface HTMLElementTagNameMap { + 'frigate-card-drawer': FrigateCardDrawer; + 'side-drawer': SideDrawer; + } } diff --git a/src/components/timeline.ts b/src/components/timeline.ts index fda166e7..ca009e4e 100644 --- a/src/components/timeline.ts +++ b/src/components/timeline.ts @@ -47,7 +47,7 @@ import { TimelineConfig, } from '../types'; import { stopEventFromActivatingCardWideActions } from '../utils/action'; -import { dispatchFrigateCardEvent, errorToConsole, prettifyTitle } from '../utils/basic'; +import { dispatchFrigateCardEvent, errorToConsole, isHoverableDevice, prettifyTitle } from '../utils/basic'; import { getCameraTitle } from '../utils/camera.js'; import { getRecordingSegments, @@ -548,9 +548,7 @@ export class FrigateCardTimelineCore extends LitElement { protected _pointerHeld = false; protected _ignoreClick = false; - protected static _isHoverableDevice = window.matchMedia( - '(hover: hover) and (pointer: fine)', - ).matches; + protected readonly _isHoverableDevice = isHoverableDevice(); /** * Get a tooltip for a given timeline event. @@ -559,7 +557,7 @@ export class FrigateCardTimelineCore extends LitElement { */ protected _getTooltip(item: TimelineItem): string { const source = (item).source; - if (!FrigateCardTimelineCore._isHoverableDevice || !source) { + if (!this._isHoverableDevice || !source) { // Don't display tooltips on touch devices, they just get in the way of // the drawer. return ''; diff --git a/src/utils/basic.ts b/src/utils/basic.ts index a4d1c483..31504bbc 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -76,4 +76,12 @@ export function errorToConsole(e: Error, func?: CallableFunction): void { } else { func(e); } -} \ No newline at end of file +} + +/** + * Determine if the device supports hovering. + * @returns `true` if the device supports hovering, `false` otherwise. + */ +export const isHoverableDevice = (): boolean => window.matchMedia( + '(hover: hover) and (pointer: fine)', +).matches;