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