Исправление зависаний (в некоторых случаях) всплывающих подсказок
This commit is contained in:
		
							
								
								
									
										125
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								index.js
									
									
									
									
									
								
							@@ -10,6 +10,18 @@ const attributeToOption = (attribute) => {
 | 
			
		||||
 | 
			
		||||
const isTouchDevice = () => 'ontouchstart' in window || navigator.maxTouchPoints > 0;
 | 
			
		||||
 | 
			
		||||
let visibilityListenerRegistered = false;
 | 
			
		||||
const handleVisibilityChange = () => {
 | 
			
		||||
    if (document.hidden) {
 | 
			
		||||
        // Скрываем все активные всплывающие подсказки
 | 
			
		||||
        for (const $tooltip of document.querySelectorAll('.tooltip')) {
 | 
			
		||||
            if ($tooltip._reference?._tooltip?.isVisible) {
 | 
			
		||||
                $tooltip._reference._tooltip.hide({ immediately: true });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const createTooltip = ($el, content, options) => {
 | 
			
		||||
    options = {
 | 
			
		||||
        animation: [
 | 
			
		||||
@@ -152,6 +164,10 @@ export const createTooltip = ($el, content, options) => {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            clearTimeout(showTimeout);
 | 
			
		||||
            clearTimeout(hideTimeout);
 | 
			
		||||
            cancelAnimationFrame(rafId);
 | 
			
		||||
 | 
			
		||||
            $el._tooltip.$tooltip?.remove();
 | 
			
		||||
 | 
			
		||||
            // Вызываем autoUpdateCleanup только если всплывающая подсказка была видна (иначе вызывать её не имеет смысла)
 | 
			
		||||
@@ -282,43 +298,37 @@ export const createTooltip = ($el, content, options) => {
 | 
			
		||||
 | 
			
		||||
        showTimeout = setTimeout(
 | 
			
		||||
            async () => {
 | 
			
		||||
                if (!$el._tooltip.isVisible) {
 | 
			
		||||
                    (options.appendTo === 'parent' ? $el.parentElement : options.appendTo).append(
 | 
			
		||||
                        $el._tooltip.$tooltip,
 | 
			
		||||
                    );
 | 
			
		||||
                    $el._tooltip.isVisible = true;
 | 
			
		||||
                    $el._tooltip.autoUpdateCleanup = autoUpdate(
 | 
			
		||||
                        $el,
 | 
			
		||||
                        $el._tooltip.$tooltip,
 | 
			
		||||
                        $el._tooltip.updatePosition,
 | 
			
		||||
                    );
 | 
			
		||||
                // Проверяем $el._tooltip на сущестование
 | 
			
		||||
                if (!$el._tooltip || $el._tooltip.isVisible) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                    if (
 | 
			
		||||
                        options.hideOnClick &&
 | 
			
		||||
                        (options.trigger.includes('click') || options.trigger.includes('manual'))
 | 
			
		||||
                    ) {
 | 
			
		||||
                        document.body.addEventListener('click', $el._tooltip.hideOnClickListener);
 | 
			
		||||
                        listeners.push({
 | 
			
		||||
                            el: document.body,
 | 
			
		||||
                            event: 'click',
 | 
			
		||||
                            listener: $el._tooltip.hideOnClickListener,
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                (options.appendTo === 'parent' ? $el.parentElement : options.appendTo).append($el._tooltip.$tooltip);
 | 
			
		||||
                $el._tooltip.isVisible = true;
 | 
			
		||||
                $el._tooltip.autoUpdateCleanup = autoUpdate($el, $el._tooltip.$tooltip, $el._tooltip.updatePosition);
 | 
			
		||||
 | 
			
		||||
                    if (options.onShow) {
 | 
			
		||||
                        options.onShow($el._tooltip);
 | 
			
		||||
                    }
 | 
			
		||||
                if (options.hideOnClick && (options.trigger.includes('click') || options.trigger.includes('manual'))) {
 | 
			
		||||
                    document.body.addEventListener('click', $el._tooltip.hideOnClickListener);
 | 
			
		||||
                    listeners.push({
 | 
			
		||||
                        el: document.body,
 | 
			
		||||
                        event: 'click',
 | 
			
		||||
                        listener: $el._tooltip.hideOnClickListener,
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                    try {
 | 
			
		||||
                        await $el._tooltip.$tooltip.querySelector('.tooltip__root').animate(options.animation[0], {
 | 
			
		||||
                            duration: immediately ? 0 : options.duration[0],
 | 
			
		||||
                            easing: options.easing[0],
 | 
			
		||||
                        }).finished;
 | 
			
		||||
                    } catch {} // eslint-disable-line no-empty
 | 
			
		||||
                if (options.onShow) {
 | 
			
		||||
                    options.onShow($el._tooltip);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                    if (options.onShown) {
 | 
			
		||||
                        options.onShown($el._tooltip);
 | 
			
		||||
                    }
 | 
			
		||||
                try {
 | 
			
		||||
                    await $el._tooltip.$tooltip.querySelector('.tooltip__root').animate(options.animation[0], {
 | 
			
		||||
                        duration: immediately ? 0 : options.duration[0],
 | 
			
		||||
                        easing: options.easing[0],
 | 
			
		||||
                    }).finished;
 | 
			
		||||
                } catch {} // eslint-disable-line no-empty
 | 
			
		||||
 | 
			
		||||
                if (options.onShown) {
 | 
			
		||||
                    options.onShown($el._tooltip);
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            immediately ? 0 : options.delay[0],
 | 
			
		||||
@@ -329,27 +339,35 @@ export const createTooltip = ($el, content, options) => {
 | 
			
		||||
        clearTimeout(showTimeout);
 | 
			
		||||
        hideTimeout = setTimeout(
 | 
			
		||||
            async () => {
 | 
			
		||||
                if ($el._tooltip.isVisible) {
 | 
			
		||||
                    if (options.onHide) {
 | 
			
		||||
                        options.onHide($el._tooltip);
 | 
			
		||||
                    }
 | 
			
		||||
                // Проверяем $el._tooltip на сущестование
 | 
			
		||||
                if (!$el._tooltip || !$el._tooltip.isVisible) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                    try {
 | 
			
		||||
                        await $el._tooltip.$tooltip.querySelector('.tooltip__root').animate(options.animation[1], {
 | 
			
		||||
                            duration: immediately ? 0 : options.duration[1],
 | 
			
		||||
                            easing: options.easing[1],
 | 
			
		||||
                        }).finished;
 | 
			
		||||
                    } catch {} // eslint-disable-line no-empty
 | 
			
		||||
                if (options.onHide) {
 | 
			
		||||
                    options.onHide($el._tooltip);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                    if ($el._tooltip.$tooltip) {
 | 
			
		||||
                        $el._tooltip.$tooltip.remove();
 | 
			
		||||
                    }
 | 
			
		||||
                    $el._tooltip.isVisible = false;
 | 
			
		||||
                    $el._tooltip.autoUpdateCleanup();
 | 
			
		||||
                try {
 | 
			
		||||
                    await $el._tooltip.$tooltip.querySelector('.tooltip__root').animate(options.animation[1], {
 | 
			
		||||
                        duration: immediately ? 0 : options.duration[1],
 | 
			
		||||
                        easing: options.easing[1],
 | 
			
		||||
                    }).finished;
 | 
			
		||||
                } catch {} // eslint-disable-line no-empty
 | 
			
		||||
 | 
			
		||||
                    if (options.onHidden) {
 | 
			
		||||
                        options.onHidden($el._tooltip);
 | 
			
		||||
                    }
 | 
			
		||||
                // Ещё одна проверка на сущестование $el._tooltip после await
 | 
			
		||||
                if (!$el._tooltip) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ($el._tooltip.$tooltip) {
 | 
			
		||||
                    $el._tooltip.$tooltip.remove();
 | 
			
		||||
                }
 | 
			
		||||
                $el._tooltip.isVisible = false;
 | 
			
		||||
                $el._tooltip.autoUpdateCleanup();
 | 
			
		||||
 | 
			
		||||
                if (options.onHidden) {
 | 
			
		||||
                    options.onHidden($el._tooltip);
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            immediately ? 0 : options.delay[1],
 | 
			
		||||
@@ -450,4 +468,9 @@ export const createTooltip = ($el, content, options) => {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    registerListeners();
 | 
			
		||||
 | 
			
		||||
    if (!visibilityListenerRegistered) {
 | 
			
		||||
        document.addEventListener('visibilitychange', handleVisibilityChange);
 | 
			
		||||
        visibilityListenerRegistered = true;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user