@synergy-design-system/components
Version:
This package provides the base of the Synergy Design System as native web components. It uses [lit](https://www.lit.dev) and parts of [shoelace](https://shoelace.style/). Synergy officially supports the latest two versions of all major browsers (as define
279 lines (275 loc) • 8.01 kB
JavaScript
import {
tooltip_custom_styles_default
} from "./chunk.E7LBPRDC.js";
import {
tooltip_styles_default
} from "./chunk.O644HRW3.js";
import {
SynPopup
} from "./chunk.MGWPQRJ7.js";
import {
waitForEvent
} from "./chunk.C2ENQBPM.js";
import {
animateTo,
parseDuration,
stopAnimations
} from "./chunk.G6ITZTTW.js";
import {
getAnimation,
setDefaultAnimation
} from "./chunk.7JGKUB4A.js";
import {
LocalizeController
} from "./chunk.OAQRCZOO.js";
import {
watch
} from "./chunk.BVZQ6QSY.js";
import {
component_styles_default
} from "./chunk.NLYVOJGK.js";
import {
SynergyElement
} from "./chunk.3THJTCRO.js";
import {
__decorateClass
} from "./chunk.Z4XV3SMG.js";
// src/components/tooltip/tooltip.component.ts
import { classMap } from "lit/directives/class-map.js";
import { html } from "lit";
import { property, query } from "lit/decorators.js";
var SynTooltip = class extends SynergyElement {
constructor() {
super();
this.localize = new LocalizeController(this);
this.content = "";
this.placement = "top";
this.disabled = false;
this.distance = 13;
this.open = false;
this.skidding = 0;
this.trigger = "hover focus";
this.hoist = false;
this.handleBlur = () => {
if (this.hasTrigger("focus")) {
this.hide();
}
};
this.handleClick = () => {
if (this.hasTrigger("click")) {
if (this.open) {
this.hide();
} else {
this.show();
}
}
};
this.handleFocus = () => {
if (this.hasTrigger("focus")) {
this.show();
}
};
this.handleDocumentKeyDown = (event) => {
if (event.key === "Escape") {
event.stopPropagation();
this.hide();
}
};
this.handleMouseOver = () => {
if (this.hasTrigger("hover")) {
const delay = parseDuration(getComputedStyle(this).getPropertyValue("--show-delay"));
clearTimeout(this.hoverTimeout);
this.hoverTimeout = window.setTimeout(() => this.show(), delay);
}
};
this.handleMouseOut = () => {
if (this.hasTrigger("hover")) {
const delay = parseDuration(getComputedStyle(this).getPropertyValue("--hide-delay"));
clearTimeout(this.hoverTimeout);
this.hoverTimeout = window.setTimeout(() => this.hide(), delay);
}
};
this.addEventListener("blur", this.handleBlur, true);
this.addEventListener("focus", this.handleFocus, true);
this.addEventListener("click", this.handleClick);
this.addEventListener("mouseover", this.handleMouseOver);
this.addEventListener("mouseout", this.handleMouseOut);
}
disconnectedCallback() {
var _a;
super.disconnectedCallback();
(_a = this.closeWatcher) == null ? void 0 : _a.destroy();
document.removeEventListener("keydown", this.handleDocumentKeyDown);
}
firstUpdated() {
this.body.hidden = !this.open;
if (this.open) {
this.popup.active = true;
this.popup.reposition();
}
}
hasTrigger(triggerType) {
const triggers = this.trigger.split(" ");
return triggers.includes(triggerType);
}
async handleOpenChange() {
var _a, _b;
if (this.open) {
if (this.disabled) {
return;
}
this.emit("syn-show");
if ("CloseWatcher" in window) {
(_a = this.closeWatcher) == null ? void 0 : _a.destroy();
this.closeWatcher = new CloseWatcher();
this.closeWatcher.onclose = () => {
this.hide();
};
} else {
document.addEventListener("keydown", this.handleDocumentKeyDown);
}
await stopAnimations(this.body);
this.body.hidden = false;
this.popup.active = true;
const { keyframes, options } = getAnimation(this, "tooltip.show", { dir: this.localize.dir() });
await animateTo(this.popup.popup, keyframes, options);
this.popup.reposition();
this.emit("syn-after-show");
} else {
this.emit("syn-hide");
(_b = this.closeWatcher) == null ? void 0 : _b.destroy();
document.removeEventListener("keydown", this.handleDocumentKeyDown);
await stopAnimations(this.body);
const { keyframes, options } = getAnimation(this, "tooltip.hide", { dir: this.localize.dir() });
await animateTo(this.popup.popup, keyframes, options);
this.popup.active = false;
this.body.hidden = true;
this.emit("syn-after-hide");
}
}
async handleOptionsChange() {
if (this.hasUpdated) {
await this.updateComplete;
this.popup.reposition();
}
}
handleDisabledChange() {
if (this.disabled && this.open) {
this.hide();
}
}
/** Shows the tooltip. */
async show() {
if (this.open) {
return void 0;
}
this.open = true;
return waitForEvent(this, "syn-after-show");
}
/** Hides the tooltip */
async hide() {
if (!this.open) {
return void 0;
}
this.open = false;
return waitForEvent(this, "syn-after-hide");
}
//
// NOTE: Tooltip is a bit unique in that we're using aria-live instead of aria-labelledby to trick screen readers into
// announcing the content. It works really well, but it violates an accessibility rule. We're also adding the
// aria-describedby attribute to a slot, which is required by <syn-popup> to correctly locate the first assigned
// element, otherwise positioning is incorrect.
//
render() {
return html`
<syn-popup
part="base"
exportparts="
popup:base__popup,
arrow:base__arrow
"
class=${classMap({
tooltip: true,
"tooltip--open": this.open
})}
placement=${this.placement}
distance=${this.distance}
skidding=${this.skidding}
strategy=${this.hoist ? "fixed" : "absolute"}
flip
shift
arrow
hover-bridge
>
${""}
<slot slot="anchor" aria-describedby="tooltip"></slot>
${""}
<div part="body" id="tooltip" class="tooltip__body" role="tooltip" aria-live=${this.open ? "polite" : "off"}>
<slot name="content">${this.content}</slot>
</div>
</syn-popup>
`;
}
};
SynTooltip.styles = [component_styles_default, tooltip_styles_default, tooltip_custom_styles_default];
SynTooltip.dependencies = { "syn-popup": SynPopup };
__decorateClass([
query("slot:not([name])")
], SynTooltip.prototype, "defaultSlot", 2);
__decorateClass([
query(".tooltip__body")
], SynTooltip.prototype, "body", 2);
__decorateClass([
query("syn-popup")
], SynTooltip.prototype, "popup", 2);
__decorateClass([
property()
], SynTooltip.prototype, "content", 2);
__decorateClass([
property()
], SynTooltip.prototype, "placement", 2);
__decorateClass([
property({ type: Boolean, reflect: true })
], SynTooltip.prototype, "disabled", 2);
__decorateClass([
property({ type: Number })
], SynTooltip.prototype, "distance", 2);
__decorateClass([
property({ type: Boolean, reflect: true })
], SynTooltip.prototype, "open", 2);
__decorateClass([
property({ type: Number })
], SynTooltip.prototype, "skidding", 2);
__decorateClass([
property()
], SynTooltip.prototype, "trigger", 2);
__decorateClass([
property({ type: Boolean })
], SynTooltip.prototype, "hoist", 2);
__decorateClass([
watch("open", { waitUntilFirstUpdate: true })
], SynTooltip.prototype, "handleOpenChange", 1);
__decorateClass([
watch(["content", "distance", "hoist", "placement", "skidding"])
], SynTooltip.prototype, "handleOptionsChange", 1);
__decorateClass([
watch("disabled")
], SynTooltip.prototype, "handleDisabledChange", 1);
setDefaultAnimation("tooltip.show", {
keyframes: [
{ opacity: 0, scale: 0.8 },
{ opacity: 1, scale: 1 }
],
options: { duration: 150, easing: "ease" }
});
setDefaultAnimation("tooltip.hide", {
keyframes: [
{ opacity: 1, scale: 1 },
{ opacity: 0, scale: 0.8 }
],
options: { duration: 150, easing: "ease" }
});
export {
SynTooltip
};
//# sourceMappingURL=chunk.7T7CWOUP.js.map