import { useState, useCallback, useEffect, useRef, createRef } from 'react';
interface RadioProps {
tabIndex: number;
ref: React.RefObject<HTMLLabelElement>;
}
interface RadioGroupProps {
onKeyDown: (e: React.KeyboardEvent) => void;
ref: React.RefObject<HTMLDivElement>;
}
export function useRadioGroup(selectedIndex: number | null = null) {
const [focusedIndex, setFocusedIndex] = useState<number>(-1);
const groupRef = useRef<HTMLDivElement>(null);
const radioRefs = useRef<React.RefObject<HTMLLabelElement>[]>([]);
const getRadioCount = useCallback(() => {
return groupRef.current?.querySelectorAll('[role="radio"]').length || 0;
}, []);
useEffect(() => {
if (groupRef.current) {
const count = getRadioCount();
radioRefs.current = Array(count)
.fill(null)
.map((_, i) => radioRefs.current[i] || createRef<HTMLLabelElement>());
}
}, [getRadioCount]);
const onKeyDown = useCallback(
(e: React.KeyboardEvent) => {
const count = getRadioCount();
if (count === 0) return;
let newIndex = focusedIndex;
const startIndex = selectedIndex !== null ? selectedIndex : 0;
switch (e.key) {
case 'ArrowRight':
case 'ArrowDown':
e.preventDefault();
if (focusedIndex === -1) {
newIndex = (startIndex + 1) % count;
} else {
newIndex = (focusedIndex + 1) % count;
}
break;
case 'ArrowLeft':
case 'ArrowUp':
e.preventDefault();
if (focusedIndex === -1) {
newIndex = (startIndex - 1 + count) % count;
} else {
newIndex = (focusedIndex - 1 + count) % count;
}
break;
case ' ':
e.preventDefault();
if (focusedIndex !== -1) {
const element = radioRefs.current[focusedIndex]?.current;
if (element) {
element.click();
}
}
return;
}
if (newIndex !== focusedIndex) {
setFocusedIndex(newIndex);
const element = radioRefs.current[newIndex]?.current;
if (element) {
element.focus();
}
}
},
[focusedIndex, selectedIndex, getRadioCount]
);
const getRadioProps = useCallback(
(index: number): RadioProps => {
if (!radioRefs.current[index]) {
radioRefs.current[index] = createRef<HTMLLabelElement>();
}
return {
tabIndex: focusedIndex === -1
? (selectedIndex === null ? (index === 0 ? 0 : -1) : (index === selectedIndex ? 0 : -1))
: (index === focusedIndex ? 0 : -1),
ref: radioRefs.current[index],
};
},
[focusedIndex, selectedIndex]
);
const getRadioGroupProps = useCallback((): RadioGroupProps => {
return {
onKeyDown,
ref: groupRef,
};
}, [onKeyDown]);
return {
focusedIndex,
getRadioGroupProps,
getRadioProps,
} as const;
}
답글 남기기
댓글을 달기 위해서는 로그인해야합니다.