@angular/cdk 21.0.0-next.8 → 21.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_adev_assets/cdk_drag_drop.json +13 -12
- package/_adev_assets/cdk_testing.json +15 -25
- package/_adev_assets/cdk_testing_protractor.json +1 -1
- package/_adev_assets/cdk_testing_selenium_webdriver.json +1 -1
- package/_adev_assets/cdk_testing_testbed.json +1 -1
- package/fesm2022/_a11y-module-chunk.mjs +755 -869
- package/fesm2022/_a11y-module-chunk.mjs.map +1 -1
- package/fesm2022/_activedescendant-key-manager-chunk.mjs +8 -8
- package/fesm2022/_activedescendant-key-manager-chunk.mjs.map +1 -1
- package/fesm2022/_array-chunk.mjs +1 -1
- package/fesm2022/_array-chunk.mjs.map +1 -1
- package/fesm2022/_breakpoints-observer-chunk.mjs +149 -152
- package/fesm2022/_breakpoints-observer-chunk.mjs.map +1 -1
- package/fesm2022/_css-pixel-value-chunk.mjs +4 -5
- package/fesm2022/_css-pixel-value-chunk.mjs.map +1 -1
- package/fesm2022/_data-source-chunk.mjs +2 -8
- package/fesm2022/_data-source-chunk.mjs.map +1 -1
- package/fesm2022/_directionality-chunk.mjs +54 -54
- package/fesm2022/_directionality-chunk.mjs.map +1 -1
- package/fesm2022/_dispose-view-repeater-strategy-chunk.mjs +25 -36
- package/fesm2022/_dispose-view-repeater-strategy-chunk.mjs.map +1 -1
- package/fesm2022/_element-chunk.mjs +6 -17
- package/fesm2022/_element-chunk.mjs.map +1 -1
- package/fesm2022/_fake-event-detection-chunk.mjs +3 -17
- package/fesm2022/_fake-event-detection-chunk.mjs.map +1 -1
- package/fesm2022/_focus-key-manager-chunk.mjs +10 -14
- package/fesm2022/_focus-key-manager-chunk.mjs.map +1 -1
- package/fesm2022/_focus-monitor-chunk.mjs +376 -566
- package/fesm2022/_focus-monitor-chunk.mjs.map +1 -1
- package/fesm2022/_id-generator-chunk.mjs +36 -27
- package/fesm2022/_id-generator-chunk.mjs.map +1 -1
- package/fesm2022/_keycodes-chunk.mjs +9 -9
- package/fesm2022/_keycodes-chunk.mjs.map +1 -1
- package/fesm2022/_list-key-manager-chunk.mjs +248 -336
- package/fesm2022/_list-key-manager-chunk.mjs.map +1 -1
- package/fesm2022/_overlay-module-chunk.mjs +2534 -2948
- package/fesm2022/_overlay-module-chunk.mjs.map +1 -1
- package/fesm2022/_passive-listeners-chunk.mjs +10 -22
- package/fesm2022/_passive-listeners-chunk.mjs.map +1 -1
- package/fesm2022/_platform-chunk.mjs +42 -65
- package/fesm2022/_platform-chunk.mjs.map +1 -1
- package/fesm2022/_recycle-view-repeater-strategy-chunk.mjs +78 -134
- package/fesm2022/_recycle-view-repeater-strategy-chunk.mjs.map +1 -1
- package/fesm2022/_scrolling-chunk.mjs +44 -85
- package/fesm2022/_scrolling-chunk.mjs.map +1 -1
- package/fesm2022/_selection-model-chunk.mjs +138 -209
- package/fesm2022/_selection-model-chunk.mjs.map +1 -1
- package/fesm2022/_shadow-dom-chunk.mjs +21 -35
- package/fesm2022/_shadow-dom-chunk.mjs.map +1 -1
- package/fesm2022/_style-loader-chunk.mjs +50 -37
- package/fesm2022/_style-loader-chunk.mjs.map +1 -1
- package/fesm2022/_test-environment-chunk.mjs +2 -14
- package/fesm2022/_test-environment-chunk.mjs.map +1 -1
- package/fesm2022/_tree-key-manager-chunk.mjs +229 -308
- package/fesm2022/_tree-key-manager-chunk.mjs.map +1 -1
- package/fesm2022/_typeahead-chunk.mjs +52 -74
- package/fesm2022/_typeahead-chunk.mjs.map +1 -1
- package/fesm2022/_unique-selection-dispatcher-chunk.mjs +43 -40
- package/fesm2022/_unique-selection-dispatcher-chunk.mjs.map +1 -1
- package/fesm2022/a11y.mjs +351 -449
- package/fesm2022/a11y.mjs.map +1 -1
- package/fesm2022/accordion.mjs +254 -192
- package/fesm2022/accordion.mjs.map +1 -1
- package/fesm2022/bidi.mjs +121 -64
- package/fesm2022/bidi.mjs.map +1 -1
- package/fesm2022/cdk.mjs +1 -2
- package/fesm2022/cdk.mjs.map +1 -1
- package/fesm2022/clipboard.mjs +208 -186
- package/fesm2022/clipboard.mjs.map +1 -1
- package/fesm2022/coercion-private.mjs +4 -8
- package/fesm2022/coercion-private.mjs.map +1 -1
- package/fesm2022/coercion.mjs +11 -29
- package/fesm2022/coercion.mjs.map +1 -1
- package/fesm2022/dialog.mjs +660 -808
- package/fesm2022/dialog.mjs.map +1 -1
- package/fesm2022/drag-drop.mjs +3347 -4286
- package/fesm2022/drag-drop.mjs.map +1 -1
- package/fesm2022/keycodes.mjs +4 -8
- package/fesm2022/keycodes.mjs.map +1 -1
- package/fesm2022/layout.mjs +44 -26
- package/fesm2022/layout.mjs.map +1 -1
- package/fesm2022/listbox.mjs +841 -895
- package/fesm2022/listbox.mjs.map +1 -1
- package/fesm2022/menu.mjs +1942 -1858
- package/fesm2022/menu.mjs.map +1 -1
- package/fesm2022/observers-private.mjs +88 -106
- package/fesm2022/observers-private.mjs.map +1 -1
- package/fesm2022/observers.mjs +262 -184
- package/fesm2022/observers.mjs.map +1 -1
- package/fesm2022/overlay.mjs +72 -68
- package/fesm2022/overlay.mjs.map +1 -1
- package/fesm2022/platform.mjs +43 -54
- package/fesm2022/platform.mjs.map +1 -1
- package/fesm2022/portal.mjs +402 -560
- package/fesm2022/portal.mjs.map +1 -1
- package/fesm2022/private.mjs +38 -10
- package/fesm2022/private.mjs.map +1 -1
- package/fesm2022/scrolling.mjs +1323 -1400
- package/fesm2022/scrolling.mjs.map +1 -1
- package/fesm2022/stepper.mjs +758 -590
- package/fesm2022/stepper.mjs.map +1 -1
- package/fesm2022/table.mjs +2327 -2319
- package/fesm2022/table.mjs.map +1 -1
- package/fesm2022/testing-selenium-webdriver.mjs +252 -325
- package/fesm2022/testing-selenium-webdriver.mjs.map +1 -1
- package/fesm2022/testing-testbed.mjs +592 -709
- package/fesm2022/testing-testbed.mjs.map +1 -1
- package/fesm2022/testing.mjs +368 -889
- package/fesm2022/testing.mjs.map +1 -1
- package/fesm2022/text-field.mjs +459 -388
- package/fesm2022/text-field.mjs.map +1 -1
- package/fesm2022/tree.mjs +1483 -1731
- package/fesm2022/tree.mjs.map +1 -1
- package/overlay/_index.scss +28 -0
- package/overlay-prebuilt.css +1 -1
- package/package.json +1 -1
- package/schematics/ng-add/index.js +1 -1
- package/types/_harness-environment-chunk.d.ts +1 -2
- package/types/_overlay-module-chunk.d.ts +59 -7
- package/types/_portal-directives-chunk.d.ts +2 -18
- package/types/accordion.d.ts +3 -1
- package/types/dialog.d.ts +1 -1
- package/types/overlay.d.ts +6 -2
- package/types/portal.d.ts +1 -1
package/fesm2022/a11y.mjs
CHANGED
|
@@ -27,494 +27,396 @@ import './_typeahead-chunk.mjs';
|
|
|
27
27
|
import './keycodes.mjs';
|
|
28
28
|
import './coercion-private.mjs';
|
|
29
29
|
|
|
30
|
-
/** IDs are delimited by an empty space, as per the spec. */
|
|
31
30
|
const ID_DELIMITER = ' ';
|
|
32
|
-
/**
|
|
33
|
-
* Adds the given ID to the specified ARIA attribute on an element.
|
|
34
|
-
* Used for attributes such as aria-labelledby, aria-owns, etc.
|
|
35
|
-
*/
|
|
36
31
|
function addAriaReferencedId(el, attr, id) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
const ids = getAriaReferenceIds(el, attr);
|
|
33
|
+
id = id.trim();
|
|
34
|
+
if (ids.some(existingId => existingId.trim() === id)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
ids.push(id);
|
|
38
|
+
el.setAttribute(attr, ids.join(ID_DELIMITER));
|
|
44
39
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Removes the given ID from the specified ARIA attribute on an element.
|
|
47
|
-
* Used for attributes such as aria-labelledby, aria-owns, etc.
|
|
48
|
-
*/
|
|
49
40
|
function removeAriaReferencedId(el, attr, id) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
41
|
+
const ids = getAriaReferenceIds(el, attr);
|
|
42
|
+
id = id.trim();
|
|
43
|
+
const filteredIds = ids.filter(val => val !== id);
|
|
44
|
+
if (filteredIds.length) {
|
|
45
|
+
el.setAttribute(attr, filteredIds.join(ID_DELIMITER));
|
|
46
|
+
} else {
|
|
47
|
+
el.removeAttribute(attr);
|
|
48
|
+
}
|
|
59
49
|
}
|
|
60
|
-
/**
|
|
61
|
-
* Gets the list of IDs referenced by the given ARIA attribute on an element.
|
|
62
|
-
* Used for attributes such as aria-labelledby, aria-owns, etc.
|
|
63
|
-
*/
|
|
64
50
|
function getAriaReferenceIds(el, attr) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return attrValue?.match(/\S+/g) ?? [];
|
|
51
|
+
const attrValue = el.getAttribute(attr);
|
|
52
|
+
return attrValue?.match(/\S+/g) ?? [];
|
|
68
53
|
}
|
|
69
54
|
|
|
70
|
-
/**
|
|
71
|
-
* ID used for the body container where all messages are appended.
|
|
72
|
-
* @deprecated No longer being used. To be removed.
|
|
73
|
-
* @breaking-change 14.0.0
|
|
74
|
-
*/
|
|
75
55
|
const MESSAGES_CONTAINER_ID = 'cdk-describedby-message-container';
|
|
76
|
-
/**
|
|
77
|
-
* ID prefix used for each created message element.
|
|
78
|
-
* @deprecated To be turned into a private variable.
|
|
79
|
-
* @breaking-change 14.0.0
|
|
80
|
-
*/
|
|
81
56
|
const CDK_DESCRIBEDBY_ID_PREFIX = 'cdk-describedby-message';
|
|
82
|
-
/**
|
|
83
|
-
* Attribute given to each host element that is described by a message element.
|
|
84
|
-
* @deprecated To be turned into a private variable.
|
|
85
|
-
* @breaking-change 14.0.0
|
|
86
|
-
*/
|
|
87
57
|
const CDK_DESCRIBEDBY_HOST_ATTRIBUTE = 'cdk-describedby-host';
|
|
88
|
-
/** Global incremental identifier for each registered message element. */
|
|
89
58
|
let nextId = 0;
|
|
90
|
-
/**
|
|
91
|
-
* Utility that creates visually hidden elements with a message content. Useful for elements that
|
|
92
|
-
* want to use aria-describedby to further describe themselves without adding additional visual
|
|
93
|
-
* content.
|
|
94
|
-
*/
|
|
95
59
|
class AriaDescriber {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
_id =
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
return !!messageId && referenceIds.indexOf(messageId) != -1;
|
|
241
|
-
}
|
|
242
|
-
/** Determines whether a message can be described on a particular element. */
|
|
243
|
-
_canBeDescribed(element, message) {
|
|
244
|
-
if (!this._isElementNode(element)) {
|
|
245
|
-
return false;
|
|
246
|
-
}
|
|
247
|
-
if (message && typeof message === 'object') {
|
|
248
|
-
// We'd have to make some assumptions about the description element's text, if the consumer
|
|
249
|
-
// passed in an element. Assume that if an element is passed in, the consumer has verified
|
|
250
|
-
// that it can be used as a description.
|
|
251
|
-
return true;
|
|
252
|
-
}
|
|
253
|
-
const trimmedMessage = message == null ? '' : `${message}`.trim();
|
|
254
|
-
const ariaLabel = element.getAttribute('aria-label');
|
|
255
|
-
// We shouldn't set descriptions if they're exactly the same as the `aria-label` of the
|
|
256
|
-
// element, because screen readers will end up reading out the same text twice in a row.
|
|
257
|
-
return trimmedMessage ? !ariaLabel || ariaLabel.trim() !== trimmedMessage : false;
|
|
258
|
-
}
|
|
259
|
-
/** Checks whether a node is an Element node. */
|
|
260
|
-
_isElementNode(element) {
|
|
261
|
-
return element.nodeType === this._document.ELEMENT_NODE;
|
|
262
|
-
}
|
|
263
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: AriaDescriber, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
264
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: AriaDescriber, providedIn: 'root' });
|
|
60
|
+
_platform = inject(Platform);
|
|
61
|
+
_document = inject(DOCUMENT);
|
|
62
|
+
_messageRegistry = new Map();
|
|
63
|
+
_messagesContainer = null;
|
|
64
|
+
_id = `${nextId++}`;
|
|
65
|
+
constructor() {
|
|
66
|
+
inject(_CdkPrivateStyleLoader).load(_VisuallyHiddenLoader);
|
|
67
|
+
this._id = inject(APP_ID) + '-' + nextId++;
|
|
68
|
+
}
|
|
69
|
+
describe(hostElement, message, role) {
|
|
70
|
+
if (!this._canBeDescribed(hostElement, message)) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const key = getKey(message, role);
|
|
74
|
+
if (typeof message !== 'string') {
|
|
75
|
+
setMessageId(message, this._id);
|
|
76
|
+
this._messageRegistry.set(key, {
|
|
77
|
+
messageElement: message,
|
|
78
|
+
referenceCount: 0
|
|
79
|
+
});
|
|
80
|
+
} else if (!this._messageRegistry.has(key)) {
|
|
81
|
+
this._createMessageElement(message, role);
|
|
82
|
+
}
|
|
83
|
+
if (!this._isElementDescribedByMessage(hostElement, key)) {
|
|
84
|
+
this._addMessageReference(hostElement, key);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
removeDescription(hostElement, message, role) {
|
|
88
|
+
if (!message || !this._isElementNode(hostElement)) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const key = getKey(message, role);
|
|
92
|
+
if (this._isElementDescribedByMessage(hostElement, key)) {
|
|
93
|
+
this._removeMessageReference(hostElement, key);
|
|
94
|
+
}
|
|
95
|
+
if (typeof message === 'string') {
|
|
96
|
+
const registeredMessage = this._messageRegistry.get(key);
|
|
97
|
+
if (registeredMessage && registeredMessage.referenceCount === 0) {
|
|
98
|
+
this._deleteMessageElement(key);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (this._messagesContainer?.childNodes.length === 0) {
|
|
102
|
+
this._messagesContainer.remove();
|
|
103
|
+
this._messagesContainer = null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
ngOnDestroy() {
|
|
107
|
+
const describedElements = this._document.querySelectorAll(`[${CDK_DESCRIBEDBY_HOST_ATTRIBUTE}="${this._id}"]`);
|
|
108
|
+
for (let i = 0; i < describedElements.length; i++) {
|
|
109
|
+
this._removeCdkDescribedByReferenceIds(describedElements[i]);
|
|
110
|
+
describedElements[i].removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE);
|
|
111
|
+
}
|
|
112
|
+
this._messagesContainer?.remove();
|
|
113
|
+
this._messagesContainer = null;
|
|
114
|
+
this._messageRegistry.clear();
|
|
115
|
+
}
|
|
116
|
+
_createMessageElement(message, role) {
|
|
117
|
+
const messageElement = this._document.createElement('div');
|
|
118
|
+
setMessageId(messageElement, this._id);
|
|
119
|
+
messageElement.textContent = message;
|
|
120
|
+
if (role) {
|
|
121
|
+
messageElement.setAttribute('role', role);
|
|
122
|
+
}
|
|
123
|
+
this._createMessagesContainer();
|
|
124
|
+
this._messagesContainer.appendChild(messageElement);
|
|
125
|
+
this._messageRegistry.set(getKey(message, role), {
|
|
126
|
+
messageElement,
|
|
127
|
+
referenceCount: 0
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
_deleteMessageElement(key) {
|
|
131
|
+
this._messageRegistry.get(key)?.messageElement?.remove();
|
|
132
|
+
this._messageRegistry.delete(key);
|
|
133
|
+
}
|
|
134
|
+
_createMessagesContainer() {
|
|
135
|
+
if (this._messagesContainer) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const containerClassName = 'cdk-describedby-message-container';
|
|
139
|
+
const serverContainers = this._document.querySelectorAll(`.${containerClassName}[platform="server"]`);
|
|
140
|
+
for (let i = 0; i < serverContainers.length; i++) {
|
|
141
|
+
serverContainers[i].remove();
|
|
142
|
+
}
|
|
143
|
+
const messagesContainer = this._document.createElement('div');
|
|
144
|
+
messagesContainer.style.visibility = 'hidden';
|
|
145
|
+
messagesContainer.classList.add(containerClassName);
|
|
146
|
+
messagesContainer.classList.add('cdk-visually-hidden');
|
|
147
|
+
if (!this._platform.isBrowser) {
|
|
148
|
+
messagesContainer.setAttribute('platform', 'server');
|
|
149
|
+
}
|
|
150
|
+
this._document.body.appendChild(messagesContainer);
|
|
151
|
+
this._messagesContainer = messagesContainer;
|
|
152
|
+
}
|
|
153
|
+
_removeCdkDescribedByReferenceIds(element) {
|
|
154
|
+
const originalReferenceIds = getAriaReferenceIds(element, 'aria-describedby').filter(id => id.indexOf(CDK_DESCRIBEDBY_ID_PREFIX) != 0);
|
|
155
|
+
element.setAttribute('aria-describedby', originalReferenceIds.join(' '));
|
|
156
|
+
}
|
|
157
|
+
_addMessageReference(element, key) {
|
|
158
|
+
const registeredMessage = this._messageRegistry.get(key);
|
|
159
|
+
addAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id);
|
|
160
|
+
element.setAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE, this._id);
|
|
161
|
+
registeredMessage.referenceCount++;
|
|
162
|
+
}
|
|
163
|
+
_removeMessageReference(element, key) {
|
|
164
|
+
const registeredMessage = this._messageRegistry.get(key);
|
|
165
|
+
registeredMessage.referenceCount--;
|
|
166
|
+
removeAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id);
|
|
167
|
+
element.removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE);
|
|
168
|
+
}
|
|
169
|
+
_isElementDescribedByMessage(element, key) {
|
|
170
|
+
const referenceIds = getAriaReferenceIds(element, 'aria-describedby');
|
|
171
|
+
const registeredMessage = this._messageRegistry.get(key);
|
|
172
|
+
const messageId = registeredMessage && registeredMessage.messageElement.id;
|
|
173
|
+
return !!messageId && referenceIds.indexOf(messageId) != -1;
|
|
174
|
+
}
|
|
175
|
+
_canBeDescribed(element, message) {
|
|
176
|
+
if (!this._isElementNode(element)) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
if (message && typeof message === 'object') {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
const trimmedMessage = message == null ? '' : `${message}`.trim();
|
|
183
|
+
const ariaLabel = element.getAttribute('aria-label');
|
|
184
|
+
return trimmedMessage ? !ariaLabel || ariaLabel.trim() !== trimmedMessage : false;
|
|
185
|
+
}
|
|
186
|
+
_isElementNode(element) {
|
|
187
|
+
return element.nodeType === this._document.ELEMENT_NODE;
|
|
188
|
+
}
|
|
189
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
190
|
+
minVersion: "12.0.0",
|
|
191
|
+
version: "20.2.0-next.2",
|
|
192
|
+
ngImport: i0,
|
|
193
|
+
type: AriaDescriber,
|
|
194
|
+
deps: [],
|
|
195
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
196
|
+
});
|
|
197
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
198
|
+
minVersion: "12.0.0",
|
|
199
|
+
version: "20.2.0-next.2",
|
|
200
|
+
ngImport: i0,
|
|
201
|
+
type: AriaDescriber,
|
|
202
|
+
providedIn: 'root'
|
|
203
|
+
});
|
|
265
204
|
}
|
|
266
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
205
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
206
|
+
minVersion: "12.0.0",
|
|
207
|
+
version: "20.2.0-next.2",
|
|
208
|
+
ngImport: i0,
|
|
209
|
+
type: AriaDescriber,
|
|
210
|
+
decorators: [{
|
|
211
|
+
type: Injectable,
|
|
212
|
+
args: [{
|
|
213
|
+
providedIn: 'root'
|
|
214
|
+
}]
|
|
215
|
+
}],
|
|
216
|
+
ctorParameters: () => []
|
|
217
|
+
});
|
|
271
218
|
function getKey(message, role) {
|
|
272
|
-
|
|
219
|
+
return typeof message === 'string' ? `${role || ''}/${message}` : message;
|
|
273
220
|
}
|
|
274
|
-
/** Assigns a unique ID to an element, if it doesn't have one already. */
|
|
275
221
|
function setMessageId(element, serviceId) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
222
|
+
if (!element.id) {
|
|
223
|
+
element.id = `${CDK_DESCRIBEDBY_ID_PREFIX}-${serviceId}-${nextId++}`;
|
|
224
|
+
}
|
|
279
225
|
}
|
|
280
226
|
|
|
281
|
-
// NoopTreeKeyManager is a "noop" implementation of TreeKeyMangerStrategy. Methods are noops. Does
|
|
282
|
-
// not emit to streams.
|
|
283
|
-
//
|
|
284
|
-
// Used for applications built before TreeKeyManager to opt-out of TreeKeyManager and revert to
|
|
285
|
-
// legacy behavior.
|
|
286
|
-
/**
|
|
287
|
-
* @docs-private
|
|
288
|
-
*
|
|
289
|
-
* Opt-out of Tree of key manager behavior.
|
|
290
|
-
*
|
|
291
|
-
* When provided, Tree has same focus management behavior as before TreeKeyManager was introduced.
|
|
292
|
-
* - Tree does not respond to keyboard interaction
|
|
293
|
-
* - Tree node allows tabindex to be set by Input binding
|
|
294
|
-
* - Tree node allows tabindex to be set by attribute binding
|
|
295
|
-
*
|
|
296
|
-
* @deprecated NoopTreeKeyManager deprecated. Use TreeKeyManager or inject a
|
|
297
|
-
* TreeKeyManagerStrategy instead. To be removed in a future version.
|
|
298
|
-
*
|
|
299
|
-
* @breaking-change 21.0.0
|
|
300
|
-
*/
|
|
301
227
|
class NoopTreeKeyManager {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
change
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
return null;
|
|
316
|
-
}
|
|
317
|
-
getActiveItem() {
|
|
318
|
-
// Always return null. NoopTreeKeyManager is a "noop" implementation that does not maintain
|
|
319
|
-
// the active item.
|
|
320
|
-
return null;
|
|
321
|
-
}
|
|
322
|
-
focusItem() {
|
|
323
|
-
// noop
|
|
324
|
-
}
|
|
228
|
+
_isNoopTreeKeyManager = true;
|
|
229
|
+
change = new Subject();
|
|
230
|
+
destroy() {
|
|
231
|
+
this.change.complete();
|
|
232
|
+
}
|
|
233
|
+
onKeydown() {}
|
|
234
|
+
getActiveItemIndex() {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
getActiveItem() {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
focusItem() {}
|
|
325
241
|
}
|
|
326
|
-
/**
|
|
327
|
-
* @docs-private
|
|
328
|
-
*
|
|
329
|
-
* Opt-out of Tree of key manager behavior.
|
|
330
|
-
*
|
|
331
|
-
* When provided, Tree has same focus management behavior as before TreeKeyManager was introduced.
|
|
332
|
-
* - Tree does not respond to keyboard interaction
|
|
333
|
-
* - Tree node allows tabindex to be set by Input binding
|
|
334
|
-
* - Tree node allows tabindex to be set by attribute binding
|
|
335
|
-
*
|
|
336
|
-
* @deprecated NoopTreeKeyManager deprecated. Use TreeKeyManager or inject a
|
|
337
|
-
* TreeKeyManagerStrategy instead. To be removed in a future version.
|
|
338
|
-
*
|
|
339
|
-
* @breaking-change 21.0.0
|
|
340
|
-
*/
|
|
341
242
|
const NOOP_TREE_KEY_MANAGER_FACTORY_PROVIDER = {
|
|
342
|
-
|
|
343
|
-
|
|
243
|
+
provide: TREE_KEY_MANAGER,
|
|
244
|
+
useFactory: () => () => new NoopTreeKeyManager()
|
|
344
245
|
};
|
|
345
246
|
|
|
346
|
-
/**
|
|
347
|
-
* Class that allows for trapping focus within a DOM element.
|
|
348
|
-
*
|
|
349
|
-
* This class uses a strategy pattern that determines how it traps focus.
|
|
350
|
-
* See FocusTrapInertStrategy.
|
|
351
|
-
*/
|
|
352
247
|
class ConfigurableFocusTrap extends FocusTrap {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
/** @docs-private Implemented as part of ManagedFocusTrap. */
|
|
385
|
-
_disable() {
|
|
386
|
-
this._inertStrategy.allowFocus(this);
|
|
387
|
-
this.toggleAnchors(false);
|
|
388
|
-
}
|
|
248
|
+
_focusTrapManager;
|
|
249
|
+
_inertStrategy;
|
|
250
|
+
get enabled() {
|
|
251
|
+
return this._enabled;
|
|
252
|
+
}
|
|
253
|
+
set enabled(value) {
|
|
254
|
+
this._enabled = value;
|
|
255
|
+
if (this._enabled) {
|
|
256
|
+
this._focusTrapManager.register(this);
|
|
257
|
+
} else {
|
|
258
|
+
this._focusTrapManager.deregister(this);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
constructor(_element, _checker, _ngZone, _document, _focusTrapManager, _inertStrategy, config, injector) {
|
|
262
|
+
super(_element, _checker, _ngZone, _document, config.defer, injector);
|
|
263
|
+
this._focusTrapManager = _focusTrapManager;
|
|
264
|
+
this._inertStrategy = _inertStrategy;
|
|
265
|
+
this._focusTrapManager.register(this);
|
|
266
|
+
}
|
|
267
|
+
destroy() {
|
|
268
|
+
this._focusTrapManager.deregister(this);
|
|
269
|
+
super.destroy();
|
|
270
|
+
}
|
|
271
|
+
_enable() {
|
|
272
|
+
this._inertStrategy.preventFocus(this);
|
|
273
|
+
this.toggleAnchors(true);
|
|
274
|
+
}
|
|
275
|
+
_disable() {
|
|
276
|
+
this._inertStrategy.allowFocus(this);
|
|
277
|
+
this.toggleAnchors(false);
|
|
278
|
+
}
|
|
389
279
|
}
|
|
390
280
|
|
|
391
|
-
/**
|
|
392
|
-
* Lightweight FocusTrapInertStrategy that adds a document focus event
|
|
393
|
-
* listener to redirect focus back inside the FocusTrap.
|
|
394
|
-
*/
|
|
395
281
|
class EventListenerFocusTrapInertStrategy {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
*
|
|
421
|
-
* This is an event listener callback. The event listener is added in runOutsideAngular,
|
|
422
|
-
* so all this code runs outside Angular as well.
|
|
423
|
-
*/
|
|
424
|
-
_trapFocus(focusTrap, event) {
|
|
425
|
-
const target = event.target;
|
|
426
|
-
const focusTrapRoot = focusTrap._element;
|
|
427
|
-
// Don't refocus if target was in an overlay, because the overlay might be associated
|
|
428
|
-
// with an element inside the FocusTrap, ex. mat-select.
|
|
429
|
-
if (target && !focusTrapRoot.contains(target) && !target.closest?.('div.cdk-overlay-pane')) {
|
|
430
|
-
// Some legacy FocusTrap usages have logic that focuses some element on the page
|
|
431
|
-
// just before FocusTrap is destroyed. For backwards compatibility, wait
|
|
432
|
-
// to be sure FocusTrap is still enabled before refocusing.
|
|
433
|
-
setTimeout(() => {
|
|
434
|
-
// Check whether focus wasn't put back into the focus trap while the timeout was pending.
|
|
435
|
-
if (focusTrap.enabled && !focusTrapRoot.contains(focusTrap._document.activeElement)) {
|
|
436
|
-
focusTrap.focusFirstTabbableElement();
|
|
437
|
-
}
|
|
438
|
-
});
|
|
282
|
+
_listener = null;
|
|
283
|
+
preventFocus(focusTrap) {
|
|
284
|
+
if (this._listener) {
|
|
285
|
+
focusTrap._document.removeEventListener('focus', this._listener, true);
|
|
286
|
+
}
|
|
287
|
+
this._listener = e => this._trapFocus(focusTrap, e);
|
|
288
|
+
focusTrap._ngZone.runOutsideAngular(() => {
|
|
289
|
+
focusTrap._document.addEventListener('focus', this._listener, true);
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
allowFocus(focusTrap) {
|
|
293
|
+
if (!this._listener) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
focusTrap._document.removeEventListener('focus', this._listener, true);
|
|
297
|
+
this._listener = null;
|
|
298
|
+
}
|
|
299
|
+
_trapFocus(focusTrap, event) {
|
|
300
|
+
const target = event.target;
|
|
301
|
+
const focusTrapRoot = focusTrap._element;
|
|
302
|
+
if (target && !focusTrapRoot.contains(target) && !target.closest?.('div.cdk-overlay-pane')) {
|
|
303
|
+
setTimeout(() => {
|
|
304
|
+
if (focusTrap.enabled && !focusTrapRoot.contains(focusTrap._document.activeElement)) {
|
|
305
|
+
focusTrap.focusFirstTabbableElement();
|
|
439
306
|
}
|
|
307
|
+
});
|
|
440
308
|
}
|
|
309
|
+
}
|
|
441
310
|
}
|
|
442
311
|
|
|
443
|
-
/** The injection token used to specify the inert strategy. */
|
|
444
312
|
const FOCUS_TRAP_INERT_STRATEGY = new InjectionToken('FOCUS_TRAP_INERT_STRATEGY');
|
|
445
313
|
|
|
446
|
-
/** Injectable that ensures only the most recently enabled FocusTrap is active. */
|
|
447
314
|
class FocusTrapManager {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
_focusTrapStack =
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
315
|
+
_focusTrapStack = [];
|
|
316
|
+
register(focusTrap) {
|
|
317
|
+
this._focusTrapStack = this._focusTrapStack.filter(ft => ft !== focusTrap);
|
|
318
|
+
let stack = this._focusTrapStack;
|
|
319
|
+
if (stack.length) {
|
|
320
|
+
stack[stack.length - 1]._disable();
|
|
321
|
+
}
|
|
322
|
+
stack.push(focusTrap);
|
|
323
|
+
focusTrap._enable();
|
|
324
|
+
}
|
|
325
|
+
deregister(focusTrap) {
|
|
326
|
+
focusTrap._disable();
|
|
327
|
+
const stack = this._focusTrapStack;
|
|
328
|
+
const i = stack.indexOf(focusTrap);
|
|
329
|
+
if (i !== -1) {
|
|
330
|
+
stack.splice(i, 1);
|
|
331
|
+
if (stack.length) {
|
|
332
|
+
stack[stack.length - 1]._enable();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
337
|
+
minVersion: "12.0.0",
|
|
338
|
+
version: "20.2.0-next.2",
|
|
339
|
+
ngImport: i0,
|
|
340
|
+
type: FocusTrapManager,
|
|
341
|
+
deps: [],
|
|
342
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
343
|
+
});
|
|
344
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
345
|
+
minVersion: "12.0.0",
|
|
346
|
+
version: "20.2.0-next.2",
|
|
347
|
+
ngImport: i0,
|
|
348
|
+
type: FocusTrapManager,
|
|
349
|
+
providedIn: 'root'
|
|
350
|
+
});
|
|
482
351
|
}
|
|
483
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
352
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
353
|
+
minVersion: "12.0.0",
|
|
354
|
+
version: "20.2.0-next.2",
|
|
355
|
+
ngImport: i0,
|
|
356
|
+
type: FocusTrapManager,
|
|
357
|
+
decorators: [{
|
|
358
|
+
type: Injectable,
|
|
359
|
+
args: [{
|
|
360
|
+
providedIn: 'root'
|
|
361
|
+
}]
|
|
362
|
+
}]
|
|
363
|
+
});
|
|
487
364
|
|
|
488
|
-
/** Factory that allows easy instantiation of configurable focus traps. */
|
|
489
365
|
class ConfigurableFocusTrapFactory {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
|
|
366
|
+
_checker = inject(InteractivityChecker);
|
|
367
|
+
_ngZone = inject(NgZone);
|
|
368
|
+
_focusTrapManager = inject(FocusTrapManager);
|
|
369
|
+
_document = inject(DOCUMENT);
|
|
370
|
+
_inertStrategy;
|
|
371
|
+
_injector = inject(Injector);
|
|
372
|
+
constructor() {
|
|
373
|
+
const inertStrategy = inject(FOCUS_TRAP_INERT_STRATEGY, {
|
|
374
|
+
optional: true
|
|
375
|
+
});
|
|
376
|
+
this._inertStrategy = inertStrategy || new EventListenerFocusTrapInertStrategy();
|
|
377
|
+
}
|
|
378
|
+
create(element, config = {
|
|
379
|
+
defer: false
|
|
380
|
+
}) {
|
|
381
|
+
let configObject;
|
|
382
|
+
if (typeof config === 'boolean') {
|
|
383
|
+
configObject = {
|
|
384
|
+
defer: config
|
|
385
|
+
};
|
|
386
|
+
} else {
|
|
387
|
+
configObject = config;
|
|
388
|
+
}
|
|
389
|
+
return new ConfigurableFocusTrap(element, this._checker, this._ngZone, this._document, this._focusTrapManager, this._inertStrategy, configObject, this._injector);
|
|
390
|
+
}
|
|
391
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
392
|
+
minVersion: "12.0.0",
|
|
393
|
+
version: "20.2.0-next.2",
|
|
394
|
+
ngImport: i0,
|
|
395
|
+
type: ConfigurableFocusTrapFactory,
|
|
396
|
+
deps: [],
|
|
397
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
398
|
+
});
|
|
399
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
400
|
+
minVersion: "12.0.0",
|
|
401
|
+
version: "20.2.0-next.2",
|
|
402
|
+
ngImport: i0,
|
|
403
|
+
type: ConfigurableFocusTrapFactory,
|
|
404
|
+
providedIn: 'root'
|
|
405
|
+
});
|
|
513
406
|
}
|
|
514
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
407
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
408
|
+
minVersion: "12.0.0",
|
|
409
|
+
version: "20.2.0-next.2",
|
|
410
|
+
ngImport: i0,
|
|
411
|
+
type: ConfigurableFocusTrapFactory,
|
|
412
|
+
decorators: [{
|
|
413
|
+
type: Injectable,
|
|
414
|
+
args: [{
|
|
415
|
+
providedIn: 'root'
|
|
416
|
+
}]
|
|
417
|
+
}],
|
|
418
|
+
ctorParameters: () => []
|
|
419
|
+
});
|
|
518
420
|
|
|
519
421
|
export { AriaDescriber, CDK_DESCRIBEDBY_HOST_ATTRIBUTE, CDK_DESCRIBEDBY_ID_PREFIX, ConfigurableFocusTrap, ConfigurableFocusTrapFactory, EventListenerFocusTrapInertStrategy, FOCUS_TRAP_INERT_STRATEGY, FocusTrap, InteractivityChecker, MESSAGES_CONTAINER_ID, NOOP_TREE_KEY_MANAGER_FACTORY_PROVIDER, NoopTreeKeyManager, TREE_KEY_MANAGER, addAriaReferencedId, getAriaReferenceIds, removeAriaReferencedId };
|
|
520
422
|
//# sourceMappingURL=a11y.mjs.map
|