import { computed, effectScope, nextTick, onScopeDispose, ref, watch, watchEffect } from "vue";
import {
  IN_BROWSER,
  SUPPORTS_FOCUS_VISIBLE,
  SUPPORTS_TOUCH,
  getCurrentInstance,
  isComponentInstance,
  propsFactory,
  querySelector
} from "@veno-ui/utils";
import { makeDelayProps, useDelay } from "../delay";
const makeActivatorProps = propsFactory({
  /**
   * @zh 激活器
   */
  activator: [String, Object],
  /**
   * @zh 激活器属性
   */
  activatorProps: {
    type: Object,
    default: () => ({})
  },
  /**
   * @zh 点击时打开
   */
  openOnClick: {
    type: Boolean,
    default: void 0
  },
  /**
   * @zh 悬停时打开
   */
  openOnHover: Boolean,
  /**
   * @zh 获取焦点时打开
   */
  openOnFocus: {
    type: Boolean,
    default: void 0
  },
  ...makeDelayProps()
}, "activator");
function useActivator(props, { isActive }) {
  const activatedPosition = ref();
  const activatorEl = ref();
  let isHovered = false;
  let isFocused = false;
  const openOnFocus = computed(() => {
    return props.openOnFocus || props.openOnFocus == null && props.openOnHover;
  });
  const openOnClick = computed(() => {
    return props.openOnClick || props.openOnClick == null && !props.openOnHover && !openOnFocus.value;
  });
  const { runOpenDelay, runCloseDelay } = useDelay(props, (value) => {
    const hovered = props.openOnHover && isHovered;
    const focused = openOnFocus.value && isFocused;
    if (value === (hovered || focused)) {
      isActive.value = value;
    }
  });
  function onEnter(e) {
    activatorEl.value = e.currentTarget || e.target;
    isHovered = true;
    runOpenDelay();
  }
  function onLeave(_) {
    isHovered = false;
    runCloseDelay();
  }
  const availableEvents = {
    click: (e) => {
      e.stopPropagation();
      activatedPosition.value = { left: e.clientX, top: e.clientY };
      activatorEl.value = e.currentTarget || e.target;
      isActive.value = !isActive.value;
    },
    mouseenter: onEnter,
    mouseleave: onLeave,
    touchstartPassive: onEnter,
    touchend: onLeave,
    contextmenu: (e) => e.preventDefault(),
    focus: (e) => {
      if (SUPPORTS_FOCUS_VISIBLE && !e.target.matches(":focus-visible"))
        return;
      e.stopPropagation();
      activatorEl.value = e.currentTarget || e.target;
      isFocused = true;
      runOpenDelay();
    },
    blur: (e) => {
      e.stopPropagation();
      isFocused = false;
      runCloseDelay();
    }
  };
  const activatorEvents = computed(() => {
    const events = {};
    if (openOnClick.value) {
      events.click = availableEvents.click;
    }
    if (props.openOnHover) {
      if (SUPPORTS_TOUCH) {
        events.touchstartPassive = availableEvents.touchstartPassive;
        events.contextmenu = availableEvents.contextmenu;
        events.touchend = availableEvents.touchend;
      } else {
        events.mouseenter = availableEvents.mouseenter;
        events.mouseleave = availableEvents.mouseleave;
      }
    }
    if (openOnFocus.value) {
      events.focus = availableEvents.focus;
      events.blur = availableEvents.blur;
    }
    return events;
  });
  const contentEvents = computed(() => {
    const events = {};
    if (props.openOnHover) {
      if (SUPPORTS_TOUCH) {
        events.touchstartPassive = (_) => isHovered = true;
        events.contextmenu = availableEvents.contextmenu;
        events.touchend = availableEvents.touchend;
      } else {
        events.mouseenter = (_) => isHovered = true;
        events.mouseleave = availableEvents.mouseleave;
      }
    }
    return events;
  });
  const activatorRef = ref();
  watchEffect(() => {
    if (!activatorRef.value)
      return;
    nextTick(() => {
      const activator = activatorRef.value;
      activatorEl.value = isComponentInstance(activator) ? activator.$el : activator;
    });
  });
  const state = {
    activatedPosition,
    activatorEl,
    activatorRef,
    activatorEvents,
    contentEvents
  };
  let scope;
  watch(() => !!props.activator, (val) => {
    if (val && IN_BROWSER) {
      scope = effectScope();
      scope.run(() => useActivatorInScope(props, state));
    } else {
      scope?.stop();
    }
  }, { flush: "post", immediate: true });
  return state;
}
function useActivatorInScope(props, { activatorEl, activatorEvents }) {
  watch(() => props.activator, (val, oldVal) => {
    if (oldVal && val !== oldVal) {
      const activator = getActivator(oldVal);
      activator && unbindActivatorProps(activator);
    }
    if (val) {
      nextTick(() => bindActivatorProps());
    }
  }, { immediate: true });
  watch(() => props.activatorProps, () => bindActivatorProps());
  onScopeDispose(unbindActivatorProps);
  function bindActivatorProps(el = getActivator(), activatorProps = props.activatorProps) {
    if (!el)
      return;
    Object.entries(activatorEvents.value).forEach(([name, cb]) => {
      el.addEventListener(name, cb);
    });
    Object.keys(activatorProps).forEach((k) => {
      if (activatorProps[k] == null) {
        el.removeAttribute(k);
      } else {
        el.setAttribute(k, activatorProps[k]);
      }
    });
  }
  function unbindActivatorProps(el = getActivator(), activatorProps = props.activatorProps) {
    if (!el)
      return;
    Object.entries(activatorEvents.value).forEach(([name, cb]) => {
      el.removeEventListener(name, cb);
    });
    Object.keys(activatorProps).forEach((k) => {
      el.removeAttribute(k);
    });
  }
  const vm = getCurrentInstance("useActivator");
  function getActivator(selector = props.activator) {
    if (selector) {
      activatorEl.value = querySelector(selector, vm);
    }
    return activatorEl.value;
  }
}
export {
  makeActivatorProps,
  useActivator
};
//# sourceMappingURL=index.mjs.map
