Extracted generic FocusedElement hook
This commit is contained in:
parent
df2204cb45
commit
6dff62d61c
42
src/app/FocusedElement.tsx
Normal file
42
src/app/FocusedElement.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
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}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import Container from 'react-bootstrap/Container';
|
||||
import { useFocusedElement } from '../FocusedElement';
|
||||
|
||||
export type Props = {
|
||||
title: string,
|
||||
@ -8,47 +9,12 @@ export type Props = {
|
||||
style?: 'primary' | 'light'
|
||||
}
|
||||
|
||||
const focusChangedEventName = "focus-changed"
|
||||
|
||||
function useFocusedElement(elementKey: string) {
|
||||
const [isFocusedElement, setFocusedElement] = useState(false);
|
||||
const focusedClass = isFocusedElement ? 'focused-element' : ''
|
||||
const elementRef = useRef<HTMLSpanElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
function getFocusedState() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
const focusedElement = params.get('focus')
|
||||
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}
|
||||
}
|
||||
|
||||
function setFocusedElement(elementKey: string) {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set('focus', elementKey);
|
||||
const focusChangeEvent = new Event(focusChangedEventName);
|
||||
history.pushState({}, "", url);
|
||||
window.dispatchEvent(focusChangeEvent)
|
||||
}
|
||||
|
||||
function Tag(props: {text: string}) {
|
||||
const tagKey = 'tag_' + props.text;
|
||||
const {focusedClass, elementRef} = useFocusedElement(tagKey)
|
||||
const {elementRef, focusedClass, focusElement} = useFocusedElement(tagKey)
|
||||
return (
|
||||
<span ref={elementRef}
|
||||
onClick={() => setFocusedElement(tagKey)}
|
||||
onClick={focusElement}
|
||||
className={`badge text-bg-light ${focusedClass}`}>{props.text}</span>
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user