[Accessibility] [Keyboard Navigation] Enable left panels to focus on the first interactive element (#2334)

* Fixed focus on the first element when opening the Resources and Bot explorer panels

* Renamed prop with a more descriptive name

Co-authored-by: Federico Bernal <64086728+FedericoBernal@users.noreply.github.com>
This commit is contained in:
Matias Lera 2021-11-29 15:53:06 -03:00 коммит произвёл GitHub
Родитель 544e913c19
Коммит ffbdf716a1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 53 добавлений и 4 удалений

Просмотреть файл

@ -32,6 +32,7 @@
//
import { IBotConfiguration } from 'botframework-config/lib/schema';
import { removeNotification } from 'packages/app/client/src/state/sagas/notificationSagas';
import * as React from 'react';
import { BotNotOpenExplorerContainer } from '../botNotOpenExplorer';
@ -48,20 +49,35 @@ interface BotExplorerBarProps {
}
export default class BotExplorerBar extends React.Component<BotExplorerBarProps, Record<string, unknown>> {
private static get activeBotJsx(): JSX.Element {
private get activeBotJsx(): JSX.Element {
return (
<>
<EndpointExplorerContainer title="Endpoint" ariaLabel="Endpoints" />
<EndpointExplorerContainer
title="Endpoint"
ariaLabel="Endpoints"
elementRefHandler={this.setEndpointsPanelRef}
/>
<ServicesExplorerContainer title="Services" ariaLabel="Services" />
</>
);
}
private openBotSettingsButtonRef: HTMLButtonElement;
private endpointsPanelRef: HTMLElement;
public componentDidMount(): void {
if (this.endpointsPanelRef) {
this.endpointsPanelRef.focus();
}
}
public render() {
const className = this.props.hidden ? styles.explorerOffScreen : '';
const explorerBody = this.props.activeBot ? BotExplorerBar.activeBotJsx : <BotNotOpenExplorerContainer />;
const explorerBody = this.props.activeBot ? (
this.activeBotJsx
) : (
<BotNotOpenExplorerContainer elementRefHandler={this.setEndpointsPanelRef} />
);
return (
<div className={`${styles.botExplorerBar} ${className}`}>
<div className={explorerStyles.explorerBarHeader}>
@ -91,4 +107,8 @@ export default class BotExplorerBar extends React.Component<BotExplorerBarProps,
private setOpenBotSettingsRef = (ref: HTMLButtonElement): void => {
this.openBotSettingsButtonRef = ref;
};
private setEndpointsPanelRef = (ref: HTMLElement) => {
this.endpointsPanelRef = ref;
};
}

Просмотреть файл

@ -40,6 +40,7 @@ export interface BotNotOpenExplorerProps {
hasChat?: boolean;
openBotFile?: () => Promise<any>;
showCreateNewBotDialog?: () => void;
elementRefHandler?: (ref: HTMLElement) => void;
}
export class BotNotOpenExplorer extends React.Component<BotNotOpenExplorerProps, Record<string, unknown>> {
@ -50,7 +51,12 @@ export class BotNotOpenExplorer extends React.Component<BotNotOpenExplorerProps,
return (
<ul className={styles.botNotOpenExplorer}>
<li>
<ExpandCollapse expanded={true} ariaLabel={label} title={label}>
<ExpandCollapse
expanded={true}
ariaLabel={label}
title={label}
elementRefHandler={this.props.elementRefHandler}
>
<ExpandCollapseContent>
<div className={styles.explorerEmptyState}>
{`To connect the Emulator services, `}

Просмотреть файл

@ -47,6 +47,14 @@ export interface ResourcesBarProps {
}
export class ResourcesBar extends Component<ResourcesBarProps, ResourcesBarProps> {
private chatFilesRef: HTMLElement;
public componentDidMount(): void {
if (this.chatFilesRef) {
this.chatFilesRef.focus();
}
}
public render() {
return (
<div className={styles.resourcesBar}>
@ -56,6 +64,7 @@ export class ResourcesBar extends Component<ResourcesBarProps, ResourcesBarProps
<ul className={explorerStyles.explorerSet}>
<li>
<ResourceExplorerContainer
elementRefHandler={this.setChatFilesRef}
files={this.props.chatFiles}
resourcesPath={this.props.chatsPath}
title="chat files"
@ -72,4 +81,7 @@ export class ResourcesBar extends Component<ResourcesBarProps, ResourcesBarProps
</div>
);
}
private setChatFilesRef = (elementRefHandler: HTMLElement) => {
this.chatFilesRef = elementRefHandler;
};
}

Просмотреть файл

@ -45,6 +45,7 @@ export interface ServicePaneProps extends ServicePaneState {
title?: string;
ariaLabel?: string;
sortCriteria?: string;
elementRefHandler?: (ref: HTMLElement) => void;
}
export interface ServicePaneState {
@ -181,6 +182,7 @@ export abstract class ServicePane<
className={styles.servicePane}
key={this.props.title}
title={this.props.title}
elementRefHandler={this.props.elementRefHandler}
ariaLabel={this.props.ariaLabel}
expanded={this.state.expanded}
>

Просмотреть файл

@ -43,6 +43,7 @@ export interface ExpandCollapseProps {
title?: string;
className?: string;
ariaLabel?: string;
elementRefHandler?: (ref: HTMLElement) => void;
}
export interface ExpandCollapseState {
@ -66,6 +67,7 @@ export class ExpandCollapse extends React.Component<ExpandCollapseProps, ExpandC
return (
<div className={`${styles.expandCollapse} ${className} ${expanded ? 'expanded' : ''}`}>
<div
ref={this.setElementRefHandler}
aria-expanded={expanded}
aria-label={ariaLabel}
role="toolbar"
@ -121,6 +123,13 @@ export class ExpandCollapse extends React.Component<ExpandCollapseProps, ExpandC
}
};
private setElementRefHandler = (ref: HTMLElement): void => {
const { elementRefHandler } = this.props;
if (elementRefHandler) {
elementRefHandler(ref);
}
};
private get announcePanelState(): React.ReactNode {
const { expanded } = this.state;
const { title } = this.props;