Files
openfoodnetwork/app/webpacker/controllers/tooltip_controller.js

79 lines
2.2 KiB
JavaScript

import { Controller } from "stimulus";
import { computePosition, offset, arrow } from "@floating-ui/dom";
export default class extends Controller {
static targets = ["element", "tooltip", "arrow"];
static values = {
tip: String,
placement: { type: String, default: "top" },
};
connect() {
if (this.hasTipValue) { this.insertToolTipMarkup() }
this.elementTarget.addEventListener("mouseenter", this.showTooltip);
this.elementTarget.addEventListener("mouseleave", this.hideTooltip);
}
disconnect() {
this.elementTarget.removeEventListener("mouseenter", this.showTooltip);
this.elementTarget.removeEventListener("mouseleave", this.hideTooltip);
}
update() {
computePosition(this.elementTarget, this.tooltipTarget, {
placement: this.placementValue,
middleware: [offset(6), arrow({ element: this.arrowTarget })],
}).then(({ x, y, placement, middlewareData }) => {
Object.assign(this.tooltipTarget.style, {
left: `${x}px`,
top: `${y}px`,
});
const { x: arrowX, y: arrowY } = middlewareData.arrow;
const staticSide = {
top: "bottom",
right: "left",
bottom: "top",
left: "right",
}[placement.split("-")[0]];
Object.assign(this.arrowTarget.style, {
left: arrowX != null ? `${arrowX}px` : "",
top: arrowY != null ? `${arrowY}px` : "",
right: "",
bottom: "",
[staticSide]: "-4px",
});
});
}
showTooltip = () => {
this.tooltipTarget.style.display = "block";
this.update();
};
hideTooltip = () => {
this.tooltipTarget.style.display = "";
};
insertToolTipMarkup() {
let container = document.createElement("div");
let tooltip = document.createElement("div");
let arrow = document.createElement("div");
let text = document.createTextNode(this.tipValue);
container.classList.add("tooltip-container");
tooltip.classList.add("tooltip");
tooltip.setAttribute("data-tooltip-target", "tooltip");
arrow.classList.add("arrow");
arrow.setAttribute("data-tooltip-target", "arrow");
container.appendChild(tooltip);
tooltip.appendChild(text);
tooltip.appendChild(arrow);
this.elementTarget.appendChild(container);
}
}