phx-react
Version:
PHX REACT
284 lines • 14.9 kB
JavaScript
;
exports.__esModule = true;
var tslib_1 = require("tslib");
var react_1 = tslib_1.__importStar(require("react"));
var react_dom_1 = require("react-dom");
var PHXTooltip = function (_a) {
var children = _a.children, _b = _a.className, className = _b === void 0 ? '' : _b, content = _a.content, _c = _a.contentClassName, contentClassName = _c === void 0 ? 'max-w-[18rem]' : _c, _d = _a.isDisableHover, isDisableHover = _d === void 0 ? false : _d, placement = _a.placement, _e = _a.underLine, underLine = _e === void 0 ? false : _e, _f = _a.hideDelay, hideDelay = _f === void 0 ? 200 : _f;
var contentRef = (0, react_1.useRef)(null);
var titleRef = (0, react_1.useRef)(null);
var _g = (0, react_1.useState)({
top: 0,
left: 0,
width: 0,
height: 0,
pos: 'top',
show: false,
arrowOffset: 0
}), contentProps = _g[0], setContentProps = _g[1];
var hideTimeoutRef = (0, react_1.useRef)();
var isMobile = function () { return window.innerWidth <= 768; };
var getOverflowDirections = function (_a) {
var height = _a.height, left = _a.left, top = _a.top, width = _a.width;
var viewportWidth = window.innerWidth;
var viewportHeight = window.innerHeight;
var margin = isMobile() ? 20 : 10;
return {
isOverFlowTop: top < margin,
isOverFlowLeft: left < margin,
isOverFlowBottom: top + height > viewportHeight - margin,
isOverFlowRight: left + width > viewportWidth - margin
};
};
var getPositionProps = function (position, titleBounding, contentBounding) {
var titleTop = titleBounding.top;
var titleLeft = titleBounding.left;
var titleWidth = titleBounding.width;
var titleHeight = titleBounding.height;
switch (position) {
case 'top':
return {
width: contentBounding.width,
height: contentBounding.height,
top: titleTop - contentBounding.height - 10,
left: titleLeft - contentBounding.width / 2 + titleWidth / 2,
pos: 'top'
};
case 'bottom':
return {
width: contentBounding.width,
height: contentBounding.height,
top: titleTop + titleHeight + 10,
left: titleLeft - contentBounding.width / 2 + titleWidth / 2,
pos: 'bottom'
};
case 'left':
return {
width: contentBounding.width,
height: contentBounding.height,
top: titleTop - contentBounding.height / 2 + titleHeight / 2,
left: titleLeft - contentBounding.width - 20,
pos: 'left'
};
case 'right':
return {
width: contentBounding.width,
height: contentBounding.height,
top: titleTop - contentBounding.height / 2 + titleHeight / 2,
left: titleLeft + titleWidth + 20,
pos: 'right'
};
default:
return {
width: contentBounding.width,
height: contentBounding.height,
top: titleTop - contentBounding.height - 10,
left: titleLeft - contentBounding.width / 2 + titleWidth / 2,
pos: 'top'
};
}
};
var showTimeoutRef = (0, react_1.useRef)();
var calculateTooltipPosition = (0, react_1.useCallback)(function () {
if (!contentRef.current || !titleRef.current)
return;
var titleBounding = titleRef.current.getBoundingClientRect();
var contentBounding = contentRef.current.getBoundingClientRect();
var preferredPlacement = isMobile() ? 'bottom' : placement || 'top';
var newProps = getPositionProps(preferredPlacement, titleBounding, contentBounding);
var overflowDirections = getOverflowDirections(newProps);
var titleCenter = titleBounding.left + titleBounding.width / 2;
var titleVerticalCenter = titleBounding.top + titleBounding.height / 2;
var arrowOffset = 0;
if (isMobile()) {
if (overflowDirections.isOverFlowBottom) {
newProps = getPositionProps('top', titleBounding, contentBounding);
var topOverflow = getOverflowDirections(newProps);
if (topOverflow.isOverFlowTop) {
newProps = tslib_1.__assign(tslib_1.__assign({}, newProps), { top: Math.max(20, Math.min(window.innerHeight - newProps.height - 20, titleBounding.top)) });
}
}
}
else {
if (placement === 'top' && overflowDirections.isOverFlowTop) {
newProps = getPositionProps('bottom', titleBounding, contentBounding);
}
else if (placement === 'bottom' && overflowDirections.isOverFlowBottom) {
newProps = getPositionProps('top', titleBounding, contentBounding);
}
else if (placement === 'left' && overflowDirections.isOverFlowLeft) {
newProps = getPositionProps('right', titleBounding, contentBounding);
}
else if (placement === 'right' && overflowDirections.isOverFlowRight) {
newProps = getPositionProps('left', titleBounding, contentBounding);
}
}
var finalOverflow = getOverflowDirections(newProps);
if (finalOverflow.isOverFlowLeft || finalOverflow.isOverFlowRight) {
if (newProps.pos === 'top' || newProps.pos === 'bottom') {
if (finalOverflow.isOverFlowRight) {
var leftProps = getPositionProps('left', titleBounding, contentBounding);
var leftOverflow = getOverflowDirections(leftProps);
if (!leftOverflow.isOverFlowLeft) {
newProps = leftProps;
}
else {
var margin = isMobile() ? 20 : 10;
newProps.left = Math.max(margin, Math.min(window.innerWidth - newProps.width - margin, newProps.left));
}
}
else if (finalOverflow.isOverFlowLeft) {
var rightProps = getPositionProps('right', titleBounding, contentBounding);
var rightOverflow = getOverflowDirections(rightProps);
if (!rightOverflow.isOverFlowRight) {
newProps = rightProps;
}
else {
var margin = isMobile() ? 20 : 10;
newProps.left = Math.max(margin, Math.min(window.innerWidth - newProps.width - margin, newProps.left));
}
}
}
else {
var margin = isMobile() ? 20 : 10;
newProps.left = Math.max(margin, Math.min(window.innerWidth - newProps.width - margin, newProps.left));
}
}
if (newProps.pos === 'top' || newProps.pos === 'bottom') {
arrowOffset = titleCenter - (newProps.left + newProps.width / 2);
var maxOffset = newProps.width / 2 - 15;
arrowOffset = Math.max(-maxOffset, Math.min(maxOffset, arrowOffset));
}
if (newProps.pos === 'left' || newProps.pos === 'right') {
arrowOffset = titleVerticalCenter - (newProps.top + newProps.height / 2);
var maxOffset = newProps.height / 2 - 15;
arrowOffset = Math.max(-maxOffset, Math.min(maxOffset, arrowOffset));
}
setContentProps(function (prev) { return (tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, prev), newProps), { arrowOffset: arrowOffset })); });
}, [placement]);
var handleMouseEnter = function () {
if (hideTimeoutRef.current) {
clearTimeout(hideTimeoutRef.current);
hideTimeoutRef.current = undefined;
}
if (showTimeoutRef.current) {
clearTimeout(showTimeoutRef.current);
}
showTimeoutRef.current = setTimeout(function () {
setContentProps(function (prev) { return (tslib_1.__assign(tslib_1.__assign({}, prev), { show: true })); });
setTimeout(function () {
calculateTooltipPosition();
}, 10);
}, 250); // <-- Độ trễ 250ms trước khi hiển thị tooltip
};
var handleMouseLeave = function () {
if (showTimeoutRef.current) {
clearTimeout(showTimeoutRef.current);
showTimeoutRef.current = undefined;
}
if (hideTimeoutRef.current) {
clearTimeout(hideTimeoutRef.current);
}
hideTimeoutRef.current = setTimeout(function () {
setContentProps(function (prev) { return (tslib_1.__assign(tslib_1.__assign({}, prev), { show: false })); });
}, hideDelay);
};
var handleMobileClick = function () {
if (isMobile()) {
setContentProps(function (prev) {
setTimeout(function () {
calculateTooltipPosition();
}, 10);
return tslib_1.__assign(tslib_1.__assign({}, prev), { show: true });
});
}
};
(0, react_1.useEffect)(function () {
return function () {
if (hideTimeoutRef.current) {
clearTimeout(hideTimeoutRef.current);
}
if (showTimeoutRef.current) {
clearTimeout(showTimeoutRef.current);
}
};
}, []);
(0, react_1.useEffect)(function () {
var timeoutId;
var isCalculating = false;
var touchStartX = 0;
var touchStartY = 0;
var updatePosition = function () {
if (contentProps.show && !isCalculating) {
isCalculating = true;
calculateTooltipPosition();
timeoutId = setTimeout(function () {
isCalculating = false;
}, 100);
}
};
var handleTouchStart = function (e) {
if (contentProps.show && isMobile()) {
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
}
};
var handleTouchMove = function (e) {
if (contentProps.show && isMobile()) {
var touchEndX = e.touches[0].clientX;
var touchEndY = e.touches[0].clientY;
var deltaX = Math.abs(touchEndX - touchStartX);
var deltaY = Math.abs(touchEndY - touchStartY);
if (deltaX > 30 || deltaY > 30) {
setContentProps(function (prev) { return (tslib_1.__assign(tslib_1.__assign({}, prev), { show: false })); });
}
}
};
if (contentProps.show) {
updatePosition();
if (isMobile()) {
document.addEventListener('touchstart', handleTouchStart, {
passive: true
});
document.addEventListener('touchmove', handleTouchMove, {
passive: true
});
}
}
return function () {
if (timeoutId) {
clearTimeout(timeoutId);
}
if (isMobile()) {
document.removeEventListener('touchstart', handleTouchStart);
document.removeEventListener('touchmove', handleTouchMove);
}
};
}, [contentProps.show, calculateTooltipPosition]);
return (react_1["default"].createElement("div", { className: "relative w-fit text-xs font-normal text-gray-600 ".concat(underLine && 'border-b-2 border-dotted border-[#B5B5B5] pb-[1px]', " ").concat(className), onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave },
content &&
(0, react_dom_1.createPortal)(react_1["default"].createElement("div", { className: "fixed z-[999] mb-2 flex transform flex-col items-center justify-center drop-shadow-md transition-opacity duration-200 ".concat(contentProps.show ? 'visible opacity-100' : 'invisible opacity-0 pointer-events-none'), onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: {
top: contentProps.top,
left: contentProps.left
} },
react_1["default"].createElement("p", { ref: contentRef, className: "whitespace-pre-wrap break-words rounded-lg border-[1px] border-gray-300 bg-white p-2 text-xs text-gray-800 ".concat(contentClassName) }, content),
react_1["default"].createElement("svg", { className: "absolute ".concat(contentProps.pos === 'top' ? '-bottom-[10px] rotate-180' : '', " ").concat(contentProps.pos === 'bottom' ? '-top-[10px]' : '', " ").concat(contentProps.pos === 'left' ? '-right-[12px] rotate-90' : '', " ").concat(contentProps.pos === 'right' ? '-left-[12px] -rotate-90' : ''), fill: 'none', height: '16', style: tslib_1.__assign({}, (contentProps.pos === 'top' || contentProps.pos === 'bottom'
? {
left: "calc(50% + ".concat(contentProps.arrowOffset, "px)"),
transform: "translateX(-50%) ".concat(contentProps.pos === 'top' ? 'rotate(180deg)' : '')
}
: {
top: "calc(50% + ".concat(contentProps.arrowOffset, "px)"),
transform: "translateY(-50%) ".concat(contentProps.pos === 'left'
? 'rotate(90deg)'
: contentProps.pos === 'right'
? 'rotate(-90deg)'
: '')
})), viewBox: '0 0 20 16', width: '20', xmlns: 'http://www.w3.org/2000/svg' },
react_1["default"].createElement("path", { d: 'M10.6082 1.2699L17.3135 10.5611C17.6715 11.0571 17.3171 11.75 16.7053 11.75H3.29465C2.68295 11.75 2.32852 11.0571 2.68649 10.5611L9.39184 1.2699C9.69119 0.855102 10.3088 0.855102 10.6082 1.2699Z', fill: 'white', stroke: '#D1D5DB', strokeWidth: '1' }),
react_1["default"].createElement("rect", { fill: 'white', height: '3', rx: '1.5', width: '16', x: '2', y: '10' })),
!isDisableHover && react_1["default"].createElement("div", { className: 'absolute cursor-pointer top-12 h-7 w-1' })), document.body),
react_1["default"].createElement("div", { ref: titleRef, onClick: handleMobileClick }, children)));
};
exports["default"] = PHXTooltip;
//# sourceMappingURL=ToolTip.js.map