11import clsx from 'clsx' ;
22import { GessoComponent } from 'gesso' ;
3- import { useEffect , useId , useRef , useState } from 'react' ;
3+ import { KeyboardEvent , createRef , useId , useMemo , useState } from 'react' ;
44import styles from './accordion.module.css' ;
5- import stylesAccordionItem from './accordion-item.module.css' ;
65import getCssVar from '../../06-utility/getCssVar' ;
76import { KEYCODE } from '../../00-config/constants' ;
87import AccordionItem , { AccordionItemProps } from './AccordionItem' ;
@@ -22,13 +21,17 @@ function Accordion({
2221 modifierClasses,
2322} : AccordionProps ) : JSX . Element {
2423 const accordionId = useId ( ) ;
25- const accordionRef = useRef ( null ) ;
2624 const [ accordionItemsStatus , setAccordionItemsStatus ] = useState (
2725 accordionItems . map ( ( item , index ) => ( {
2826 ...item ,
2927 id : `${ accordionId } -${ index } ` ,
3028 } ) ) ,
3129 ) ;
30+ const accordionItemRefs = useMemo ( ( ) => {
31+ const refs : { [ key : string ] : React . RefObject < HTMLButtonElement > } = { } ;
32+ accordionItemsStatus . forEach ( item => ( refs [ item . id ] = createRef ( ) ) ) ;
33+ return refs ;
34+ } , [ accordionItemsStatus ] ) ;
3235
3336 const openAccordionItem = ( items : AccordionItemProps [ ] , index : number ) => {
3437 return items . with ( index , {
@@ -65,23 +68,19 @@ function Accordion({
6568 } ;
6669
6770 const handleKeydown = ( event : KeyboardEvent ) => {
68- const currentTarget = event . target as HTMLElement ;
69- const accordion = accordionRef . current as HTMLElement | null ;
70- const ACCORDION_TOGGLE_CLASS = stylesAccordionItem . toggle ;
71+ const currentTarget = event . target as HTMLButtonElement ;
7172
7273 // Create the array of toggle elements for the accordion group
73- const triggers = Array . prototype . slice . call (
74- accordion ? accordion . querySelectorAll ( `.${ ACCORDION_TOGGLE_CLASS } ` ) : [ ] ,
75- ) ;
74+ const triggers = Object . values ( accordionItemRefs ) . map ( ref => ref . current ) ;
7675
7776 // Is this coming from an accordion header?
78- if ( currentTarget . tagName === 'BUTTON' ) {
77+ if ( triggers && currentTarget . tagName === 'BUTTON' ) {
7978 // Up/ Down arrow and Control + Page Up/ Page Down keyboard operations
8079 if (
8180 event . code === KEYCODE . UP ||
8281 event . code === KEYCODE . DOWN ||
83- event . code === KEYCODE . PAGEDOWN ||
84- event . code === KEYCODE . UP
82+ event . code === KEYCODE . PAGEUP ||
83+ event . code === KEYCODE . PAGEDOWN
8584 ) {
8685 const index = triggers . indexOf ( currentTarget ) ;
8786 let direction ;
@@ -92,40 +91,33 @@ function Accordion({
9291 }
9392 const triggerLength = triggers . length ;
9493 const newIndex = ( index + triggerLength + direction ) % triggerLength ;
95- triggers [ newIndex ] . focus ( ) ;
94+ triggers [ newIndex ] ? .focus ( ) ;
9695 event . preventDefault ( ) ;
9796 } else if ( event . code === KEYCODE . HOME || event . code === KEYCODE . END ) {
9897 switch ( event . code ) {
9998 // Go to first accordion
10099 case KEYCODE . HOME :
101- triggers [ 0 ] . focus ( ) ;
100+ triggers [ 0 ] ? .focus ( ) ;
102101 break ;
103102 // Go to last accordion
104103 case KEYCODE . END :
105- triggers [ triggers . length - 1 ] . focus ( ) ;
104+ triggers [ triggers . length - 1 ] ? .focus ( ) ;
106105 break ;
107106 default :
108- triggers [ 0 ] . focus ( ) ;
107+ triggers [ 0 ] ? .focus ( ) ;
109108 break ;
110109 }
111110 event . preventDefault ( ) ;
112111 }
113112 }
114113 } ;
115114
116- useEffect ( ( ) => {
117- const accordion = accordionRef . current as HTMLElement | null ;
118- if ( accordion ) {
119- accordion . addEventListener ( 'keydown' , handleKeydown ) ;
120- }
121- } ) ;
122-
123115 return (
124116 < >
125117 < div
126- ref = { accordionRef }
127118 className = { clsx ( styles . accordion , modifierClasses ) }
128119 id = { accordionId }
120+ onKeyDown = { handleKeydown }
129121 >
130122 < div className = { styles . content } >
131123 { accordionItemsStatus . map ( item => {
@@ -134,6 +126,7 @@ function Accordion({
134126 key = { item . id }
135127 { ...item }
136128 accordionSpeed = { accordionSpeed }
129+ toggleRef = { accordionItemRefs [ item . id ] }
137130 handleClick = { ( ) => handleClick ( item . id , item . isOpen ) }
138131 />
139132 ) ;
0 commit comments