@antv/t8
Version:
T8 is a text visualization solution for unstructured data within the AntV technology stack, and it is a declarative JSON Schema syntax that can be used to describe the content of data interpretation reports.
220 lines (216 loc) • 9.74 kB
JavaScript
;
var tslib = require('tslib');
var jsxRuntime = require('preact/jsx-runtime');
var preact = require('preact');
var hooks = require('preact/hooks');
var getPrefixCls = require('../../../utils/getPrefixCls.js');
require('clarinet');
var TOOLTIP_CONTAINER_ID = 'ntv-tooltip-container';
// Create portal container.
var createContainer = function () {
if (document.getElementById(TOOLTIP_CONTAINER_ID)) {
return document.getElementById(TOOLTIP_CONTAINER_ID);
}
var container = document.createElement('div');
container.className = getPrefixCls.getPrefixCls('tooltip-container');
container.id = TOOLTIP_CONTAINER_ID;
document.body.appendChild(container);
return container;
};
var tooltipContentStyle = {
position: 'absolute',
zIndex: 1000,
padding: '6px 8px',
backgroundColor: 'rgba(0, 0, 0, 0.75)',
color: '#fff',
borderRadius: '4px',
fontSize: '12px',
maxWidth: '300px',
wordWrap: 'break-word',
boxShadow: '0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08)',
fontFamily: 'PingFang SC, Microsoft YaHei, Arial, sans-serif',
};
var arrowStyle = {
position: 'absolute',
width: '0',
height: '0',
borderStyle: 'solid',
borderWidth: '4px',
};
/**
* Tooltip Component
*
* A simple, lightweight tooltip component that displays tips when users interact with elements
*
* @example
* <Tooltip title="This is a tip">
* <button>Hover to see</button>
* </Tooltip>
*/
var Tooltip = function (_a) {
var title = _a.title, propsVisible = _a.visible, _b = _a.defaultVisible, defaultVisible = _b === void 0 ? false : _b, children = _a.children, _c = _a.placement, placement = _c === void 0 ? 'top' : _c, _d = _a.trigger, trigger = _d === void 0 ? 'hover' : _d, style = _a.style, className = _a.className, _e = _a.showArrow, showArrow = _e === void 0 ? true : _e, onVisibleChange = _a.onVisibleChange, _f = _a.offset, offset = _f === void 0 ? placement === 'top' || placement === 'bottom' ? 4 : 8 : _f, _g = _a.mouseEnterDelay, mouseEnterDelay = _g === void 0 ? 100 : _g, _h = _a.mouseLeaveDelay, mouseLeaveDelay = _h === void 0 ? 100 : _h;
// Store element references.
var triggerChildrenRef = hooks.useRef(null);
var tooltipRef = hooks.useRef(null);
var containerRef = hooks.useRef(null);
var enterTimer = hooks.useRef(null);
var leaveTimer = hooks.useRef(null);
var tooltipInnerRef = hooks.useRef(null);
// Control visibility.
var _j = hooks.useState(defaultVisible), visible = _j[0], setVisible = _j[1];
// if visible is provided, use it as the final visible state.
var finalVisible = propsVisible !== undefined ? propsVisible : visible;
// Ensure container is created only once.
hooks.useEffect(function () {
if (!containerRef.current) {
containerRef.current = createContainer();
}
// clear container when unmount.
return function () {
if (containerRef.current && containerRef.current.parentElement === document.body) {
document.body.removeChild(containerRef.current);
containerRef.current = null;
}
// Clear potential timers
if (enterTimer.current)
window.clearTimeout(enterTimer.current);
if (leaveTimer.current)
window.clearTimeout(leaveTimer.current);
};
}, []);
hooks.useEffect(function () {
// render tooltip when visible or title changes.
renderTooltip();
// // render title to tooltip-inner
// if (finalVisible) {
// renderTitle();
// }
}, [finalVisible, title]);
// Calculate tooltip position
hooks.useEffect(function () {
if (finalVisible && triggerChildrenRef.current && tooltipRef.current) {
var triggerRect = triggerChildrenRef.current.getBoundingClientRect();
var tooltipRect = tooltipRef.current.getBoundingClientRect();
var top_1 = 0;
var left = 0;
var arrowStyle_1 = {};
// Calculate coordinates based on placement
switch (placement) {
case 'top':
top_1 = triggerRect.top - tooltipRect.height - offset;
left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
arrowStyle_1 = {
bottom: '-8px',
left: '50%',
transform: 'translateX(-50%)',
borderColor: 'rgba(0, 0, 0, 0.75) transparent transparent transparent',
};
break;
case 'bottom':
top_1 = triggerRect.bottom + offset;
left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
arrowStyle_1 = {
top: '-8px',
left: '50%',
transform: 'translateX(-50%)',
borderColor: 'transparent transparent rgba(0, 0, 0, 0.75) transparent',
};
break;
case 'left':
top_1 = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
left = triggerRect.left - tooltipRect.width - offset;
arrowStyle_1 = {
right: '-8px',
top: '50%',
transform: 'translateY(-50%)',
borderColor: 'transparent transparent transparent rgba(0, 0, 0, 0.75)',
};
break;
case 'right':
top_1 = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
left = triggerRect.right + offset;
arrowStyle_1 = {
left: '-8px',
top: '50%',
transform: 'translateY(-50%)',
borderColor: 'transparent rgba(0, 0, 0, 0.75) transparent transparent',
};
break;
}
// Apply calculated position
tooltipRef.current.style.top = "".concat(top_1 + window.scrollY, "px");
tooltipRef.current.style.left = "".concat(left + window.scrollX, "px");
// If showing arrow, set arrow style
if (showArrow && tooltipRef.current.firstChild) {
var arrowElement = tooltipRef.current.firstChild;
Object.assign(arrowElement.style, arrowStyle_1);
}
}
}, [finalVisible, placement, offset, showArrow]);
// Handle visibility change
var handleVisibleChange = function (newVisible) {
if (propsVisible === undefined) {
setVisible(newVisible);
}
onVisibleChange === null || onVisibleChange === void 0 ? void 0 : onVisibleChange(newVisible);
};
// Mouse enter handler
var handleMouseEnter = function () {
if (leaveTimer.current) {
window.clearTimeout(leaveTimer.current);
leaveTimer.current = null;
}
if (!finalVisible) {
enterTimer.current = window.setTimeout(function () {
handleVisibleChange(true);
}, mouseEnterDelay);
}
};
// Mouse leave handler
var handleMouseLeave = function () {
if (enterTimer.current) {
window.clearTimeout(enterTimer.current);
enterTimer.current = null;
}
if (finalVisible) {
leaveTimer.current = window.setTimeout(function () {
handleVisibleChange(false);
}, mouseLeaveDelay);
}
};
// Click handler
var handleClick = function () {
handleVisibleChange(!finalVisible);
};
// Add event handlers based on trigger type
var triggerProps = {};
if (trigger === 'hover') {
triggerProps.onMouseEnter = handleMouseEnter;
triggerProps.onMouseLeave = handleMouseLeave;
}
else if (trigger === 'click') {
triggerProps.onClick = handleClick;
}
// Assign ref to the child element
triggerProps.ref = triggerChildrenRef;
triggerProps.className = getPrefixCls.getPrefixCls('tooltip-trigger');
// Render tooltip content
var renderTooltip = function () {
var container = containerRef.current;
var tooltipContent = !finalVisible || !title ? null : (jsxRuntime.jsxs("div", { ref: tooltipRef, className: "".concat(getPrefixCls.getPrefixCls('tooltip'), " ").concat(className || ''), style: tslib.__assign(tslib.__assign({}, tooltipContentStyle), style), onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [showArrow && jsxRuntime.jsx("div", { className: getPrefixCls.getPrefixCls('tooltip-arrow'), style: arrowStyle }), jsxRuntime.jsx("div", { className: getPrefixCls.getPrefixCls('tooltip-inner'), id: "tooltip-inner", ref: tooltipInnerRef })] }));
preact.render(tooltipContent, container);
// apply real dom to tooltip-inner when visible.
if (tooltipInnerRef.current && finalVisible) {
if (typeof title === 'string' || typeof title === 'number') {
tooltipInnerRef.current.appendChild(document.createTextNode(String(title)));
}
else if (title instanceof HTMLElement) {
tooltipInnerRef.current.appendChild(title);
}
}
};
// Return the modified child and tooltip
return jsxRuntime.jsx("span", tslib.__assign({}, triggerProps, { children: children }));
};
exports.Tooltip = Tooltip;
//# sourceMappingURL=Tooltip.js.map