Browse Source

AutoFocus

master
Dejvino 11 months ago
parent
commit
9edf9777a0
3 changed files with 36 additions and 16 deletions
  1. +30
    -10
      src/app/FocusedElement.tsx
  2. +3
    -1
      src/app/components/JobCard.tsx
  3. +3
    -5
      src/app/components/TagCloud.tsx

+ 30
- 10
src/app/FocusedElement.tsx View File

@@ -1,4 +1,4 @@
import { useState, useRef, useEffect } from "react";
import { useState, useRef, useEffect, useCallback } from "react";

const focusUrlParamName = 'focus'
const focusChangedEventName = "focus-changed"
@@ -16,31 +16,51 @@ function triggerElementFocused(elementKey?: string) {
window.dispatchEvent(focusChangeEvent)
}

export function useFocusedElement(elementKey: string) {
export function useFocusedElement<ElementType extends HTMLElement>(elementKey: string) {
const [isFocusedElement, setFocusedElement] = useState(false)
const focusedClass = isFocusedElement ? focusedElementClassName : ''
const elementRef = useRef<HTMLSpanElement>(null)
const elementRef = useRef<ElementType>(null)

function focusElement() {
const focusElement = useCallback(() => {
triggerElementFocused(isFocusedElement ? undefined : elementKey)
}
}, [isFocusedElement, elementKey])

useEffect(() => {
function getFocusedState() {
function updateFocusedState() {
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)
updateFocusedState()
addEventListener(focusChangedEventName, updateFocusedState)
return () => {
removeEventListener(focusChangedEventName, getFocusedState)
removeEventListener(focusChangedEventName, updateFocusedState)
}
}, [elementKey, setFocusedElement])
}, [elementKey, setFocusedElement, focusElement])

isFocusedElement && elementRef.current?.scrollIntoView()

return {isFocusedElement, focusedClass, elementRef, focusElement}
}

export function useAutoFocus<ElementType extends HTMLElement>(elementKey: string) {
const {elementRef, focusedClass, focusElement} = useFocusedElement<ElementType>(elementKey);

useEffect(() => {
let cleanup = () => {}
if (elementRef.current) {
const elem = elementRef.current
elem.onclick = focusElement
const classNameBackup = elem.className
elem.className += ' ' + focusedClass
cleanup = () => {
elem.className = classNameBackup
}
}
return cleanup
}, [elementRef, focusedClass, focusElement])

return elementRef
}

+ 3
- 1
src/app/components/JobCard.tsx View File

@@ -1,5 +1,6 @@
import React from 'react';
import Card from 'react-bootstrap/Card';
import { useAutoFocus, useFocusedElement } from '../FocusedElement';

export type Props = {
heading?: string,
@@ -10,8 +11,9 @@ export type Props = {
};

export default function JobCard(props: Props) {
const focusRef = useAutoFocus<HTMLDivElement>([props.position, props.company].join(', '))
return (
<Card className='job-card'>
<Card ref={focusRef} className='job-card'>
{props.heading && (
<Card.Header>{props.heading}</Card.Header>
)}


+ 3
- 5
src/app/components/TagCloud.tsx View File

@@ -1,6 +1,6 @@
import React, { useEffect, useRef, useState } from 'react';
import Container from 'react-bootstrap/Container';
import { useFocusedElement } from '../FocusedElement';
import { useAutoFocus, useFocusedElement } from '../FocusedElement';

export type Props = {
title: string,
@@ -11,11 +11,9 @@ export type Props = {

function Tag(props: {text: string}) {
const tagKey = 'tag_' + props.text;
const {elementRef, focusedClass, focusElement} = useFocusedElement(tagKey)
const elementRef = useAutoFocus(tagKey)
return (
<span ref={elementRef}
onClick={focusElement}
className={`badge text-bg-light ${focusedClass}`}>{props.text}</span>
<span ref={elementRef} className='badge text-bg-light'>{props.text}</span>
)
}



Loading…
Cancel
Save