43 lines
1.5 KiB
TypeScript
43 lines
1.5 KiB
TypeScript
|
import { useState, useRef, useEffect } from "react";
|
||
|
|
||
|
const focusUrlParamName = 'focus'
|
||
|
const focusChangedEventName = "focus-changed"
|
||
|
const focusedElementClassName = 'focused-element'
|
||
|
|
||
|
function triggerElementFocused(elementKey: string) {
|
||
|
const url = new URL(window.location.href);
|
||
|
url.searchParams.set(focusUrlParamName, elementKey);
|
||
|
const focusChangeEvent = new Event(focusChangedEventName);
|
||
|
history.pushState({}, "", url);
|
||
|
window.dispatchEvent(focusChangeEvent)
|
||
|
}
|
||
|
|
||
|
export function useFocusedElement(elementKey: string) {
|
||
|
const [isFocusedElement, setFocusedElement] = useState(false);
|
||
|
const focusedClass = isFocusedElement ? focusedElementClassName : ''
|
||
|
const elementRef = useRef<HTMLSpanElement>(null)
|
||
|
|
||
|
function focusElement() {
|
||
|
triggerElementFocused(elementKey)
|
||
|
}
|
||
|
|
||
|
useEffect(() => {
|
||
|
function getFocusedState() {
|
||
|
const params = new URLSearchParams(window.location.search)
|
||
|
const focusedElement = params.get(focusUrlParamName)
|
||
|
const focused: boolean = focusedElement && focusedElement == elementKey || false
|
||
|
setFocusedElement(focused)
|
||
|
}
|
||
|
|
||
|
getFocusedState()
|
||
|
addEventListener(focusChangedEventName, getFocusedState)
|
||
|
return () => {
|
||
|
removeEventListener(focusChangedEventName, getFocusedState)
|
||
|
}
|
||
|
}, [elementKey, setFocusedElement])
|
||
|
|
||
|
isFocusedElement && elementRef.current?.scrollIntoView()
|
||
|
|
||
|
return {isFocusedElement, focusedClass, elementRef, focusElement}
|
||
|
}
|