type NavigationListener = (loading: boolean) => void; let listeners = new Set(); let loading = false; function notify() { listeners.forEach((listener) => listener(loading)); } export function subscribeNavigationLoading(listener: NavigationListener) { listeners.add(listener); listener(loading); return () => { listeners.delete(listener); }; } export function startNavigation() { if (loading) return; loading = true; notify(); } export function stopNavigation() { if (!loading) return; loading = false; notify(); } export function isNavigationLoading() { return loading; } export function isInternalNavigationClick( event: MouseEvent, anchor: HTMLAnchorElement ): boolean { if (event.defaultPrevented) return false; if (event.button !== 0) return false; if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return false; if (anchor.target === "_blank") return false; if (anchor.hasAttribute("download")) return false; const href = anchor.getAttribute("href"); if ( !href || href.startsWith("#") || href.startsWith("mailto:") || href.startsWith("tel:") || href.startsWith("javascript:") ) { return false; } try { const url = new URL(href, window.location.href); if (url.origin !== window.location.origin) return false; if ( url.pathname === window.location.pathname && url.search === window.location.search && !url.hash ) { return false; } return true; } catch { return false; } }