Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/browser/ui/aria/aria.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as dom from '../../dom.js';
7
import './aria.css';
8
9
// Use a max length since we are inserting the whole msg in the DOM and that can cause browsers to freeze for long messages #94233
10
const MAX_MESSAGE_LENGTH = 20000;
11
let ariaContainer: HTMLElement;
12
let alertContainer: HTMLElement;
13
let alertContainer2: HTMLElement;
14
let statusContainer: HTMLElement;
15
let statusContainer2: HTMLElement;
16
export function setARIAContainer(parent: HTMLElement) {
17
ariaContainer = document.createElement('div');
18
ariaContainer.className = 'monaco-aria-container';
19
20
const createAlertContainer = () => {
21
const element = document.createElement('div');
22
element.className = 'monaco-alert';
23
element.setAttribute('role', 'alert');
24
element.setAttribute('aria-atomic', 'true');
25
ariaContainer.appendChild(element);
26
return element;
27
};
28
alertContainer = createAlertContainer();
29
alertContainer2 = createAlertContainer();
30
31
const createStatusContainer = () => {
32
const element = document.createElement('div');
33
element.className = 'monaco-status';
34
element.setAttribute('aria-live', 'polite');
35
element.setAttribute('aria-atomic', 'true');
36
ariaContainer.appendChild(element);
37
return element;
38
};
39
statusContainer = createStatusContainer();
40
statusContainer2 = createStatusContainer();
41
42
parent.appendChild(ariaContainer);
43
}
44
/**
45
* Given the provided message, will make sure that it is read as alert to screen readers.
46
*/
47
export function alert(msg: string): void {
48
if (!ariaContainer) {
49
return;
50
}
51
52
// Use alternate containers such that duplicated messages get read out by screen readers #99466
53
if (alertContainer.textContent !== msg) {
54
dom.clearNode(alertContainer2);
55
insertMessage(alertContainer, msg);
56
} else {
57
dom.clearNode(alertContainer);
58
insertMessage(alertContainer2, msg);
59
}
60
}
61
62
/**
63
* Given the provided message, will make sure that it is read as status to screen readers.
64
*/
65
export function status(msg: string): void {
66
if (!ariaContainer) {
67
return;
68
}
69
70
if (statusContainer.textContent !== msg) {
71
dom.clearNode(statusContainer2);
72
insertMessage(statusContainer, msg);
73
} else {
74
dom.clearNode(statusContainer);
75
insertMessage(statusContainer2, msg);
76
}
77
}
78
79
function insertMessage(target: HTMLElement, msg: string): void {
80
dom.clearNode(target);
81
if (msg.length > MAX_MESSAGE_LENGTH) {
82
msg = msg.substr(0, MAX_MESSAGE_LENGTH);
83
}
84
target.textContent = msg;
85
86
// See https://www.paciellogroup.com/blog/2012/06/html5-accessibility-chops-aria-rolealert-browser-support/
87
target.style.visibility = 'hidden';
88
target.style.visibility = 'visible';
89
}
90
91
// Copied from @types/react which original came from https://www.w3.org/TR/wai-aria-1.1/#role_definitions
92
export type AriaRole =
93
| 'alert'
94
| 'alertdialog'
95
| 'application'
96
| 'article'
97
| 'banner'
98
| 'button'
99
| 'cell'
100
| 'checkbox'
101
| 'columnheader'
102
| 'combobox'
103
| 'complementary'
104
| 'contentinfo'
105
| 'definition'
106
| 'dialog'
107
| 'directory'
108
| 'document'
109
| 'feed'
110
| 'figure'
111
| 'form'
112
| 'grid'
113
| 'gridcell'
114
| 'group'
115
| 'heading'
116
| 'img'
117
| 'link'
118
| 'list'
119
| 'listbox'
120
| 'listitem'
121
| 'log'
122
| 'main'
123
| 'marquee'
124
| 'math'
125
| 'menu'
126
| 'menubar'
127
| 'menuitem'
128
| 'menuitemcheckbox'
129
| 'menuitemradio'
130
| 'navigation'
131
| 'none'
132
| 'note'
133
| 'option'
134
| 'presentation'
135
| 'progressbar'
136
| 'radio'
137
| 'radiogroup'
138
| 'region'
139
| 'row'
140
| 'rowgroup'
141
| 'rowheader'
142
| 'scrollbar'
143
| 'search'
144
| 'searchbox'
145
| 'separator'
146
| 'slider'
147
| 'spinbutton'
148
| 'status'
149
| 'switch'
150
| 'tab'
151
| 'table'
152
| 'tablist'
153
| 'tabpanel'
154
| 'term'
155
| 'textbox'
156
| 'timer'
157
| 'toolbar'
158
| 'tooltip'
159
| 'tree'
160
| 'treegrid'
161
| 'treeitem'
162
| (string & {}) // Prevent type collapsing to `string`
163
;
164
165