import { useEffect, type RefObject } from 'react' import { isUrlValue, normalizeUrl, openExternalUrl } from '../utils/url' const CODE_CONTEXT_SELECTOR = '[data-content-type="codeBlock"], pre, code' function hasFollowModifier(event: KeyboardEvent | MouseEvent) { return event.metaKey || event.ctrlKey } function isInsideCodeContext(target: HTMLElement) { return !!target.closest(CODE_CONTEXT_SELECTOR) } function resolveWikilinkTarget(target: HTMLElement) { return target.closest('.wikilink[data-target]')?.dataset.target ?? null } function resolveUrlTarget(target: HTMLElement) { const href = target.closest('a[href]')?.getAttribute('href')?.trim() if (!href || !isUrlValue(href)) return null return normalizeUrl(href) } function setFollowLinksActive(container: HTMLElement, active: boolean) { if (active) container.setAttribute('data-follow-links', '') else container.removeAttribute('data-follow-links') } export function useEditorLinkActivation( containerRef: RefObject, onNavigateWikilink: (target: string) => void, ) { useEffect(() => { const container = containerRef.current if (!container) return const resetModifierState = () => setFollowLinksActive(container, false) const handleModifierChange = (event: KeyboardEvent) => { setFollowLinksActive(container, hasFollowModifier(event)) } const handleVisibilityChange = () => { if (document.visibilityState !== 'visible') resetModifierState() } const handleClick = (event: MouseEvent) => { if (!hasFollowModifier(event)) return if (!(event.target instanceof HTMLElement) || isInsideCodeContext(event.target)) return const wikilinkTarget = resolveWikilinkTarget(event.target) if (wikilinkTarget) { event.preventDefault() event.stopPropagation() onNavigateWikilink(wikilinkTarget) return } const urlTarget = resolveUrlTarget(event.target) if (!urlTarget) return event.preventDefault() event.stopPropagation() openExternalUrl(urlTarget).catch(() => {}) } container.addEventListener('click', handleClick, true) window.addEventListener('keydown', handleModifierChange) window.addEventListener('keyup', handleModifierChange) window.addEventListener('blur', resetModifierState) document.addEventListener('visibilitychange', handleVisibilityChange) return () => { container.removeEventListener('click', handleClick, true) window.removeEventListener('keydown', handleModifierChange) window.removeEventListener('keyup', handleModifierChange) window.removeEventListener('blur', resetModifierState) document.removeEventListener('visibilitychange', handleVisibilityChange) resetModifierState() } }, [containerRef, onNavigateWikilink]) }