use aria-label over title, prefix tab ids

This commit is contained in:
Simon Knott 2024-10-24 14:24:59 +02:00
parent d4adcfed17
commit fef30043f0
No known key found for this signature in database
GPG key ID: 8CEDC00028084AEC
6 changed files with 18 additions and 12 deletions

View file

@ -165,6 +165,7 @@ export const Recorder: React.FC<RecorderProps> = ({
sidebarSize={200} sidebarSize={200}
main={<CodeMirrorWrapper text={source.text} language={source.language} highlight={source.highlight} revealLine={source.revealLine} readOnly={true} lineNumbers={true} />} main={<CodeMirrorWrapper text={source.text} language={source.language} highlight={source.highlight} revealLine={source.revealLine} readOnly={true} lineNumbers={true} />}
sidebar={<TabbedPane sidebar={<TabbedPane
id='recorder-sidebar'
rightToolbar={selectedTab === 'locator' || selectedTab === 'aria' ? [<ToolbarButton key={1} icon='files' title='Copy' onClick={() => copy((selectedTab === 'locator' ? locator : ariaSnapshot) || '')} />] : []} rightToolbar={selectedTab === 'locator' || selectedTab === 'aria' ? [<ToolbarButton key={1} icon='files' title='Copy' onClick={() => copy((selectedTab === 'locator' ? locator : ariaSnapshot) || '')} />] : []}
tabs={[ tabs={[
{ {

View file

@ -63,7 +63,7 @@ const ExpandableAttachment: React.FunctionComponent<ExpandableAttachmentProps> =
return Math.min(Math.max(5, lineCount), 20) * lineHeight; return Math.min(Math.max(5, lineCount), 20) * lineHeight;
}, [attachmentText]); }, [attachmentText]);
const title = <span style={{ marginLeft: 5 }} ref={ref} title={attachment.name}> const title = <span style={{ marginLeft: 5 }} ref={ref} aria-label={attachment.name}>
<span style={highlight ? { textDecoration: 'underline var(--vscode-terminal-findMatchBackground)', textDecorationThickness: 1.5 } : {}}>{linkifyText(attachment.name)}</span> <span style={highlight ? { textDecoration: 'underline var(--vscode-terminal-findMatchBackground)', textDecorationThickness: 1.5 } : {}}>{linkifyText(attachment.name)}</span>
{hasContent && <a style={{ marginLeft: 5 }} href={downloadURL(attachment)}>download</a>} {hasContent && <a style={{ marginLeft: 5 }} href={downloadURL(attachment)}>download</a>}
</span>; </span>;

View file

@ -151,7 +151,7 @@ export const Workbench: React.FunctionComponent = () => {
<ToolbarButton icon='color-mode' title='Toggle color mode' toggled={false} onClick={() => toggleTheme()}></ToolbarButton> <ToolbarButton icon='color-mode' title='Toggle color mode' toggled={false} onClick={() => toggleTheme()}></ToolbarButton>
</Toolbar>; </Toolbar>;
const sidebarTabbedPane = <TabbedPane tabs={[actionsTab]} />; const sidebarTabbedPane = <TabbedPane id='recorder-actions-tab' tabs={[actionsTab]} />;
const traceView = <TraceView const traceView = <TraceView
sdkLanguage={sdkLanguage} sdkLanguage={sdkLanguage}
callId={traceCallId} callId={traceCallId}
@ -249,6 +249,7 @@ const PropertiesView: React.FunctionComponent<{
]; ];
return <TabbedPane return <TabbedPane
id='properties-tabs'
tabs={tabs} tabs={tabs}
selectedTab={selectedPropertiesTab} selectedTab={selectedPropertiesTab}
setSelectedTab={setSelectedPropertiesTab} setSelectedTab={setSelectedPropertiesTab}

View file

@ -341,6 +341,7 @@ export const Workbench: React.FunctionComponent<{
openPage={openPage} />} openPage={openPage} />}
sidebar={ sidebar={
<TabbedPane <TabbedPane
id='actionlist-sidebar'
tabs={[actionsTab, metadataTab]} tabs={[actionsTab, metadataTab]}
selectedTab={selectedNavigatorTab} selectedTab={selectedNavigatorTab}
setSelectedTab={setSelectedNavigatorTab} setSelectedTab={setSelectedNavigatorTab}
@ -348,6 +349,7 @@ export const Workbench: React.FunctionComponent<{
} }
/>} />}
sidebar={<TabbedPane sidebar={<TabbedPane
id='workbench-sidebar'
tabs={tabs} tabs={tabs}
selectedTab={selectedPropertiesTab} selectedTab={selectedPropertiesTab}
setSelectedTab={selectPropertiesTab} setSelectedTab={selectPropertiesTab}

View file

@ -36,7 +36,8 @@ export const TabbedPane: React.FunctionComponent<{
setSelectedTab?: (tab: string) => void, setSelectedTab?: (tab: string) => void,
dataTestId?: string, dataTestId?: string,
mode?: 'default' | 'select', mode?: 'default' | 'select',
}> = ({ tabs, selectedTab, setSelectedTab, leftToolbar, rightToolbar, dataTestId, mode }) => { id: string,
}> = ({ tabs, selectedTab, setSelectedTab, leftToolbar, rightToolbar, dataTestId, mode, id }) => {
if (!selectedTab) if (!selectedTab)
selectedTab = tabs[0].id; selectedTab = tabs[0].id;
if (!mode) if (!mode)
@ -52,6 +53,7 @@ export const TabbedPane: React.FunctionComponent<{
<TabbedPaneTab <TabbedPaneTab
key={tab.id} key={tab.id}
id={tab.id} id={tab.id}
aria-controls={`pane-${id}-tab-${tab.id}`}
title={tab.title} title={tab.title}
count={tab.count} count={tab.count}
errorCount={tab.errorCount} errorCount={tab.errorCount}
@ -70,7 +72,7 @@ export const TabbedPane: React.FunctionComponent<{
suffix = ` (${tab.count})`; suffix = ` (${tab.count})`;
if (tab.errorCount) if (tab.errorCount)
suffix = ` (${tab.errorCount})`; suffix = ` (${tab.errorCount})`;
return <option key={tab.id} value={tab.id} selected={tab.id === selectedTab} role='tab' aria-controls={`tab-${tab.id}`}>{tab.title}{suffix}</option>; return <option key={tab.id} value={tab.id} selected={tab.id === selectedTab} role='tab' aria-controls={`pane-${id}-tab-${tab.id}`}>{tab.title}{suffix}</option>;
})} })}
</select> </select>
</div>} </div>}
@ -82,9 +84,9 @@ export const TabbedPane: React.FunctionComponent<{
tabs.map(tab => { tabs.map(tab => {
const className = 'tab-content tab-' + tab.id; const className = 'tab-content tab-' + tab.id;
if (tab.component) if (tab.component)
return <div key={tab.id} id={`tab-${tab.id}`} role='tabpanel' title={tab.title} className={className} style={{ display: selectedTab === tab.id ? 'inherit' : 'none' }}>{tab.component}</div>; return <div key={tab.id} id={`pane-${id}-tab-${tab.id}`} role='tabpanel' aria-label={tab.title} className={className} style={{ display: selectedTab === tab.id ? 'inherit' : 'none' }}>{tab.component}</div>;
if (selectedTab === tab.id) if (selectedTab === tab.id)
return <div key={tab.id} id={`tab-${tab.id}`} role='tabpanel' title={tab.title} className={className}>{tab.render!()}</div>; return <div key={tab.id} id={`pane-${id}-tab-${tab.id}`} role='tabpanel' aria-label={tab.title} className={className}>{tab.render!()}</div>;
}) })
} }
</div> </div>
@ -97,14 +99,14 @@ export const TabbedPaneTab: React.FunctionComponent<{
count?: number, count?: number,
errorCount?: number, errorCount?: number,
selected?: boolean, selected?: boolean,
onSelect?: (id: string) => void onSelect?: (id: string) => void,
}> = ({ id, title, count, errorCount, selected, onSelect }) => { 'aria-controls'?: string,
}> = ({ id, title, count, errorCount, selected, onSelect, 'aria-controls': ariaControls }) => {
return <div className={clsx('tabbed-pane-tab', selected && 'selected')} return <div className={clsx('tabbed-pane-tab', selected && 'selected')}
onClick={() => onSelect?.(id)} onClick={() => onSelect?.(id)}
role='tab' role='tab'
aria-controls={`tab-${id}`} aria-controls={ariaControls}
title={title} aria-label={title}>
key={id}>
<div className='tabbed-pane-tab-label'>{title}</div> <div className='tabbed-pane-tab-label'>{title}</div>
{!!count && <div className='tabbed-pane-tab-counter'>{count}</div>} {!!count && <div className='tabbed-pane-tab-counter'>{count}</div>}
{!!errorCount && <div className='tabbed-pane-tab-counter error'>{errorCount}</div>} {!!errorCount && <div className='tabbed-pane-tab-counter error'>{errorCount}</div>}

View file

@ -166,7 +166,7 @@ test('should link from attachment step to attachments view', async ({ runUITest,
await page.getByRole('tab', { name: 'Attachments' }).click(); await page.getByRole('tab', { name: 'Attachments' }).click();
const panel = page.getByRole('tabpanel', { name: 'Attachments' }); const panel = page.getByRole('tabpanel', { name: 'Attachments' });
const attachment = panel.getByTitle('my-attachment'); const attachment = panel.getByLabel('my-attachment');
await expect(attachment).not.toBeInViewport(); await expect(attachment).not.toBeInViewport();
await page.getByText('attach "my-attachment"').click(); await page.getByText('attach "my-attachment"').click();
await expect(attachment).toBeInViewport(); await expect(attachment).toBeInViewport();