123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- // Components
- import { VMenuSymbol } from "../VMenu/shared.mjs"; // Composables
- import { makeDelayProps, useDelay } from "../../composables/delay.mjs"; // Utilities
- import { computed, effectScope, inject, mergeProps, nextTick, onScopeDispose, ref, watch, watchEffect } from 'vue';
- import { bindProps, getCurrentInstance, IN_BROWSER, matchesSelector, propsFactory, refElement, unbindProps } from "../../util/index.mjs"; // Types
- export const makeActivatorProps = propsFactory({
- activator: [String, Object],
- activatorProps: {
- type: Object,
- default: () => ({})
- },
- openOnClick: {
- type: Boolean,
- default: undefined
- },
- openOnHover: Boolean,
- openOnFocus: {
- type: Boolean,
- default: undefined
- },
- closeOnContentClick: Boolean,
- ...makeDelayProps()
- }, 'VOverlay-activator');
- export function useActivator(props, _ref) {
- let {
- isActive,
- isTop
- } = _ref;
- const activatorEl = ref();
- let isHovered = false;
- let isFocused = false;
- let firstEnter = true;
- const openOnFocus = computed(() => props.openOnFocus || props.openOnFocus == null && props.openOnHover);
- const openOnClick = computed(() => props.openOnClick || props.openOnClick == null && !props.openOnHover && !openOnFocus.value);
- const {
- runOpenDelay,
- runCloseDelay
- } = useDelay(props, value => {
- if (value === (props.openOnHover && isHovered || openOnFocus.value && isFocused) && !(props.openOnHover && isActive.value && !isTop.value)) {
- if (isActive.value !== value) {
- firstEnter = true;
- }
- isActive.value = value;
- }
- });
- const availableEvents = {
- onClick: e => {
- e.stopPropagation();
- activatorEl.value = e.currentTarget || e.target;
- isActive.value = !isActive.value;
- },
- onMouseenter: e => {
- if (e.sourceCapabilities?.firesTouchEvents) return;
- isHovered = true;
- activatorEl.value = e.currentTarget || e.target;
- runOpenDelay();
- },
- onMouseleave: e => {
- isHovered = false;
- runCloseDelay();
- },
- onFocus: e => {
- if (matchesSelector(e.target, ':focus-visible') === false) return;
- isFocused = true;
- e.stopPropagation();
- activatorEl.value = e.currentTarget || e.target;
- runOpenDelay();
- },
- onBlur: e => {
- isFocused = false;
- e.stopPropagation();
- runCloseDelay();
- }
- };
- const activatorEvents = computed(() => {
- const events = {};
- if (openOnClick.value) {
- events.onClick = availableEvents.onClick;
- }
- if (props.openOnHover) {
- events.onMouseenter = availableEvents.onMouseenter;
- events.onMouseleave = availableEvents.onMouseleave;
- }
- if (openOnFocus.value) {
- events.onFocus = availableEvents.onFocus;
- events.onBlur = availableEvents.onBlur;
- }
- return events;
- });
- const contentEvents = computed(() => {
- const events = {};
- if (props.openOnHover) {
- events.onMouseenter = () => {
- isHovered = true;
- runOpenDelay();
- };
- events.onMouseleave = () => {
- isHovered = false;
- runCloseDelay();
- };
- }
- if (openOnFocus.value) {
- events.onFocusin = () => {
- isFocused = true;
- runOpenDelay();
- };
- events.onFocusout = () => {
- isFocused = false;
- runCloseDelay();
- };
- }
- if (props.closeOnContentClick) {
- const menu = inject(VMenuSymbol, null);
- events.onClick = () => {
- isActive.value = false;
- menu?.closeParents();
- };
- }
- return events;
- });
- const scrimEvents = computed(() => {
- const events = {};
- if (props.openOnHover) {
- events.onMouseenter = () => {
- if (firstEnter) {
- isHovered = true;
- firstEnter = false;
- runOpenDelay();
- }
- };
- events.onMouseleave = () => {
- isHovered = false;
- runCloseDelay();
- };
- }
- return events;
- });
- watch(isTop, val => {
- if (val && (props.openOnHover && !isHovered && (!openOnFocus.value || !isFocused) || openOnFocus.value && !isFocused && (!props.openOnHover || !isHovered))) {
- isActive.value = false;
- }
- });
- const activatorRef = ref();
- watchEffect(() => {
- if (!activatorRef.value) return;
- nextTick(() => {
- activatorEl.value = refElement(activatorRef.value);
- });
- });
- const vm = getCurrentInstance('useActivator');
- let scope;
- watch(() => !!props.activator, val => {
- if (val && IN_BROWSER) {
- scope = effectScope();
- scope.run(() => {
- _useActivator(props, vm, {
- activatorEl,
- activatorEvents
- });
- });
- } else if (scope) {
- scope.stop();
- }
- }, {
- flush: 'post',
- immediate: true
- });
- onScopeDispose(() => {
- scope?.stop();
- });
- return {
- activatorEl,
- activatorRef,
- activatorEvents,
- contentEvents,
- scrimEvents
- };
- }
- function _useActivator(props, vm, _ref2) {
- let {
- activatorEl,
- activatorEvents
- } = _ref2;
- 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() {
- let el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getActivator();
- let _props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : props.activatorProps;
- if (!el) return;
- bindProps(el, mergeProps(activatorEvents.value, _props));
- }
- function unbindActivatorProps() {
- let el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getActivator();
- let _props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : props.activatorProps;
- if (!el) return;
- unbindProps(el, mergeProps(activatorEvents.value, _props));
- }
- function getActivator() {
- let selector = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : props.activator;
- let activator;
- if (selector) {
- if (selector === 'parent') {
- let el = vm?.proxy?.$el?.parentNode;
- while (el.hasAttribute('data-no-activator')) {
- el = el.parentNode;
- }
- activator = el;
- } else if (typeof selector === 'string') {
- // Selector
- activator = document.querySelector(selector);
- } else if ('$el' in selector) {
- // Component (ref)
- activator = selector.$el;
- } else {
- // HTMLElement | Element
- activator = selector;
- }
- }
- // The activator should only be a valid element (Ignore comments and text nodes)
- activatorEl.value = activator?.nodeType === Node.ELEMENT_NODE ? activator : null;
- return activatorEl.value;
- }
- }
- //# sourceMappingURL=useActivator.mjs.map
|