chore: use React.useId for a11y (#33402)

This commit is contained in:
Pavel Feldman 2024-11-01 13:38:16 -07:00 committed by GitHub
parent c76f004ec3
commit 80bd246543
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 14 additions and 5 deletions

View File

@ -30,10 +30,12 @@ export const Chip: React.FC<{
dataTestId?: string,
targetRef?: React.RefObject<HTMLDivElement>,
}> = ({ header, expanded, setExpanded, children, noInsets, dataTestId, targetRef }) => {
const id = React.useId();
return <div className='chip' data-testid={dataTestId} ref={targetRef}>
<div
role='button'
aria-expanded={!!expanded}
aria-controls={id}
className={clsx('chip-header', setExpanded && ' expanded-' + expanded)}
onClick={() => setExpanded?.(!expanded)}
title={typeof header === 'string' ? header : undefined}>
@ -41,7 +43,7 @@ export const Chip: React.FC<{
{setExpanded && !expanded && icons.rightArrow()}
{header}
</div>
{(!setExpanded || expanded) && <div role='region' className={clsx('chip-body', noInsets && 'chip-body-no-insets')}>{children}</div>}
{(!setExpanded || expanded) && <div id={id} role='region' className={clsx('chip-body', noInsets && 'chip-body-no-insets')}>{children}</div>}
</div>;
};

View File

@ -24,14 +24,20 @@ export const Expandable: React.FunctionComponent<React.PropsWithChildren<{
expanded: boolean,
expandOnTitleClick?: boolean,
}>> = ({ title, children, setExpanded, expanded, expandOnTitleClick }) => {
const id = React.useId();
return <div className={clsx('expandable', expanded && 'expanded')}>
<div className='expandable-title' onClick={() => expandOnTitleClick && setExpanded(!expanded)}>
<div
role='button'
aria-expanded={expanded}
aria-controls={id}
className='expandable-title'
onClick={() => expandOnTitleClick && setExpanded(!expanded)}>
<div
className={clsx('codicon', expanded ? 'codicon-chevron-down' : 'codicon-chevron-right')}
style={{ cursor: 'pointer', color: 'var(--vscode-foreground)', marginLeft: '5px' }}
onClick={() => !expandOnTitleClick && setExpanded(!expanded)} />
{title}
</div>
{ expanded && <div style={{ marginLeft: 25 }}>{children}</div> }
{ expanded && <div id={id} role='region' style={{ marginLeft: 25 }}>{children}</div> }
</div>;
};

View File

@ -231,6 +231,7 @@ export function TreeItemHeader<T extends TreeItem>({
icon,
isKeyboardNavigation,
setIsKeyboardNavigation }: TreeItemHeaderProps<T>) {
const groupId = React.useId();
const itemRef = React.useRef(null);
React.useEffect(() => {
@ -251,7 +252,7 @@ export function TreeItemHeader<T extends TreeItem>({
const titled = title?.(item);
const iconed = icon?.(item) || 'codicon-blank';
return <div ref={itemRef} role='treeitem' aria-selected={item === selectedItem} aria-expanded={expanded} title={titled} className='vbox' style={{ flex: 'none' }}>
return <div ref={itemRef} role='treeitem' aria-selected={item === selectedItem} aria-expanded={expanded} aria-controls={groupId} title={titled} className='vbox' style={{ flex: 'none' }}>
<div
onDoubleClick={() => onAccepted?.(item)}
className={clsx(
@ -281,7 +282,7 @@ export function TreeItemHeader<T extends TreeItem>({
{icon && <div className={'codicon ' + iconed} style={{ minWidth: 16, marginRight: 4 }} aria-label={'[' + iconed.replace('codicon', 'icon') + ']'}></div>}
{typeof rendered === 'string' ? <div style={{ textOverflow: 'ellipsis', overflow: 'hidden' }}>{rendered}</div> : rendered}
</div>
{!!children.length && <div role='group'>
{!!children.length && <div id={groupId} role='group'>
{children.map(child => {
const itemData = treeItems.get(child);
return itemData && <TreeItemHeader