"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.popoverBaseProps = void 0;
const vue_1 = require("vue");
const vueuc_1 = require("vueuc");
const vooks_1 = require("vooks");
const _utils_1 = require("../../_utils");
const _mixins_1 = require("../../_mixins");
const PopoverBody_1 = require("./PopoverBody");
const bodyPropKeys = Object.keys(PopoverBody_1.popoverBodyProps);
const triggerEventMap = {
    focus: ['onFocus', 'onBlur'],
    click: ['onClick'],
    hover: ['onMouseenter', 'onMouseleave'],
    manual: []
};
function appendEvents(vNode, trigger, events) {
    triggerEventMap[trigger].forEach((eventName) => {
        if (!vNode.props)
            vNode.props = {};
        else {
            vNode.props = Object.assign({}, vNode.props);
        }
        const originalHandler = vNode.props[eventName];
        const handler = events[eventName];
        if (!originalHandler)
            vNode.props[eventName] = handler;
        else {
            vNode.props[eventName] = (...args) => {
                originalHandler(...args);
                handler(...args);
            };
        }
    });
}
const textVNodeType = vue_1.createTextVNode('').type;
exports.popoverBaseProps = {
    show: {
        type: Boolean,
        default: undefined
    },
    defaultShow: Boolean,
    showArrow: {
        type: Boolean,
        default: true
    },
    trigger: {
        type: String,
        default: 'hover'
    },
    delay: {
        type: Number,
        default: 100
    },
    duration: {
        type: Number,
        default: 100
    },
    raw: Boolean,
    placement: {
        type: String,
        default: 'top'
    },
    x: Number,
    y: Number,
    disabled: Boolean,
    getDisabled: Function,
    displayDirective: {
        type: String,
        default: 'if'
    },
    arrowStyle: [String, Object],
    filp: {
        type: Boolean,
        default: true
    },
    animated: {
        type: Boolean,
        default: true
    },
    width: {
        type: [Number, String],
        default: undefined
    },
    overlap: Boolean,
    internalExtraClass: {
        type: Array,
        default: () => []
    },
    onClickoutside: Function,
    // events
    'onUpdate:show': [Function, Array],
    onUpdateShow: [Function, Array],
    /** @deprecated */
    onShow: {
        type: [Function, Array],
        validator: () => {
            _utils_1.warn('popover', '`on-show` is deprecated, please use `on-update:show` instead.');
            return true;
        },
        default: undefined
    },
    /** @deprecated */
    onHide: {
        type: [Function, Array],
        validator: () => {
            _utils_1.warn('popover', '`on-hide` is deprecated, please use `on-update:show` instead.');
            return true;
        },
        default: undefined
    },
    /** @deprecated */
    arrow: {
        type: Boolean,
        default: undefined
    },
    /** @deprecated */
    minWidth: Number,
    /** @deprecated */
    maxWidth: Number
};
const popoverProps = Object.assign(Object.assign(Object.assign({}, _mixins_1.useTheme.props), exports.popoverBaseProps), { internalRenderBody: Function });
exports.default = vue_1.defineComponent({
    name: 'Popover',
    inheritAttrs: false,
    props: popoverProps,
    setup(props) {
        const isMountedRef = vooks_1.useIsMounted();
        // setup show
        const controlledShowRef = vue_1.computed(() => props.show);
        const uncontrolledShowRef = vue_1.ref(props.defaultShow);
        const mergedShowWithoutDisabledRef = vooks_1.useMergedState(controlledShowRef, uncontrolledShowRef);
        const getMergedDisabled = () => {
            if (props.disabled)
                return true;
            const { getDisabled } = props;
            if (getDisabled === null || getDisabled === void 0 ? void 0 : getDisabled())
                return true;
            return false;
        };
        const getMergedShow = () => {
            if (getMergedDisabled())
                return false;
            return mergedShowWithoutDisabledRef.value;
        };
        // setup show-arrow
        const compatibleShowArrowRef = vooks_1.useCompitable(props, ['arrow', 'showArrow']);
        const mergedShowArrowRef = vue_1.computed(() => {
            if (props.overlap)
                return false;
            return compatibleShowArrowRef.value;
        });
        // trigger
        let triggerVNode = null;
        // bodyInstance
        let bodyInstance = null;
        const showTimerIdRef = vue_1.ref(null);
        const hideTimerIdRef = vue_1.ref(null);
        const positionManuallyRef = vooks_1.useMemo(() => {
            return props.x !== undefined && props.y !== undefined;
        });
        // methods
        function doUpdateShow(value) {
            const { 'onUpdate:show': _onUpdateShow, onUpdateShow, onShow, onHide } = props;
            uncontrolledShowRef.value = value;
            if (_onUpdateShow) {
                _utils_1.call(_onUpdateShow, value);
            }
            if (onUpdateShow) {
                _utils_1.call(onUpdateShow, value);
            }
            if (value && onShow) {
                _utils_1.call(onShow, true);
            }
            if (value && onHide) {
                _utils_1.call(onHide, false);
            }
        }
        function syncPosition() {
            if (bodyInstance) {
                bodyInstance.syncPosition();
            }
        }
        function clearShowTimer() {
            const { value: showTimerId } = showTimerIdRef;
            if (showTimerId) {
                window.clearTimeout(showTimerId);
                showTimerIdRef.value = null;
            }
        }
        function clearHideTimer() {
            const { value: hideTimerId } = hideTimerIdRef;
            if (hideTimerId) {
                window.clearTimeout(hideTimerId);
                hideTimerIdRef.value = null;
            }
        }
        function handleFocus() {
            const mergedDisabled = getMergedDisabled();
            if (props.trigger === 'focus' && !mergedDisabled) {
                if (getMergedShow())
                    return;
                doUpdateShow(true);
            }
        }
        function handleBlur() {
            const mergedDisabled = getMergedDisabled();
            if (props.trigger === 'focus' && !mergedDisabled) {
                if (!getMergedShow())
                    return;
                doUpdateShow(false);
            }
        }
        function handleMouseEnter() {
            const mergedDisabled = getMergedDisabled();
            if (props.trigger === 'hover' && !mergedDisabled) {
                clearHideTimer();
                if (showTimerIdRef.value !== null)
                    return;
                if (getMergedShow())
                    return;
                const delayCallback = () => {
                    doUpdateShow(true);
                    showTimerIdRef.value = null;
                };
                const { delay } = props;
                if (delay === 0) {
                    delayCallback();
                }
                else {
                    showTimerIdRef.value = window.setTimeout(delayCallback, delay);
                }
            }
        }
        function handleMouseLeave() {
            const mergedDisabled = getMergedDisabled();
            if (props.trigger === 'hover' && !mergedDisabled) {
                clearShowTimer();
                if (hideTimerIdRef.value !== null)
                    return;
                if (!getMergedShow())
                    return;
                const delayedCallback = () => {
                    doUpdateShow(false);
                    hideTimerIdRef.value = null;
                };
                const { duration } = props;
                if (duration === 0) {
                    delayedCallback();
                }
                else {
                    hideTimerIdRef.value = window.setTimeout(delayedCallback, duration);
                }
            }
        }
        // will be called in popover-content
        function handleMouseMoveOutside() {
            handleMouseLeave();
        }
        // will be called in popover-content
        function handleClickOutside(e) {
            var _a;
            if (!getMergedShow())
                return;
            if (props.trigger === 'click') {
                clearShowTimer();
                clearHideTimer();
                doUpdateShow(false);
            }
            (_a = props.onClickoutside) === null || _a === void 0 ? void 0 : _a.call(props, e);
        }
        function handleClick() {
            if (props.trigger === 'click' && !getMergedDisabled()) {
                clearShowTimer();
                clearHideTimer();
                const nextShow = !getMergedShow();
                doUpdateShow(nextShow);
            }
        }
        function setShow(value) {
            uncontrolledShowRef.value = value;
        }
        function getTriggerElement() {
            return triggerVNode === null || triggerVNode === void 0 ? void 0 : triggerVNode.el;
        }
        function setBodyInstance(value) {
            bodyInstance = value;
        }
        vue_1.provide('NPopover', {
            getTriggerElement,
            handleMouseEnter,
            handleMouseLeave,
            handleClickOutside,
            handleMouseMoveOutside,
            setBodyInstance,
            positionManuallyRef: positionManuallyRef,
            isMountedRef: isMountedRef,
            extraClassRef: vue_1.toRef(props, 'internalExtraClass'),
            internalRenderBodyRef: vue_1.toRef(props, 'internalRenderBody')
        });
        return {
            positionManually: positionManuallyRef,
            // if to show popover body
            uncontrolledShow: uncontrolledShowRef,
            mergedShowArrow: mergedShowArrowRef,
            getMergedShow,
            setShow,
            handleClick,
            handleMouseEnter,
            handleMouseLeave,
            handleFocus,
            handleBlur,
            setTriggerVNode(v) {
                triggerVNode = v;
            },
            syncPosition
        };
    },
    render() {
        const { positionManually } = this;
        const slots = Object.assign({}, this.$slots);
        let triggerVNode;
        if (!positionManually) {
            if (slots.activator) {
                triggerVNode = _utils_1.getFirstSlotVNode(slots, 'activator');
            }
            else {
                triggerVNode = _utils_1.getFirstSlotVNode(slots, 'trigger');
            }
            if (triggerVNode) {
                triggerVNode =
                    triggerVNode.type === textVNodeType
                        ? vue_1.h('span', [triggerVNode])
                        : triggerVNode;
                appendEvents(triggerVNode, positionManually ? 'manual' : this.trigger, {
                    onClick: this.handleClick,
                    onMouseenter: this.handleMouseEnter,
                    onMouseleave: this.handleMouseLeave,
                    onFocus: this.handleFocus,
                    onBlur: this.handleBlur
                });
            }
            this.setTriggerVNode(triggerVNode);
        }
        return vue_1.h(vueuc_1.VBinder, null, {
            default: () => {
                const mergedShow = this.getMergedShow();
                return [
                    positionManually
                        ? null
                        : vue_1.h(vueuc_1.VTarget, null, {
                            default: () => triggerVNode
                        }),
                    vue_1.h(PopoverBody_1.default, _utils_1.keep(this.$props, bodyPropKeys, Object.assign(Object.assign({}, this.$attrs), { showArrow: this.mergedShowArrow, show: mergedShow })), slots)
                ];
            }
        });
    }
});
