Show a tooltip when hovering sidebar items in compact mode (#3393)

* Show a tooltip when hovering sidebar items in compact mode

* Use div for tooltip
This commit is contained in:
Paulus Schoutsen 2019-07-20 10:31:13 -07:00 committed by GitHub
parent da741238d2
commit 75c7445dd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -5,6 +5,7 @@ import {
css,
PropertyValues,
property,
eventOptions,
} from "lit-element";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@polymer/paper-icon-button/paper-icon-button";
@ -28,6 +29,8 @@ import {
} from "../data/persistent_notification";
import computeDomain from "../common/entity/compute_domain";
import { classMap } from "lit-html/directives/class-map";
// tslint:disable-next-line: no-duplicate-imports
import { PaperIconItemElement } from "@polymer/paper-item/paper-icon-item";
const SHOW_AFTER_SPACER = ["config", "developer-tools"];
@ -103,6 +106,10 @@ class HaSidebar extends LitElement {
@property() private _externalConfig?: ExternalConfig;
@property() private _notifications?: PersistentNotification[];
private _mouseLeaveTimeout?: number;
private _tooltipHideTimeout?: number;
private _recentKeydownActiveUntil = 0;
protected render() {
const hass = this.hass;
@ -134,7 +141,14 @@ class HaSidebar extends LitElement {
: ""}
<span class="title">Home Assistant</span>
</div>
<paper-listbox attr-for-selected="data-panel" .selected=${hass.panelUrl}>
<paper-listbox
attr-for-selected="data-panel"
.selected=${hass.panelUrl}
@focusin=${this._listboxFocusIn}
@focusout=${this._listboxFocusOut}
@scroll=${this._listboxScroll}
@keydown=${this._listboxKeydown}
>
${this._renderPanel(
this._defaultPage,
"hass:apps",
@ -165,7 +179,10 @@ class HaSidebar extends LitElement {
tabindex="-1"
@click=${this._handleExternalAppConfiguration}
>
<paper-icon-item>
<paper-icon-item
@mouseenter=${this._itemMouseEnter}
@mouseleave=${this._itemMouseLeave}
>
<ha-icon
slot="item-icon"
icon="hass:cellphone-settings-variant"
@ -185,6 +202,8 @@ class HaSidebar extends LitElement {
class="notifications"
aria-role="option"
@click=${this._handleShowNotificationDrawer}
@mouseenter=${this._itemMouseEnter}
@mouseleave=${this._itemMouseLeave}
>
<ha-icon slot="item-icon" icon="hass:bell"></ha-icon>
${!this.expanded && notificationCount > 0
@ -216,7 +235,10 @@ class HaSidebar extends LitElement {
aria-role="option"
aria-label=${hass.localize("panel.profile")}
>
<paper-icon-item>
<paper-icon-item
@mouseenter=${this._itemMouseEnter}
@mouseleave=${this._itemMouseLeave}
>
<ha-user-badge slot="item-icon" .user=${hass.user}></ha-user-badge>
<span class="item-text">
@ -225,6 +247,7 @@ class HaSidebar extends LitElement {
</paper-icon-item>
</a>
<div disabled class="bottom-spacer"></div>
<div class="tooltip"></div>
`;
}
@ -286,6 +309,91 @@ class HaSidebar extends LitElement {
}
}
private get _tooltip() {
return this.shadowRoot!.querySelector(".tooltip")! as HTMLDivElement;
}
private _itemMouseEnter(ev: MouseEvent) {
// On keypresses on the listbox, we're going to ignore mouse enter events
// for 100ms so that we ignore it when pressing down arrow scrolls the
// sidebar causing the mouse to hover a new icon
if (
this.expanded ||
new Date().getTime() < this._recentKeydownActiveUntil
) {
return;
}
if (this._mouseLeaveTimeout) {
clearTimeout(this._mouseLeaveTimeout);
this._mouseLeaveTimeout = undefined;
}
this._showTooltip(ev.currentTarget as PaperIconItemElement);
}
private _itemMouseLeave() {
if (this._mouseLeaveTimeout) {
clearTimeout(this._mouseLeaveTimeout);
}
this._mouseLeaveTimeout = window.setTimeout(() => {
this._hideTooltip();
}, 500);
}
private _listboxFocusIn(ev) {
if (this.expanded || ev.target.nodeName !== "A") {
return;
}
this._showTooltip(ev.target.querySelector("paper-icon-item"));
}
private _listboxFocusOut() {
this._hideTooltip();
}
@eventOptions({
passive: true,
})
private _listboxScroll() {
// On keypresses on the listbox, we're going to ignore scroll events
// for 100ms so that if pressing down arrow scrolls the sidebar, the tooltip
// will not be hidden.
if (new Date().getTime() < this._recentKeydownActiveUntil) {
return;
}
this._hideTooltip();
}
private _listboxKeydown() {
this._recentKeydownActiveUntil = new Date().getTime() + 100;
}
private _showTooltip(item: PaperIconItemElement) {
if (this._tooltipHideTimeout) {
clearTimeout(this._tooltipHideTimeout);
this._tooltipHideTimeout = undefined;
}
const tooltip = this._tooltip;
const listbox = this.shadowRoot!.querySelector("paper-listbox")!;
let top = item.offsetTop + 7;
if (listbox.contains(item)) {
top -= listbox.scrollTop;
}
tooltip.innerHTML = item.querySelector(".item-text")!.innerHTML;
tooltip.style.display = "block";
tooltip.style.top = `${top}px`;
tooltip.style.left = `${item.offsetLeft + item.clientWidth + 12}px`;
}
private _hideTooltip() {
// Delay it a little in case other events are pending processing.
if (!this._tooltipHideTimeout) {
this._tooltipHideTimeout = window.setTimeout(() => {
this._tooltipHideTimeout = undefined;
this._tooltip.style.display = "none";
}, 10);
}
}
private _handleShowNotificationDrawer() {
fireEvent(this, "hass-show-notifications");
}
@ -309,7 +417,10 @@ class HaSidebar extends LitElement {
data-panel="${urlPath}"
tabindex="-1"
>
<paper-icon-item>
<paper-icon-item
@mouseenter=${this._itemMouseEnter}
@mouseleave=${this._itemMouseLeave}
>
<ha-icon slot="item-icon" .icon="${icon}"></ha-icon>
<span class="item-text">${title}</span>
</paper-icon-item>
@ -327,10 +438,7 @@ class HaSidebar extends LitElement {
-webkit-user-select: none;
-moz-user-select: none;
border-right: 1px solid var(--divider-color);
background-color: var(
--sidebar-background-color,
var(--primary-background-color)
);
background-color: var(--sidebar-background-color);
width: 64px;
}
:host([expanded]) {
@ -524,6 +632,18 @@ class HaSidebar extends LitElement {
.dev-tools a {
color: var(--sidebar-icon-color);
}
.tooltip {
display: none;
position: absolute;
opacity: 0.9;
border-radius: 2px;
white-space: nowrap;
color: var(--sidebar-background-color);
background-color: var(--sidebar-text-color);
padding: 4px;
font-weight: 500;
}
`;
}
}