@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.
Files changed (124) hide show
  1. package/_adev_assets/cdk_drag_drop.json +13 -12
  2. package/_adev_assets/cdk_testing.json +15 -25
  3. package/_adev_assets/cdk_testing_protractor.json +1 -1
  4. package/_adev_assets/cdk_testing_selenium_webdriver.json +1 -1
  5. package/_adev_assets/cdk_testing_testbed.json +1 -1
  6. package/fesm2022/_a11y-module-chunk.mjs +755 -869
  7. package/fesm2022/_a11y-module-chunk.mjs.map +1 -1
  8. package/fesm2022/_activedescendant-key-manager-chunk.mjs +8 -8
  9. package/fesm2022/_activedescendant-key-manager-chunk.mjs.map +1 -1
  10. package/fesm2022/_array-chunk.mjs +1 -1
  11. package/fesm2022/_array-chunk.mjs.map +1 -1
  12. package/fesm2022/_breakpoints-observer-chunk.mjs +149 -152
  13. package/fesm2022/_breakpoints-observer-chunk.mjs.map +1 -1
  14. package/fesm2022/_css-pixel-value-chunk.mjs +4 -5
  15. package/fesm2022/_css-pixel-value-chunk.mjs.map +1 -1
  16. package/fesm2022/_data-source-chunk.mjs +2 -8
  17. package/fesm2022/_data-source-chunk.mjs.map +1 -1
  18. package/fesm2022/_directionality-chunk.mjs +54 -54
  19. package/fesm2022/_directionality-chunk.mjs.map +1 -1
  20. package/fesm2022/_dispose-view-repeater-strategy-chunk.mjs +25 -36
  21. package/fesm2022/_dispose-view-repeater-strategy-chunk.mjs.map +1 -1
  22. package/fesm2022/_element-chunk.mjs +6 -17
  23. package/fesm2022/_element-chunk.mjs.map +1 -1
  24. package/fesm2022/_fake-event-detection-chunk.mjs +3 -17
  25. package/fesm2022/_fake-event-detection-chunk.mjs.map +1 -1
  26. package/fesm2022/_focus-key-manager-chunk.mjs +10 -14
  27. package/fesm2022/_focus-key-manager-chunk.mjs.map +1 -1
  28. package/fesm2022/_focus-monitor-chunk.mjs +376 -566
  29. package/fesm2022/_focus-monitor-chunk.mjs.map +1 -1
  30. package/fesm2022/_id-generator-chunk.mjs +36 -27
  31. package/fesm2022/_id-generator-chunk.mjs.map +1 -1
  32. package/fesm2022/_keycodes-chunk.mjs +9 -9
  33. package/fesm2022/_keycodes-chunk.mjs.map +1 -1
  34. package/fesm2022/_list-key-manager-chunk.mjs +248 -336
  35. package/fesm2022/_list-key-manager-chunk.mjs.map +1 -1
  36. package/fesm2022/_overlay-module-chunk.mjs +2534 -2948
  37. package/fesm2022/_overlay-module-chunk.mjs.map +1 -1
  38. package/fesm2022/_passive-listeners-chunk.mjs +10 -22
  39. package/fesm2022/_passive-listeners-chunk.mjs.map +1 -1
  40. package/fesm2022/_platform-chunk.mjs +42 -65
  41. package/fesm2022/_platform-chunk.mjs.map +1 -1
  42. package/fesm2022/_recycle-view-repeater-strategy-chunk.mjs +78 -134
  43. package/fesm2022/_recycle-view-repeater-strategy-chunk.mjs.map +1 -1
  44. package/fesm2022/_scrolling-chunk.mjs +44 -85
  45. package/fesm2022/_scrolling-chunk.mjs.map +1 -1
  46. package/fesm2022/_selection-model-chunk.mjs +138 -209
  47. package/fesm2022/_selection-model-chunk.mjs.map +1 -1
  48. package/fesm2022/_shadow-dom-chunk.mjs +21 -35
  49. package/fesm2022/_shadow-dom-chunk.mjs.map +1 -1
  50. package/fesm2022/_style-loader-chunk.mjs +50 -37
  51. package/fesm2022/_style-loader-chunk.mjs.map +1 -1
  52. package/fesm2022/_test-environment-chunk.mjs +2 -14
  53. package/fesm2022/_test-environment-chunk.mjs.map +1 -1
  54. package/fesm2022/_tree-key-manager-chunk.mjs +229 -308
  55. package/fesm2022/_tree-key-manager-chunk.mjs.map +1 -1
  56. package/fesm2022/_typeahead-chunk.mjs +52 -74
  57. package/fesm2022/_typeahead-chunk.mjs.map +1 -1
  58. package/fesm2022/_unique-selection-dispatcher-chunk.mjs +43 -40
  59. package/fesm2022/_unique-selection-dispatcher-chunk.mjs.map +1 -1
  60. package/fesm2022/a11y.mjs +351 -449
  61. package/fesm2022/a11y.mjs.map +1 -1
  62. package/fesm2022/accordion.mjs +254 -192
  63. package/fesm2022/accordion.mjs.map +1 -1
  64. package/fesm2022/bidi.mjs +121 -64
  65. package/fesm2022/bidi.mjs.map +1 -1
  66. package/fesm2022/cdk.mjs +1 -2
  67. package/fesm2022/cdk.mjs.map +1 -1
  68. package/fesm2022/clipboard.mjs +208 -186
  69. package/fesm2022/clipboard.mjs.map +1 -1
  70. package/fesm2022/coercion-private.mjs +4 -8
  71. package/fesm2022/coercion-private.mjs.map +1 -1
  72. package/fesm2022/coercion.mjs +11 -29
  73. package/fesm2022/coercion.mjs.map +1 -1
  74. package/fesm2022/dialog.mjs +660 -808
  75. package/fesm2022/dialog.mjs.map +1 -1
  76. package/fesm2022/drag-drop.mjs +3347 -4286
  77. package/fesm2022/drag-drop.mjs.map +1 -1
  78. package/fesm2022/keycodes.mjs +4 -8
  79. package/fesm2022/keycodes.mjs.map +1 -1
  80. package/fesm2022/layout.mjs +44 -26
  81. package/fesm2022/layout.mjs.map +1 -1
  82. package/fesm2022/listbox.mjs +841 -895
  83. package/fesm2022/listbox.mjs.map +1 -1
  84. package/fesm2022/menu.mjs +1942 -1858
  85. package/fesm2022/menu.mjs.map +1 -1
  86. package/fesm2022/observers-private.mjs +88 -106
  87. package/fesm2022/observers-private.mjs.map +1 -1
  88. package/fesm2022/observers.mjs +262 -184
  89. package/fesm2022/observers.mjs.map +1 -1
  90. package/fesm2022/overlay.mjs +72 -68
  91. package/fesm2022/overlay.mjs.map +1 -1
  92. package/fesm2022/platform.mjs +43 -54
  93. package/fesm2022/platform.mjs.map +1 -1
  94. package/fesm2022/portal.mjs +402 -560
  95. package/fesm2022/portal.mjs.map +1 -1
  96. package/fesm2022/private.mjs +38 -10
  97. package/fesm2022/private.mjs.map +1 -1
  98. package/fesm2022/scrolling.mjs +1323 -1400
  99. package/fesm2022/scrolling.mjs.map +1 -1
  100. package/fesm2022/stepper.mjs +758 -590
  101. package/fesm2022/stepper.mjs.map +1 -1
  102. package/fesm2022/table.mjs +2327 -2319
  103. package/fesm2022/table.mjs.map +1 -1
  104. package/fesm2022/testing-selenium-webdriver.mjs +252 -325
  105. package/fesm2022/testing-selenium-webdriver.mjs.map +1 -1
  106. package/fesm2022/testing-testbed.mjs +592 -709
  107. package/fesm2022/testing-testbed.mjs.map +1 -1
  108. package/fesm2022/testing.mjs +368 -889
  109. package/fesm2022/testing.mjs.map +1 -1
  110. package/fesm2022/text-field.mjs +459 -388
  111. package/fesm2022/text-field.mjs.map +1 -1
  112. package/fesm2022/tree.mjs +1483 -1731
  113. package/fesm2022/tree.mjs.map +1 -1
  114. package/overlay/_index.scss +28 -0
  115. package/overlay-prebuilt.css +1 -1
  116. package/package.json +1 -1
  117. package/schematics/ng-add/index.js +1 -1
  118. package/types/_harness-environment-chunk.d.ts +1 -2
  119. package/types/_overlay-module-chunk.d.ts +59 -7
  120. package/types/_portal-directives-chunk.d.ts +2 -18
  121. package/types/accordion.d.ts +3 -1
  122. package/types/dialog.d.ts +1 -1
  123. package/types/overlay.d.ts +6 -2
  124. 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
- const ids = getAriaReferenceIds(el, attr);
38
- id = id.trim();
39
- if (ids.some(existingId => existingId.trim() === id)) {
40
- return;
41
- }
42
- ids.push(id);
43
- el.setAttribute(attr, ids.join(ID_DELIMITER));
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
- const ids = getAriaReferenceIds(el, attr);
51
- id = id.trim();
52
- const filteredIds = ids.filter(val => val !== id);
53
- if (filteredIds.length) {
54
- el.setAttribute(attr, filteredIds.join(ID_DELIMITER));
55
- }
56
- else {
57
- el.removeAttribute(attr);
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
- // Get string array of all individual ids (whitespace delimited) in the attribute value
66
- const attrValue = el.getAttribute(attr);
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
- _platform = inject(Platform);
97
- _document = inject(DOCUMENT);
98
- /** Map of all registered message elements that have been placed into the document. */
99
- _messageRegistry = new Map();
100
- /** Container for all registered messages. */
101
- _messagesContainer = null;
102
- /** Unique ID for the service. */
103
- _id = `${nextId++}`;
104
- constructor() {
105
- inject(_CdkPrivateStyleLoader).load(_VisuallyHiddenLoader);
106
- this._id = inject(APP_ID) + '-' + nextId++;
107
- }
108
- describe(hostElement, message, role) {
109
- if (!this._canBeDescribed(hostElement, message)) {
110
- return;
111
- }
112
- const key = getKey(message, role);
113
- if (typeof message !== 'string') {
114
- // We need to ensure that the element has an ID.
115
- setMessageId(message, this._id);
116
- this._messageRegistry.set(key, { messageElement: message, referenceCount: 0 });
117
- }
118
- else if (!this._messageRegistry.has(key)) {
119
- this._createMessageElement(message, role);
120
- }
121
- if (!this._isElementDescribedByMessage(hostElement, key)) {
122
- this._addMessageReference(hostElement, key);
123
- }
124
- }
125
- removeDescription(hostElement, message, role) {
126
- if (!message || !this._isElementNode(hostElement)) {
127
- return;
128
- }
129
- const key = getKey(message, role);
130
- if (this._isElementDescribedByMessage(hostElement, key)) {
131
- this._removeMessageReference(hostElement, key);
132
- }
133
- // If the message is a string, it means that it's one that we created for the
134
- // consumer so we can remove it safely, otherwise we should leave it in place.
135
- if (typeof message === 'string') {
136
- const registeredMessage = this._messageRegistry.get(key);
137
- if (registeredMessage && registeredMessage.referenceCount === 0) {
138
- this._deleteMessageElement(key);
139
- }
140
- }
141
- if (this._messagesContainer?.childNodes.length === 0) {
142
- this._messagesContainer.remove();
143
- this._messagesContainer = null;
144
- }
145
- }
146
- /** Unregisters all created message elements and removes the message container. */
147
- ngOnDestroy() {
148
- const describedElements = this._document.querySelectorAll(`[${CDK_DESCRIBEDBY_HOST_ATTRIBUTE}="${this._id}"]`);
149
- for (let i = 0; i < describedElements.length; i++) {
150
- this._removeCdkDescribedByReferenceIds(describedElements[i]);
151
- describedElements[i].removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE);
152
- }
153
- this._messagesContainer?.remove();
154
- this._messagesContainer = null;
155
- this._messageRegistry.clear();
156
- }
157
- /**
158
- * Creates a new element in the visually hidden message container element with the message
159
- * as its content and adds it to the message registry.
160
- */
161
- _createMessageElement(message, role) {
162
- const messageElement = this._document.createElement('div');
163
- setMessageId(messageElement, this._id);
164
- messageElement.textContent = message;
165
- if (role) {
166
- messageElement.setAttribute('role', role);
167
- }
168
- this._createMessagesContainer();
169
- this._messagesContainer.appendChild(messageElement);
170
- this._messageRegistry.set(getKey(message, role), { messageElement, referenceCount: 0 });
171
- }
172
- /** Deletes the message element from the global messages container. */
173
- _deleteMessageElement(key) {
174
- this._messageRegistry.get(key)?.messageElement?.remove();
175
- this._messageRegistry.delete(key);
176
- }
177
- /** Creates the global container for all aria-describedby messages. */
178
- _createMessagesContainer() {
179
- if (this._messagesContainer) {
180
- return;
181
- }
182
- const containerClassName = 'cdk-describedby-message-container';
183
- const serverContainers = this._document.querySelectorAll(`.${containerClassName}[platform="server"]`);
184
- for (let i = 0; i < serverContainers.length; i++) {
185
- // When going from the server to the client, we may end up in a situation where there's
186
- // already a container on the page, but we don't have a reference to it. Clear the
187
- // old container so we don't get duplicates. Doing this, instead of emptying the previous
188
- // container, should be slightly faster.
189
- serverContainers[i].remove();
190
- }
191
- const messagesContainer = this._document.createElement('div');
192
- // We add `visibility: hidden` in order to prevent text in this container from
193
- // being searchable by the browser's Ctrl + F functionality.
194
- // Screen-readers will still read the description for elements with aria-describedby even
195
- // when the description element is not visible.
196
- messagesContainer.style.visibility = 'hidden';
197
- // Even though we use `visibility: hidden`, we still apply `cdk-visually-hidden` so that
198
- // the description element doesn't impact page layout.
199
- messagesContainer.classList.add(containerClassName);
200
- messagesContainer.classList.add('cdk-visually-hidden');
201
- if (!this._platform.isBrowser) {
202
- messagesContainer.setAttribute('platform', 'server');
203
- }
204
- this._document.body.appendChild(messagesContainer);
205
- this._messagesContainer = messagesContainer;
206
- }
207
- /** Removes all cdk-describedby messages that are hosted through the element. */
208
- _removeCdkDescribedByReferenceIds(element) {
209
- // Remove all aria-describedby reference IDs that are prefixed by CDK_DESCRIBEDBY_ID_PREFIX
210
- const originalReferenceIds = getAriaReferenceIds(element, 'aria-describedby').filter(id => id.indexOf(CDK_DESCRIBEDBY_ID_PREFIX) != 0);
211
- element.setAttribute('aria-describedby', originalReferenceIds.join(' '));
212
- }
213
- /**
214
- * Adds a message reference to the element using aria-describedby and increments the registered
215
- * message's reference count.
216
- */
217
- _addMessageReference(element, key) {
218
- const registeredMessage = this._messageRegistry.get(key);
219
- // Add the aria-describedby reference and set the
220
- // describedby_host attribute to mark the element.
221
- addAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id);
222
- element.setAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE, this._id);
223
- registeredMessage.referenceCount++;
224
- }
225
- /**
226
- * Removes a message reference from the element using aria-describedby
227
- * and decrements the registered message's reference count.
228
- */
229
- _removeMessageReference(element, key) {
230
- const registeredMessage = this._messageRegistry.get(key);
231
- registeredMessage.referenceCount--;
232
- removeAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id);
233
- element.removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE);
234
- }
235
- /** Returns true if the element has been described by the provided message ID. */
236
- _isElementDescribedByMessage(element, key) {
237
- const referenceIds = getAriaReferenceIds(element, 'aria-describedby');
238
- const registeredMessage = this._messageRegistry.get(key);
239
- const messageId = registeredMessage && registeredMessage.messageElement.id;
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({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: AriaDescriber, decorators: [{
267
- type: Injectable,
268
- args: [{ providedIn: 'root' }]
269
- }], ctorParameters: () => [] });
270
- /** Gets a key that can be used to look messages up in the registry. */
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
- return typeof message === 'string' ? `${role || ''}/${message}` : message;
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
- if (!element.id) {
277
- element.id = `${CDK_DESCRIBEDBY_ID_PREFIX}-${serviceId}-${nextId++}`;
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
- _isNoopTreeKeyManager = true;
303
- // Provide change as required by TreeKeyManagerStrategy. NoopTreeKeyManager is a "noop"
304
- // implementation that does not emit to streams.
305
- change = new Subject();
306
- destroy() {
307
- this.change.complete();
308
- }
309
- onKeydown() {
310
- // noop
311
- }
312
- getActiveItemIndex() {
313
- // Always return null. NoopTreeKeyManager is a "noop" implementation that does not maintain
314
- // the active item.
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
- provide: TREE_KEY_MANAGER,
343
- useFactory: () => () => new NoopTreeKeyManager(),
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
- _focusTrapManager;
354
- _inertStrategy;
355
- /** Whether the FocusTrap is enabled. */
356
- get enabled() {
357
- return this._enabled;
358
- }
359
- set enabled(value) {
360
- this._enabled = value;
361
- if (this._enabled) {
362
- this._focusTrapManager.register(this);
363
- }
364
- else {
365
- this._focusTrapManager.deregister(this);
366
- }
367
- }
368
- constructor(_element, _checker, _ngZone, _document, _focusTrapManager, _inertStrategy, config, injector) {
369
- super(_element, _checker, _ngZone, _document, config.defer, injector);
370
- this._focusTrapManager = _focusTrapManager;
371
- this._inertStrategy = _inertStrategy;
372
- this._focusTrapManager.register(this);
373
- }
374
- /** Notifies the FocusTrapManager that this FocusTrap will be destroyed. */
375
- destroy() {
376
- this._focusTrapManager.deregister(this);
377
- super.destroy();
378
- }
379
- /** @docs-private Implemented as part of ManagedFocusTrap. */
380
- _enable() {
381
- this._inertStrategy.preventFocus(this);
382
- this.toggleAnchors(true);
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
- /** Focus event handler. */
397
- _listener = null;
398
- /** Adds a document event listener that keeps focus inside the FocusTrap. */
399
- preventFocus(focusTrap) {
400
- // Ensure there's only one listener per document
401
- if (this._listener) {
402
- focusTrap._document.removeEventListener('focus', this._listener, true);
403
- }
404
- this._listener = (e) => this._trapFocus(focusTrap, e);
405
- focusTrap._ngZone.runOutsideAngular(() => {
406
- focusTrap._document.addEventListener('focus', this._listener, true);
407
- });
408
- }
409
- /** Removes the event listener added in preventFocus. */
410
- allowFocus(focusTrap) {
411
- if (!this._listener) {
412
- return;
413
- }
414
- focusTrap._document.removeEventListener('focus', this._listener, true);
415
- this._listener = null;
416
- }
417
- /**
418
- * Refocuses the first element in the FocusTrap if the focus event target was outside
419
- * the FocusTrap.
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
- // A stack of the FocusTraps on the page. Only the FocusTrap at the
449
- // top of the stack is active.
450
- _focusTrapStack = [];
451
- /**
452
- * Disables the FocusTrap at the top of the stack, and then pushes
453
- * the new FocusTrap onto the stack.
454
- */
455
- register(focusTrap) {
456
- // Dedupe focusTraps that register multiple times.
457
- this._focusTrapStack = this._focusTrapStack.filter(ft => ft !== focusTrap);
458
- let stack = this._focusTrapStack;
459
- if (stack.length) {
460
- stack[stack.length - 1]._disable();
461
- }
462
- stack.push(focusTrap);
463
- focusTrap._enable();
464
- }
465
- /**
466
- * Removes the FocusTrap from the stack, and activates the
467
- * FocusTrap that is the new top of the stack.
468
- */
469
- deregister(focusTrap) {
470
- focusTrap._disable();
471
- const stack = this._focusTrapStack;
472
- const i = stack.indexOf(focusTrap);
473
- if (i !== -1) {
474
- stack.splice(i, 1);
475
- if (stack.length) {
476
- stack[stack.length - 1]._enable();
477
- }
478
- }
479
- }
480
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FocusTrapManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
481
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FocusTrapManager, providedIn: 'root' });
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({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FocusTrapManager, decorators: [{
484
- type: Injectable,
485
- args: [{ providedIn: 'root' }]
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
- _checker = inject(InteractivityChecker);
491
- _ngZone = inject(NgZone);
492
- _focusTrapManager = inject(FocusTrapManager);
493
- _document = inject(DOCUMENT);
494
- _inertStrategy;
495
- _injector = inject(Injector);
496
- constructor() {
497
- const inertStrategy = inject(FOCUS_TRAP_INERT_STRATEGY, { optional: true });
498
- // TODO split up the strategies into different modules, similar to DateAdapter.
499
- this._inertStrategy = inertStrategy || new EventListenerFocusTrapInertStrategy();
500
- }
501
- create(element, config = { defer: false }) {
502
- let configObject;
503
- if (typeof config === 'boolean') {
504
- configObject = { defer: config };
505
- }
506
- else {
507
- configObject = config;
508
- }
509
- return new ConfigurableFocusTrap(element, this._checker, this._ngZone, this._document, this._focusTrapManager, this._inertStrategy, configObject, this._injector);
510
- }
511
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ConfigurableFocusTrapFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
512
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ConfigurableFocusTrapFactory, providedIn: 'root' });
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({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ConfigurableFocusTrapFactory, decorators: [{
515
- type: Injectable,
516
- args: [{ providedIn: 'root' }]
517
- }], ctorParameters: () => [] });
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