@progress/kendo-react-tooltip
Version:
React Tooltips library represents popups with information that is related to a UI element. KendoReact Tooltips package
242 lines (241 loc) • 9.48 kB
JavaScript
/**
* @license
*-------------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the package root for more information
*-------------------------------------------------------------------------------------------
*/
import * as l from "react";
import * as T from "react-dom";
import r from "prop-types";
import { dispatchEvent as m, ZIndexContext as y, classNames as d } from "@progress/kendo-react-common";
import { isTooltipElement as f, getDomRect as I, getLeftPosition as k, getTopPosition as C } from "./utils.mjs";
const x = 100, p = class p extends l.PureComponent {
constructor() {
super(...arguments), this.context = 0, this.state = {
targetElement: null,
open: !1,
title: ""
}, this.top = 0, this.left = 0, this.willOpen = !1, this.handleMouseOut = (t) => {
const { targetElement: o } = this.state, s = o ? o.ownerDocument : document, e = s && s.elementFromPoint(t.clientX, t.clientY);
f(e) || this.props.open || (clearInterval(this.updateIntervalId), this.willOpen = !1, this.onClose(t));
}, this.compareTargets = (t) => this.state.targetElement === t.nativeEvent.target, this.handleEscape = (t) => {
const o = this.compareTargets(t);
this.state.open && o && this.onClose(t);
}, this.handleTargetItemClick = (t) => {
const o = this.compareTargets(t);
if (this.state.open && o) {
this.onClose(t);
return;
}
this.showToolTip(t);
}, this.handleKeyDown = (t, o) => {
const s = t.key;
t.key === "Escape" ? this.handleEscape(t) : o.includes(s) && this.handleMouseOver(t);
}, this.handleMouseOver = (t) => {
const o = t.target;
!this.isVisible(o) || f(o) || o === this.state.targetElement || this.showToolTip(t);
}, this.handleBodyMousemove = (t) => {
this.top = t.clientY, this.left = t.clientX;
}, this.onClose = (t) => {
m(this.props.onClose, t, this, void 0), this.setState({ targetElement: null, open: !1, title: "" });
}, this.setUpdateInterval = () => {
this.props.updateInterval && (this.updateIntervalId = setInterval(this.onIntervalUpdate, this.props.updateInterval));
}, this.onIntervalUpdate = () => {
const t = this.state.targetElement;
t && (t.parentElement === null ? this.onClose({ target: t }) : this.showToolTip({ target: t }));
}, this.position = (t) => {
const o = I(this.state.targetElement), s = k(
this.left,
t.offsetWidth,
o,
this.props.anchorElement,
this.props.position
), e = C(
this.top,
o,
t.offsetHeight,
this.props.anchorElement,
this.props.position
);
return { left: s, top: e };
}, this.getTitle = (t) => {
for (; t; ) {
if (t.getAttribute("title") !== null || t.titleExpando)
return { title: t.getAttribute("title") || t.titleExpando, element: t };
t = this.props.parentTitle && t.parentElement || null;
}
return { title: "", element: t };
}, this.calloutClassName = () => {
switch (this.props.position) {
case "bottom":
return "k-callout k-callout-n";
case "left":
return "k-callout k-callout-e";
case "right":
return "k-callout k-callout-w";
case "top":
return "k-callout k-callout-s";
default:
return this.top < window.innerHeight / 2 ? "k-callout k-callout-n" : "k-callout k-callout-s";
}
}, this.getCurrentZIndex = () => this.context ? this.context : x;
}
/**
* @hidden
*/
componentDidMount() {
document && document.body.addEventListener("mousemove", this.handleBodyMousemove);
}
/**
* @hidden
*/
componentWillUnmount() {
clearTimeout(this.openTimeoutId), clearInterval(this.updateIntervalId), document && document.body.removeEventListener("mousemove", this.handleBodyMousemove);
}
/**
* @hidden
*/
componentDidUpdate() {
this.props.open && this.props.targetElement && this.showToolTip({ target: this.props.targetElement });
}
/**
* @hidden
*/
render() {
if (this.props.children) {
const { children: s, showOption: e, ...h } = this.props;
let n = null;
const c = (e == null ? void 0 : e.hover) !== void 0 ? e == null ? void 0 : e.hover : !0, g = (e == null ? void 0 : e.click) !== void 0 ? e == null ? void 0 : e.click : !1, v = (e == null ? void 0 : e.focus) !== void 0 ? e == null ? void 0 : e.focus : !1, a = (e == null ? void 0 : e.none) !== void 0 ? e == null ? void 0 : e.none : !1, u = ((e == null ? void 0 : e.keys) !== void 0 ? e == null ? void 0 : e.keys : []).map((i) => i === "Space" ? " " : i);
return /* @__PURE__ */ l.createElement(
"div",
{
onMouseOver: (i) => {
n && !a && c && n.handleMouseOver(i);
},
onMouseOut: (i) => {
n && !a && c && n.handleMouseOut(i);
},
onClick: (i) => {
n && !a && g && n.handleTargetItemClick(i);
},
onFocus: (i) => {
n && !a && v && n.handleMouseOver(i);
},
onKeyDown: (i) => {
(n && !a && u.length > 0 || n && !a && i.key === "Escape") && n.handleKeyDown(i, u);
}
},
/* @__PURE__ */ l.createElement(
p,
{
ref: (i) => {
n = i;
},
...h
}
),
s
);
}
if (this.props.open === !1)
return null;
const { targetElement: t } = this.state, o = this.getCurrentZIndex();
return t && this.state.title && t.ownerDocument && T.createPortal(
/* @__PURE__ */ l.createElement(
"div",
{
ref: (s) => {
if (!s)
return;
let e;
if (this.props.onPosition) {
const h = {
element: s,
targetElement: this.state.targetElement,
mouseTop: this.top,
mouseLeft: this.left,
anchorElement: this.props.anchorElement,
position: this.props.position,
target: this,
syntheticEvent: null,
nativeEvent: null
};
e = this.props.onPosition.call(void 0, h);
} else
e = this.position(s);
s.style.left = e.left + "px", s.style.top = e.top + "px";
},
className: d(
"k-animation-container",
"k-animation-container-fixed",
"k-animation-container-shown",
this.props.className
),
style: {
zIndex: o,
...this.props.style
},
tabIndex: 0
},
/* @__PURE__ */ l.createElement("div", { className: "k-child-animation-container" }, /* @__PURE__ */ l.createElement(
"div",
{
id: this.props.id,
role: "tooltip",
className: d("k-tooltip", this.props.tooltipClassName),
style: { position: "relative", ...this.props.tooltipStyle }
},
/* @__PURE__ */ l.createElement("div", { className: "k-tooltip-content" }, this.props.content && /* @__PURE__ */ l.createElement(this.props.content, { title: this.state.title, target: this.state.targetElement }) || this.state.title),
this.props.showCallout && /* @__PURE__ */ l.createElement(
"div",
{
ref: (s) => {
s && (s.className = this.calloutClassName(), this.props.position === "auto" && (this.left < window.screen.availWidth / 2 ? s.style.left = this.props.setCalloutOnPositionAuto || "25%" : s.style.left = this.props.setCalloutOnPositionAuto || "75%"));
}
}
)
))
),
this.props.appendTo ? this.props.appendTo : t.ownerDocument.body
);
}
showToolTip(t) {
clearTimeout(this.openTimeoutId), clearInterval(this.updateIntervalId), t.target.hasChildNodes() && t.target.childNodes.forEach((e) => {
e.nodeName === "title" && (t.target.titleExpando = e.innerHTML, e.remove());
});
const o = this.props.targetElement || t.target, s = this.getTitle(o);
if (!s.title) {
this.state.open && this.onClose(t);
return;
}
s.element && (s.element.titleExpando = s.title, s.element.title = ""), this.willOpen = !0, this.props.openDelay ? this.openTimeoutId = window.setTimeout(() => {
this.willOpen && this.setState(
{ targetElement: o, open: !0, title: s.title },
this.setUpdateInterval
);
}, this.props.openDelay) : this.setState({ targetElement: o, open: !0, title: s.title }, this.setUpdateInterval), this.state.title !== s.title && m(this.props.onOpen, t, this, void 0);
}
isVisible(t) {
return !this.props.filter || this.props.filter(t);
}
};
p.propTypes = {
anchorElement: r.oneOf(["pointer", "target"]),
content: r.func,
filter: r.func,
openDelay: r.number,
position: r.oneOf(["right", "left", "top", "bottom", "auto"]),
updateInterval: r.number,
showOption: r.object
}, p.defaultProps = {
anchorElement: "pointer",
openDelay: 400,
position: "auto",
showCallout: !0,
parentTitle: !1
}, p.contextType = y;
let E = p;
export {
E as Tooltip
};