"use strict";
const vue = require("vue");
const types = require("./types.js");
const dom = require("../_utils/dom.js");
const helper = require("../_utils/helper.js");
const is = require("../_utils/is.js");
const popup = require("./popup.js");
const useResizeObserver = require("../hooks/use-resize-observer.js");
const resizeObserver = require("../resize-observer/resize-observer.js");
const useIntersectionObserver = require("../hooks/use-intersection-observer.js");
const useScreen = require("../hooks/use-screen.js");
const childOnly = require("../child-only/child-only.js");
const clientOnly = require("../_components/client-only.js");
const vueUtils = require("../_utils/vue-utils.js");
const zIndex = require("../_utils/z-index.js");
const __default__ = {
  inheritAttrs: false
};
const _sfc_main = /* @__PURE__ */ vue.defineComponent({
  ...__default__,
  __name: "OPopup",
  props: types.popupProps,
  emits: ["update:visible", "change"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emits = __emit;
    const { isPhonePad } = useScreen.useScreen();
    const triggers = vue.computed(() => {
      const triggers2 = is.isArray(props.trigger) ? props.trigger : [props.trigger];
      if (isPhonePad.value) {
        const r = triggers2.filter((item) => ["none", "click-outclick", "click"].includes(item));
        return r.length > 0 ? r : ["click"];
      }
      return triggers2;
    });
    const visible = vue.ref(false);
    const targetElRef = vue.ref(null);
    let targetEl = null;
    const isTargetInViewport = vue.ref(true);
    let wrapperEl = vue.ref(null);
    const popupRef = vue.ref(null);
    const popStyle = vue.reactive({
      "--popup-edge-offset": `${props.edgeOffset}px`
    });
    const popPosition = vue.ref(props.position);
    const wrapOrigin = vue.ref({ left: "0px", top: "0px" });
    const wrapStyle = vue.computed(() => ({
      transformOrigin: `${wrapOrigin.value.left} ${wrapOrigin.value.top}`
    }));
    const anchorStyle = vue.reactive({});
    const toMount = vue.ref(false);
    const isAnimating = vue.ref(false);
    let ro = null;
    let io = null;
    const updateZIndex = (show) => {
      if (show) {
        popStyle["--popup-z-index"] = zIndex.createTopZIndex();
      } else {
        zIndex.removeZIndex(popStyle["--popup-z-index"]);
      }
    };
    vue.onMounted(() => {
      ro = useResizeObserver.useResizeObserver();
      io = useIntersectionObserver.useIntersectionObserver();
      visible.value = props.visible;
      if (props.visible) {
        updateZIndex(props.visible);
      }
      const { target, wrapper } = vue.toRefs(props);
      vueUtils.resolveHtmlElement(target).then((el) => {
        if (el) {
          bindTargetEvent(el);
        }
      });
      vueUtils.resolveHtmlElement(wrapper).then((el) => {
        if (el) {
          wrapperEl.value = el;
        }
      });
    });
    let triggerListener = [];
    const bindTargetEvent = (el) => {
      if (!el) {
        return;
      }
      targetEl = el;
      if (props.adjustMinWidth) {
        popStyle.minWidth = `${targetEl.offsetWidth}px`;
      } else if (props.adjustWidth) {
        popStyle.width = `${targetEl.offsetWidth}px`;
      }
      triggerListener = popup.bindTrigger(el, popupRef, triggers.value, {
        updateFn: updateVisible,
        hoverDelay: props.hoverDelay,
        autoHide: props.autoHide
      });
      if (props.hideWhenTargetInvisible) {
        io == null ? void 0 : io.observe(targetEl, onTargetInterscting);
      }
    };
    vue.onUnmounted(() => {
      triggerListener.forEach((fn) => {
        fn();
      });
      if (wrapperEl.value) {
        ro == null ? void 0 : ro.unobserve(wrapperEl.value, onResize);
      }
      if (targetEl) {
        ro == null ? void 0 : ro.unobserve(targetEl, onResize);
      }
    });
    const updatePopupStyle = () => {
      if (props.hideWhenTargetInvisible && !isTargetInViewport.value) {
        return;
      }
      if (!targetEl || !popupRef.value || !wrapperEl.value) {
        return;
      }
      const {
        popupStyle: pStyle,
        position,
        anchorStyle: aStyle
      } = popup.calcPopupStyle(popupRef.value, targetEl, props.position, {
        adaptive: props.adaptive,
        offset: props.offset,
        edgeOffset: props.edgeOffset,
        anchor: props.anchor
      });
      wrapOrigin.value = popup.getTransformOrigin(position);
      if (pStyle) {
        popStyle.top = `${Math.floor(pStyle.top)}px`;
        popStyle.left = `${Math.floor(pStyle.left)}px`;
        popPosition.value = position;
      }
      if (aStyle) {
        Object.keys(aStyle).forEach((k) => {
          const val = aStyle[k];
          anchorStyle[k] = `${Math.floor(val)}px`;
        });
      }
    };
    let oldIntersecting = null;
    const onTargetInterscting = (entry) => {
      isTargetInViewport.value = entry.isIntersecting;
      if (oldIntersecting !== null && entry.isIntersecting) {
        if (visible.value) {
          vue.nextTick(() => {
            updatePopupStyle();
          });
        }
      }
      oldIntersecting = isTargetInViewport.value;
    };
    const beforeToggle = async (show) => {
      let goon = true;
      if (show) {
        if (is.isFunction(props.beforeShow)) {
          goon = await props.beforeShow();
        }
      } else {
        if (is.isFunction(props.beforeHide)) {
          goon = await props.beforeHide();
        }
      }
      return goon !== false;
    };
    vue.watch(
      () => props.visible,
      async (val) => {
        if (visible.value === val) {
          return;
        }
        const goon = await beforeToggle(val);
        if (!goon) {
          emits("update:visible", visible.value);
          return;
        }
        updateVisible(val);
        updateZIndex(val);
        if (val) {
          vue.nextTick(() => {
            updatePopupStyle();
          });
        }
      }
    );
    let visibleTimer = 0;
    const clearVisibleTimer = () => {
      if (visibleTimer) {
        window.clearTimeout(visibleTimer);
        visibleTimer = 0;
      }
    };
    const updateVisible = async (isVisible, delay) => {
      if (props.disabled) {
        return;
      }
      const v = isVisible === void 0 ? !visible.value : isVisible;
      if (v === visible.value && visibleTimer === 0) {
        return;
      }
      const update = () => {
        if (visible.value === v) {
          return;
        }
        visible.value = v;
        updateZIndex(v);
        emits("update:visible", v);
        emits("change", v);
        if (v) {
          toMount.value = true;
          if (props.hideWhenTargetInvisible && targetEl) {
            io == null ? void 0 : io.observe(targetEl, onTargetInterscting);
          }
        }
      };
      const goon = await beforeToggle(v);
      if (!goon) {
        return;
      }
      if (delay) {
        clearVisibleTimer();
        visibleTimer = window.setTimeout(update, delay);
      } else {
        update();
      }
    };
    vue.watch(targetElRef, (elRef) => {
      if (dom.isHtmlElement(elRef == null ? void 0 : elRef.$el)) {
        bindTargetEvent(elRef == null ? void 0 : elRef.$el);
      }
    });
    const onResize = (_en, isFirst) => {
      if (visible.value && !isFirst) {
        updatePopupStyle();
      }
    };
    const onPopupResize = helper.debounce((en) => {
      onResize(en, false);
    }, 100);
    const handleTransitionStart = () => {
      isAnimating.value = true;
    };
    const handleTransitionEnd = () => {
      isAnimating.value = false;
      if (!visible.value && props.unmountOnHide) {
        toMount.value = false;
      }
    };
    const scrollListener = helper.throttleRAF(() => {
      if (visible.value) {
        updatePopupStyle();
      }
    });
    const listenScroll = (el) => {
      el.addEventListener("scroll", scrollListener, { passive: true });
      return () => {
        el.removeEventListener("scroll", scrollListener);
      };
    };
    vue.watch(popupRef, (popEl) => {
      let handles = [];
      if (popEl) {
        if (targetEl) {
          const scrollers = dom.getScrollParents(targetEl);
          handles = scrollers.map((el) => {
            return listenScroll(el);
          });
          ro == null ? void 0 : ro.observe(targetEl, (en, isFirst) => {
            if (props.adjustMinWidth) {
              popStyle.minWidth = `${targetEl == null ? void 0 : targetEl.offsetWidth}px`;
            } else if (props.adjustWidth) {
              popStyle.width = `${targetEl == null ? void 0 : targetEl.offsetWidth}px`;
            }
            onResize(en, isFirst);
          });
        }
        if (wrapperEl.value) {
          ro == null ? void 0 : ro.observe(wrapperEl.value, onResize);
        }
      } else {
        handles.forEach((hl) => hl());
        if (wrapperEl.value) {
          ro == null ? void 0 : ro.unobserve(wrapperEl.value, onResize);
        }
        if (targetEl) {
          ro == null ? void 0 : ro.unobserve(targetEl, onResize);
          io == null ? void 0 : io.unobserve(targetEl, onTargetInterscting);
          isTargetInViewport.value = true;
        }
      }
    });
    const onPopupHoverIn = () => {
      if (triggers.value.includes("hover")) {
        updateVisible(true, props.hoverDelay);
      }
    };
    const onPopupHoverOut = () => {
      if (triggers.value.includes("hover") && props.autoHide) {
        updateVisible(false, props.hoverDelay);
      }
    };
    const sholdUmMount = vue.computed(() => {
      return toMount.value || visible.value || !props.unmountOnHide;
    });
    return (_ctx, _cache) => {
      return vue.openBlock(), vue.createElementBlock(
        vue.Fragment,
        null,
        [
          _ctx.$slots.target ? (vue.openBlock(), vue.createBlock(
            vue.unref(childOnly),
            {
              key: 0,
              ref_key: "targetElRef",
              ref: targetElRef
            },
            {
              default: vue.withCtx(() => [
                vue.renderSlot(_ctx.$slots, "target")
              ]),
              _: 3
              /* FORWARDED */
            },
            512
            /* NEED_PATCH */
          )) : vue.createCommentVNode("v-if", true),
          !props.disabled ? (vue.openBlock(), vue.createBlock(vue.unref(clientOnly), { key: 1 }, {
            default: vue.withCtx(() => [
              (vue.openBlock(), vue.createBlock(vue.Teleport, {
                to: props.wrapper,
                disabled: !props.wrapper
              }, [
                vue.createVNode(vue.unref(resizeObserver), { onResize: vue.unref(onPopupResize) }, {
                  default: vue.withCtx(() => [
                    sholdUmMount.value ? (vue.openBlock(), vue.createElementBlock(
                      "div",
                      vue.mergeProps({
                        key: 0,
                        ref_key: "popupRef",
                        ref: popupRef,
                        class: ["o-popup", [
                          `o-popup-pos-${popPosition.value}`,
                          {
                            "out-view": props.hideWhenTargetInvisible && !isTargetInViewport.value,
                            animating: isAnimating.value
                          }
                        ]],
                        style: popStyle
                      }, _ctx.$attrs, {
                        onMouseenter: onPopupHoverIn,
                        onMouseleave: onPopupHoverOut
                      }),
                      [
                        vue.createVNode(vue.Transition, {
                          name: props.transition,
                          appear: true,
                          onBeforeEnter: handleTransitionStart,
                          onAfterEnter: handleTransitionEnd,
                          onBeforeLeave: handleTransitionStart,
                          onAfterLeave: handleTransitionEnd,
                          persisted: ""
                        }, {
                          default: vue.withCtx(() => [
                            vue.withDirectives(vue.createElementVNode(
                              "div",
                              {
                                class: vue.normalizeClass(["o-popup-wrap", props.wrapClass]),
                                style: vue.normalizeStyle(wrapStyle.value)
                              },
                              [
                                vue.createElementVNode(
                                  "div",
                                  {
                                    class: vue.normalizeClass(["o-popup-body", props.bodyClass])
                                  },
                                  [
                                    vue.renderSlot(_ctx.$slots, "default")
                                  ],
                                  2
                                  /* CLASS */
                                ),
                                props.anchor ? (vue.openBlock(), vue.createElementBlock(
                                  "div",
                                  {
                                    key: 0,
                                    class: vue.normalizeClass(["o-popup-anchor", props.anchorClass]),
                                    style: vue.normalizeStyle(anchorStyle)
                                  },
                                  [
                                    vue.renderSlot(_ctx.$slots, "anchor")
                                  ],
                                  6
                                  /* CLASS, STYLE */
                                )) : vue.createCommentVNode("v-if", true)
                              ],
                              6
                              /* CLASS, STYLE */
                            ), [
                              [vue.vShow, visible.value]
                            ])
                          ]),
                          _: 3
                          /* FORWARDED */
                        }, 8, ["name"])
                      ],
                      16
                      /* FULL_PROPS */
                    )) : vue.createCommentVNode("v-if", true)
                  ]),
                  _: 3
                  /* FORWARDED */
                }, 8, ["onResize"])
              ], 8, ["to", "disabled"]))
            ]),
            _: 3
            /* FORWARDED */
          })) : vue.createCommentVNode("v-if", true)
        ],
        64
        /* STABLE_FRAGMENT */
      );
    };
  }
});
module.exports = _sfc_main;
