Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | 1x 71x 71x 71x 71x 71x 71x 71x 28x 71x 53x 28x 71x 71x 19x 71x 4x 4x 4x 71x | import React, { KeyboardEventHandler, MouseEventHandler, PropsWithChildren, useEffect, useId, useRef, useState } from 'react';
import styles from './Expandable.module.css';
import getString from '../../strings/getString';
// let expandableCounter = 0; // unique ID suffix for aria components
export type ExpandablePropsType = {
startExpanded?: boolean;
expandPrompt?: string;
collapsePrompt?: string;
}
const Expandable: React.FC<PropsWithChildren<ExpandablePropsType>> = ({
startExpanded = false,
expandPrompt,
collapsePrompt,
children
}) => {
const idDiscriminator = useId();
const contentRef = useRef(null);
const buttonRef = useRef(null);
const effectiveExpandPrompt = expandPrompt || getString('expandable-component-default-expand-prompt');
const effectiveCollapsePrompt = collapsePrompt || getString('expandable-component-default-collapse-prompt');
const [isExpanded, setExpanded] = useState(startExpanded);
useEffect(() => {
setExpanded(() => startExpanded);
}, [startExpanded])
useEffect(() => {
if(isExpanded) { contentRef.current.focus(); }
else { buttonRef.current.focus(); }
})
const toggleExpanded = () => setExpanded(prevExpanded => !prevExpanded);
const handleClick: MouseEventHandler = (e) => {
toggleExpanded();
}
const handleKeyDown: KeyboardEventHandler = (e) => {
Eif(['Enter', ' '].includes(e.key)) {
e.preventDefault();
toggleExpanded();
}
}
return (
<div className={styles.container}>
<div
ref={contentRef}
tabIndex={isExpanded ? 0 : 1}
data-testid={`expandable-section-${idDiscriminator}`}
id={`expandable-section-${idDiscriminator}`}
className={ styles.expandableBlock }
hidden={!isExpanded}
>
{children}
</div>
<button
ref={buttonRef}
tabIndex={0}
className={styles.toggle}
onClick={handleClick}
onKeyDown={handleKeyDown}
aria-expanded={isExpanded}
aria-controls={`expandable-section-toggle-${idDiscriminator}`}
>
{ isExpanded ? effectiveCollapsePrompt : effectiveExpandPrompt }
</button>
</div>
)
}
export default Expandable; |