a11y: platform fixes for mac (#2381)
* a11y: 63767 - fix VoiceOver reading whole list content In Electron/Chrome it reads the whole list content when the list root focused. Add a label to fix the issue. * a11y: 64009 - improve left pane contrast Fixes secondary text contrast and improves contrast ratio for primary text for the Left pane. The bug mentioned some menu contrast issues, I believe the're not existent. The bug also mentioned JSON contrast. It is already fixed. * a11y: 64005 - make consistent full-screen handling between all platforms Includes the following changes: - Move the popup logic into the command - Use the command for the native menu * a11y: switch theme: announce on all platforms Adds announcement for macOS as well. And makes message to start with visible content. * Revert "a11y: 64005 - make consistent full-screen handling between all platforms" This reverts commit 850cd46f32d718efe6cc5a5ec4db9e37f56f033d. * Revert "a11y: switch theme: announce on all platforms" This reverts commit 14aea00b857b63ce0eb60cdd35a13dfb7000b9f8. * a11y: 63887 - make ngrok status accessible Not able to reproduce the original issue, but found that the ngrok status is not being announced, so added the tunnel status and tunnel errors announcement. * a11y: 63914 - rework collapsable content announcement Prevent lists from being announced when a new entry gets added. Co-authored-by: Eugene Olonov <v-evolo@microsoft.com> Co-authored-by: Tony Anziano <tonyanziano5@gmail.com>
This commit is contained in:
Родитель
72e46fe262
Коммит
0ac4a1c47f
|
@ -158,7 +158,12 @@ export const NgrokDebugger = (props: NgrokDebuggerProps) => {
|
|||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<LinkButton linkRole={true} onClick={props.onPingTunnelClick} buttonRef={setPingTunnelInputRef}>
|
||||
<LinkButton
|
||||
linkRole={true}
|
||||
ariaLabel={'Click here to ping the tunnel now'}
|
||||
onClick={props.onPingTunnelClick}
|
||||
buttonRef={setPingTunnelInputRef}
|
||||
>
|
||||
Click here
|
||||
</LinkButton>
|
||||
to ping the tunnel now
|
||||
|
|
|
@ -46,7 +46,7 @@ export const NgrokErrorHandler = (props: NgrokErrorHandlerProps) => {
|
|||
case 429:
|
||||
return (
|
||||
<>
|
||||
<legend>
|
||||
<legend role="alert">
|
||||
Looks like you have hit your free tier limit on connections to your tunnel. Below you will find several
|
||||
possible solutions.
|
||||
</legend>
|
||||
|
@ -81,9 +81,11 @@ export const NgrokErrorHandler = (props: NgrokErrorHandlerProps) => {
|
|||
|
||||
case 402:
|
||||
return (
|
||||
<legend>
|
||||
Looks like the ngrok tunnel has expired. Try reconnecting to Ngrok or examine the logs for a detailed
|
||||
explanation of the error.
|
||||
<>
|
||||
<legend role="alert">
|
||||
Looks like the ngrok tunnel has expired. Try reconnecting to Ngrok or examine the logs for a detailed
|
||||
explanation of the error.
|
||||
</legend>
|
||||
<LinkButton
|
||||
ariaLabel="Click here to reconnect to ngrok."
|
||||
linkRole={false}
|
||||
|
@ -91,14 +93,16 @@ export const NgrokErrorHandler = (props: NgrokErrorHandlerProps) => {
|
|||
>
|
||||
Click here to reconnect to ngrok
|
||||
</LinkButton>
|
||||
</legend>
|
||||
</>
|
||||
);
|
||||
|
||||
default:
|
||||
return (
|
||||
<legend>
|
||||
Looks like the ngrok tunnel does not exist anymore. Try reconnecting to Ngrok or examine the logs for a
|
||||
detailed explanation of the error.
|
||||
<>
|
||||
<legend role="alert">
|
||||
Looks like the ngrok tunnel does not exist anymore. Try reconnecting to Ngrok or examine the logs for a
|
||||
detailed explanation of the error.
|
||||
</legend>
|
||||
<LinkButton
|
||||
ariaLabel="Click here to reconnect to ngrok."
|
||||
linkRole={false}
|
||||
|
@ -106,7 +110,7 @@ export const NgrokErrorHandler = (props: NgrokErrorHandlerProps) => {
|
|||
>
|
||||
Click here to reconnect to ngrok
|
||||
</LinkButton>
|
||||
</legend>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -8,6 +8,15 @@
|
|||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.announcement {
|
||||
position: absolute;
|
||||
left: -10000px;
|
||||
top: auto;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// This is a generated file. Changes are likely to result in being overwritten
|
||||
export const ngrokStatusIndicator: string;
|
||||
export const announcement: string;
|
||||
export const header: string;
|
||||
export const tunnelHealthIndicator: string;
|
||||
export const tunnelError: string;
|
||||
|
|
|
@ -45,19 +45,23 @@ export interface NgrokTimeIntervalIndicatorProps {
|
|||
export const NgrokStatusIndicator = (props: NgrokTimeIntervalIndicatorProps) => {
|
||||
const [statusDisplay, setStatusDisplay] = useState(styles.tunnelInactive);
|
||||
const [displayTimeInterval, setTimeIntervalDisplay] = useState('Last refreshed now');
|
||||
const [statusAnnouncement, setStatusAnnouncement] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
switch (props.tunnelStatus) {
|
||||
case TunnelStatus.Active:
|
||||
setStatusDisplay(styles.tunnelActive);
|
||||
setStatusAnnouncement('active');
|
||||
break;
|
||||
|
||||
case TunnelStatus.Error:
|
||||
setStatusDisplay(styles.tunnelError);
|
||||
setStatusAnnouncement('error');
|
||||
break;
|
||||
|
||||
default:
|
||||
setStatusDisplay(styles.tunnelInactive);
|
||||
setStatusAnnouncement('inactive');
|
||||
break;
|
||||
}
|
||||
}, [props.tunnelStatus]);
|
||||
|
@ -84,6 +88,9 @@ export const NgrokStatusIndicator = (props: NgrokTimeIntervalIndicatorProps) =>
|
|||
|
||||
return (
|
||||
<div className={styles.ngrokStatusIndicator}>
|
||||
<span className={styles.announcement} role="status">
|
||||
{props.header} {statusAnnouncement} {displayTimeInterval}
|
||||
</span>
|
||||
<span className={styles.header}>{props.header}:</span>
|
||||
<span className={[styles.tunnelHealthIndicator, statusDisplay].join(' ')}>
|
||||
<span>{displayTimeInterval}</span>
|
||||
|
|
|
@ -60,7 +60,7 @@ export class BotNotOpenExplorer extends React.Component<BotNotOpenExplorerProps,
|
|||
role={this.props.role}
|
||||
>
|
||||
<ExpandCollapseContent>
|
||||
<div className={styles.explorerEmptyState}>
|
||||
<div aria-live="polite" className={styles.explorerEmptyState}>
|
||||
{`To connect the Emulator services, `}
|
||||
<LinkButton className={styles.explorerLink} onClick={this.onOpenBotFileClick}>
|
||||
open a .bot file
|
||||
|
|
|
@ -23,5 +23,5 @@ ul > li > input[type="text"] {
|
|||
.empty-content {
|
||||
margin: 12px 25px;
|
||||
font-size: 13px;
|
||||
color: var(--neutral-7);
|
||||
color: var(--list-info-color);
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
}
|
||||
|
||||
.empty-content {
|
||||
color: var(--neutral-7);
|
||||
color: var(--list-info-color);
|
||||
font-size: 13px;
|
||||
margin: 12px 25px;
|
||||
}
|
||||
|
@ -100,7 +100,7 @@
|
|||
}
|
||||
|
||||
& span {
|
||||
color: var(--neutral-7);
|
||||
color: var(--list-item-secondary-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,16 +111,26 @@ export abstract class ServicePane<
|
|||
protected get content(): JSX.Element {
|
||||
const { links, additionalContent } = this;
|
||||
const { sortCriteriaChanged } = this.state;
|
||||
const { ariaLabel } = this.props;
|
||||
|
||||
if (!links || !links.length) {
|
||||
return <ExpandCollapseContent>{this.emptyContent}</ExpandCollapseContent>;
|
||||
return (
|
||||
<ExpandCollapseContent>
|
||||
<div aria-live="polite">{this.emptyContent}</div>
|
||||
</ExpandCollapseContent>
|
||||
);
|
||||
}
|
||||
if (sortCriteriaChanged) {
|
||||
this.listRef && this.listRef.focus();
|
||||
}
|
||||
return (
|
||||
<ExpandCollapseContent>
|
||||
<ul className={styles.servicePaneList} ref={ul => (this.listRef = ul)} tabIndex={0}>
|
||||
<ul
|
||||
className={styles.servicePaneList}
|
||||
ref={ul => (this.listRef = ul)}
|
||||
tabIndex={0}
|
||||
aria-label={`${ariaLabel} list`}
|
||||
>
|
||||
{links}
|
||||
</ul>
|
||||
{additionalContent}
|
||||
|
|
|
@ -7,6 +7,7 @@ html {
|
|||
|
||||
/* Highlight colors */
|
||||
--list-item-color: var(--neutral-3);
|
||||
--list-item-secondary-color: var(--neutral-6);
|
||||
--list-item-selected-color: var(--neutral-2);
|
||||
--list-item-hover-bg: var(--neutral-13);
|
||||
--list-item-hover-border: 1px dashed transparent;
|
||||
|
@ -15,6 +16,7 @@ html {
|
|||
--focused-outline: 1px solid #0E369C;
|
||||
--focused-selected-highlighted-list-item: #3062D6;
|
||||
--focused-selected-list-item-bg: #3794FF;
|
||||
--list-info-color: var(--neutral-6);
|
||||
|
||||
/* Alert colors */
|
||||
--info-bg: #063B49;
|
||||
|
|
|
@ -7,6 +7,7 @@ html {
|
|||
|
||||
/* Highlight colors */
|
||||
--list-item-color: var(--neutral-1);
|
||||
--list-item-secondary-color: var(--neutral-1);
|
||||
--list-item-selected-color: var(--neutral-2);
|
||||
--list-item-hover-bg: transparent;
|
||||
--list-item-hover-border: 1px dashed #F38518;
|
||||
|
@ -15,6 +16,7 @@ html {
|
|||
--focused-outline: var(--list-item-hover-border);
|
||||
--focused-selected-highlighted-list-item: #3062D6;
|
||||
--focused-selected-list-item-bg: #3794FF;
|
||||
--list-info-color: var(--neutral-1);
|
||||
|
||||
/* Alert colors */
|
||||
--info-bg: #D6ECF2;
|
||||
|
|
|
@ -6,7 +6,8 @@ html {
|
|||
--box-shadow-color: var(--neutral-6);
|
||||
|
||||
/* Highlight colors */
|
||||
--list-item-color: #605E5C;
|
||||
--list-item-color: var(--neutral-14);
|
||||
--list-item-secondary-color: var(--neutral-10);
|
||||
--list-item-selected-color: var(--neutral-2);
|
||||
--list-item-hover-bg: var(--neutral-4);
|
||||
--list-item-hover-border: 1px dashed transparent;
|
||||
|
@ -15,6 +16,7 @@ html {
|
|||
--focused-outline: 1px solid #0E369C;
|
||||
--focused-selected-highlighted-list-item: #3062D6;
|
||||
--focused-selected-list-item-bg: #006AB1;
|
||||
--list-info-color: var(--neutral-10);
|
||||
|
||||
/* Alert colors */
|
||||
--info-bg: #D6ECF2;
|
||||
|
|
|
@ -123,10 +123,12 @@ export class NgrokInstance {
|
|||
return;
|
||||
}
|
||||
const errorMessage = response.text;
|
||||
this.ws.write('-- Tunnel Error Response --');
|
||||
this.ws.write(`Status Code: ${response.status}`);
|
||||
this.ws.write(errorMessage);
|
||||
this.ws.write('-- End Response --');
|
||||
if (this.ws) {
|
||||
this.ws.write('-- Tunnel Error Response --');
|
||||
this.ws.write(`Status Code: ${response.status}`);
|
||||
this.ws.write(errorMessage);
|
||||
this.ws.write('-- End Response --');
|
||||
}
|
||||
this.ngrokEmitter.emit('onTunnelError', {
|
||||
statusCode: response.status,
|
||||
errorMessage,
|
||||
|
|
|
@ -85,7 +85,7 @@ export class ExpandCollapse extends React.Component<ExpandCollapseProps, ExpandC
|
|||
</div>
|
||||
{this.announcePanelState}
|
||||
</div>
|
||||
<div className={styles.body} aria-live={'polite'}>
|
||||
<div className={styles.body}>
|
||||
{expanded && filterChildren(children, child => hmrSafeNameComparison(child.type, ExpandCollapseContent))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
Загрузка…
Ссылка в новой задаче