"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Tooltip = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const react_dom_1 = __importDefault(require("react-dom"));
const react_popper_1 = require("react-popper");
const auto_id_1 = require("@reach/auto-id");
const web_1 = require("@react-spring/web");
require("./Tooltip.css");
const ANIMATION_CONFIGS = {
    fade: {
        from: { opacity: 0 },
        enter: { opacity: 1 },
        leave: { opacity: 0 },
    },
    scale: {
        from: { opacity: 0, transform: 'scale(0.95)' },
        enter: { opacity: 1, transform: 'scale(1)' },
        leave: { opacity: 0, transform: 'scale(0.95)' },
    },
    slide: {
        from: { opacity: 0, transform: 'translateY(10px)' },
        enter: { opacity: 1, transform: 'translateY(0)' },
        leave: { opacity: 0, transform: 'translateY(10px)' },
    },
    none: {
        from: {},
        enter: {},
        leave: {},
    },
};
const Tooltip = ({ children, content, placement = 'top', trigger = 'hover', size = 'md', isOpen: controlledIsOpen, onOpenChange, delay = 0, className, tooltipClassName, disabled, offset = 8, arrow = true, portal = false, portalTarget, ariaLabel = 'Tooltip', animation = 'fade', maxWidth = 300, interactive = false, hideDelay = 0, strategy = 'absolute', modifiers = [], onShow, onHide, zIndex = 1000, theme = 'system', }) => {
    const [uncontrolledIsOpen, setUncontrolledIsOpen] = (0, react_1.useState)(false);
    const [referenceElement, setReferenceElement] = (0, react_1.useState)(null);
    const [popperElement, setPopperElement] = (0, react_1.useState)(null);
    const [arrowElement, setArrowElement] = (0, react_1.useState)(null);
    const timeoutRef = (0, react_1.useRef)();
    const hideTimeoutRef = (0, react_1.useRef)();
    const tooltipId = (0, auto_id_1.useId)('tooltip');
    const triggerId = (0, auto_id_1.useId)('tooltip-trigger');
    const isControlled = controlledIsOpen !== undefined;
    const isOpen = isControlled ? controlledIsOpen : uncontrolledIsOpen;
    const { styles, attributes, update } = (0, react_popper_1.usePopper)(referenceElement, popperElement, {
        placement,
        strategy,
        modifiers: [
            {
                name: 'offset',
                options: {
                    offset: [0, offset],
                },
            },
            {
                name: 'arrow',
                options: {
                    element: arrowElement,
                    padding: 5,
                },
            },
            {
                name: 'preventOverflow',
                options: {
                    padding: 8,
                    boundary: 'viewport',
                },
            },
            {
                name: 'flip',
                options: {
                    padding: 8,
                    fallbackPlacements: ['top', 'right', 'bottom', 'left'],
                },
            },
            ...modifiers,
        ],
    });
    const transitions = (0, web_1.useTransition)(isOpen, {
        ...ANIMATION_CONFIGS[animation],
        config: {
            tension: 300,
            friction: 20,
        },
    });
    const handleOpenChange = (0, react_1.useCallback)((newIsOpen) => {
        if (!isControlled) {
            setUncontrolledIsOpen(newIsOpen);
        }
        onOpenChange?.(newIsOpen);
        if (newIsOpen) {
            onShow?.();
        }
        else {
            onHide?.();
        }
    }, [isControlled, onOpenChange, onShow, onHide]);
    const clearTimeouts = (0, react_1.useCallback)(() => {
        if (timeoutRef.current) {
            clearTimeout(timeoutRef.current);
        }
        if (hideTimeoutRef.current) {
            clearTimeout(hideTimeoutRef.current);
        }
    }, []);
    const handleTriggerMouseEnter = (0, react_1.useCallback)(() => {
        if (disabled)
            return;
        if (trigger === 'hover') {
            clearTimeouts();
            timeoutRef.current = setTimeout(() => {
                handleOpenChange(true);
            }, delay);
        }
    }, [disabled, trigger, delay, clearTimeouts, handleOpenChange]);
    const handleTriggerMouseLeave = (0, react_1.useCallback)(() => {
        if (disabled)
            return;
        if (trigger === 'hover' && !interactive) {
            clearTimeouts();
            hideTimeoutRef.current = setTimeout(() => {
                handleOpenChange(false);
            }, hideDelay);
        }
    }, [disabled, trigger, interactive, hideDelay, clearTimeouts, handleOpenChange]);
    const handleTriggerClick = (0, react_1.useCallback)(() => {
        if (disabled)
            return;
        if (trigger === 'click') {
            handleOpenChange(!isOpen);
        }
    }, [disabled, trigger, isOpen, handleOpenChange]);
    const handleTriggerFocus = (0, react_1.useCallback)(() => {
        if (disabled)
            return;
        if (trigger === 'focus') {
            handleOpenChange(true);
        }
    }, [disabled, trigger, handleOpenChange]);
    const handleTriggerBlur = (0, react_1.useCallback)(() => {
        if (disabled)
            return;
        if (trigger === 'focus') {
            handleOpenChange(false);
        }
    }, [disabled, trigger, handleOpenChange]);
    const handleKeyDown = (0, react_1.useCallback)((event) => {
        if (disabled)
            return;
        if (event.key === 'Escape' && isOpen) {
            handleOpenChange(false);
        }
    }, [disabled, isOpen, handleOpenChange]);
    (0, react_1.useEffect)(() => {
        const handleClickOutside = (event) => {
            if (trigger === 'click' &&
                popperElement &&
                referenceElement &&
                !popperElement.contains(event.target) &&
                !referenceElement.contains(event.target)) {
                handleOpenChange(false);
            }
        };
        if (isOpen && trigger === 'click') {
            document.addEventListener('mousedown', handleClickOutside);
        }
        return () => {
            document.removeEventListener('mousedown', handleClickOutside);
            clearTimeouts();
        };
    }, [isOpen, trigger, popperElement, referenceElement, handleOpenChange, clearTimeouts]);
    (0, react_1.useEffect)(() => {
        if (isOpen && update) {
            update();
        }
    }, [isOpen, update]);
    const tooltipClasses = [
        'bf-tooltip',
        `bf-tooltip--${size}`,
        `bf-tooltip--${placement}`,
        `bf-tooltip--${theme}`,
        arrow ? 'bf-tooltip--arrow' : '',
        interactive ? 'bf-tooltip--interactive' : '',
        tooltipClassName || '',
    ].filter(Boolean).join(' ');
    const triggerClasses = [
        'bf-tooltip__trigger',
        disabled ? 'bf-tooltip__trigger--disabled' : '',
        className || '',
    ].filter(Boolean).join(' ');
    const tooltipContent = ((0, jsx_runtime_1.jsxs)(web_1.animated.div, { ref: setPopperElement, className: tooltipClasses, role: "tooltip", "aria-label": ariaLabel, "aria-hidden": !isOpen, id: tooltipId, style: {
            ...styles.popper,
            zIndex,
            maxWidth: `${maxWidth}px`,
        }, ...attributes.popper, children: [arrow && ((0, jsx_runtime_1.jsx)("div", { ref: setArrowElement, className: "bf-tooltip__arrow", style: styles.arrow, "data-popper-arrow": true })), (0, jsx_runtime_1.jsx)("div", { className: "bf-tooltip__content", children: content })] }));
    return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { ref: setReferenceElement, className: triggerClasses, onMouseEnter: handleTriggerMouseEnter, onMouseLeave: handleTriggerMouseLeave, onClick: handleTriggerClick, onFocus: handleTriggerFocus, onBlur: handleTriggerBlur, onKeyDown: handleKeyDown, tabIndex: disabled ? -1 : 0, "aria-describedby": isOpen ? tooltipId : undefined, id: triggerId, role: trigger === 'click' ? 'button' : undefined, "aria-expanded": trigger === 'click' ? isOpen : undefined, children: children }), portal
                ? react_dom_1.default.createPortal(transitions((style, show) => show && ((0, jsx_runtime_1.jsx)(web_1.animated.div, { style: style, children: tooltipContent }))), portalTarget || document.body)
                : transitions((style, show) => show && ((0, jsx_runtime_1.jsx)(web_1.animated.div, { style: style, children: tooltipContent })))] }));
};
exports.Tooltip = Tooltip;
exports.default = exports.Tooltip;
//# sourceMappingURL=Tooltip.js.map