UNPKG

@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
/** * @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 };