@angular/cdk 10.0.0-rc.3 → 10.1.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 (242) hide show
  1. package/a11y/aria-describer/aria-describer.d.ts +10 -1
  2. package/a11y/focus-trap/focus-trap.d.ts +4 -2
  3. package/a11y/index.metadata.json +1 -1
  4. package/a11y/interactivity-checker/interactivity-checker.d.ts +11 -1
  5. package/a11y/key-manager/list-key-manager.d.ts +6 -0
  6. package/accordion/accordion.d.ts +7 -1
  7. package/accordion/index.d.ts +1 -0
  8. package/accordion/index.metadata.json +1 -1
  9. package/bundles/cdk-a11y.umd.js +78 -15
  10. package/bundles/cdk-a11y.umd.js.map +1 -1
  11. package/bundles/cdk-a11y.umd.min.js +11 -11
  12. package/bundles/cdk-a11y.umd.min.js.map +1 -1
  13. package/bundles/cdk-accordion.umd.js +12 -4
  14. package/bundles/cdk-accordion.umd.js.map +1 -1
  15. package/bundles/cdk-accordion.umd.min.js +2 -2
  16. package/bundles/cdk-accordion.umd.min.js.map +1 -1
  17. package/bundles/cdk-drag-drop.umd.js +717 -641
  18. package/bundles/cdk-drag-drop.umd.js.map +1 -1
  19. package/bundles/cdk-drag-drop.umd.min.js +8 -16
  20. package/bundles/cdk-drag-drop.umd.min.js.map +1 -1
  21. package/bundles/cdk-overlay.umd.js +199 -42
  22. package/bundles/cdk-overlay.umd.js.map +1 -1
  23. package/bundles/cdk-overlay.umd.min.js +11 -18
  24. package/bundles/cdk-overlay.umd.min.js.map +1 -1
  25. package/bundles/cdk-platform.umd.js +0 -1
  26. package/bundles/cdk-platform.umd.js.map +1 -1
  27. package/bundles/cdk-platform.umd.min.js +2 -2
  28. package/bundles/cdk-platform.umd.min.js.map +1 -1
  29. package/bundles/cdk-scrolling.umd.js +26 -4
  30. package/bundles/cdk-scrolling.umd.js.map +1 -1
  31. package/bundles/cdk-scrolling.umd.min.js +11 -4
  32. package/bundles/cdk-scrolling.umd.min.js.map +1 -1
  33. package/bundles/cdk-testing-protractor.umd.min.js +1 -1
  34. package/bundles/cdk-testing-protractor.umd.min.js.map +1 -1
  35. package/bundles/cdk-testing-testbed.umd.min.js +8 -8
  36. package/bundles/cdk-testing-testbed.umd.min.js.map +1 -1
  37. package/bundles/cdk-testing.umd.js +32 -0
  38. package/bundles/cdk-testing.umd.js.map +1 -1
  39. package/bundles/cdk-testing.umd.min.js +5 -5
  40. package/bundles/cdk-testing.umd.min.js.map +1 -1
  41. package/bundles/cdk-tree.umd.js +6 -2
  42. package/bundles/cdk-tree.umd.js.map +1 -1
  43. package/bundles/cdk-tree.umd.min.js +3 -3
  44. package/bundles/cdk-tree.umd.min.js.map +1 -1
  45. package/bundles/cdk.umd.js +1 -1
  46. package/bundles/cdk.umd.js.map +1 -1
  47. package/bundles/cdk.umd.min.js +1 -1
  48. package/bundles/cdk.umd.min.js.map +1 -1
  49. package/drag-drop/directives/drag-handle.d.ts +7 -1
  50. package/drag-drop/directives/drag-placeholder.d.ts +7 -1
  51. package/drag-drop/directives/drag-preview.d.ts +7 -1
  52. package/drag-drop/directives/drag.d.ts +4 -14
  53. package/drag-drop/directives/drop-list-group.d.ts +7 -1
  54. package/drag-drop/directives/drop-list.d.ts +7 -1
  55. package/drag-drop/drag-ref.d.ts +6 -0
  56. package/drag-drop/drop-list-ref.d.ts +3 -2
  57. package/drag-drop/index.d.ts +2 -2
  58. package/drag-drop/index.metadata.json +1 -1
  59. package/esm2015/a11y/a11y-module.js +15 -19
  60. package/esm2015/a11y/aria-describer/aria-describer.js +177 -167
  61. package/esm2015/a11y/focus-monitor/focus-monitor.js +337 -345
  62. package/esm2015/a11y/focus-trap/configurable-focus-trap-factory.js +30 -34
  63. package/esm2015/a11y/focus-trap/focus-trap-manager.js +36 -40
  64. package/esm2015/a11y/focus-trap/focus-trap.js +85 -82
  65. package/esm2015/a11y/high-contrast-mode/high-contrast-mode-detector.js +56 -60
  66. package/esm2015/a11y/interactivity-checker/interactivity-checker.js +113 -104
  67. package/esm2015/a11y/key-manager/list-key-manager.js +29 -4
  68. package/esm2015/a11y/live-announcer/live-announcer.js +138 -146
  69. package/esm2015/accordion/accordion-item.js +119 -123
  70. package/esm2015/accordion/accordion-module.js +9 -13
  71. package/esm2015/accordion/accordion.js +49 -46
  72. package/esm2015/accordion/index.js +2 -1
  73. package/esm2015/bidi/bidi-module.js +9 -13
  74. package/esm2015/bidi/dir.js +41 -45
  75. package/esm2015/bidi/directionality.js +27 -31
  76. package/esm2015/clipboard/clipboard-module.js +9 -13
  77. package/esm2015/clipboard/clipboard.js +36 -40
  78. package/esm2015/clipboard/copy-to-clipboard.js +71 -75
  79. package/esm2015/collections/unique-selection-dispatcher.js +33 -37
  80. package/esm2015/drag-drop/directives/drag-handle.js +42 -39
  81. package/esm2015/drag-drop/directives/drag-placeholder.js +24 -21
  82. package/esm2015/drag-drop/directives/drag-preview.js +29 -26
  83. package/esm2015/drag-drop/directives/drag.js +313 -319
  84. package/esm2015/drag-drop/directives/drop-list-group.js +32 -29
  85. package/esm2015/drag-drop/directives/drop-list.js +251 -250
  86. package/esm2015/drag-drop/drag-drop-module.js +27 -31
  87. package/esm2015/drag-drop/drag-drop-registry.js +139 -143
  88. package/esm2015/drag-drop/drag-drop.js +33 -37
  89. package/esm2015/drag-drop/drag-ref.js +59 -25
  90. package/esm2015/drag-drop/drop-list-ref.js +15 -9
  91. package/esm2015/drag-drop/index.js +3 -2
  92. package/esm2015/layout/breakpoints-observer.js +81 -85
  93. package/esm2015/layout/layout-module.js +6 -10
  94. package/esm2015/layout/media-matcher.js +28 -32
  95. package/esm2015/observers/observe-content.js +147 -163
  96. package/esm2015/overlay/dispatchers/base-overlay-dispatcher.js +51 -0
  97. package/esm2015/overlay/dispatchers/index.js +10 -0
  98. package/esm2015/overlay/dispatchers/overlay-keyboard-dispatcher.js +79 -0
  99. package/esm2015/overlay/dispatchers/overlay-outside-click-dispatcher.js +94 -0
  100. package/esm2015/overlay/fullscreen-overlay-container.js +70 -74
  101. package/esm2015/overlay/index.js +5 -4
  102. package/esm2015/overlay/overlay-config.js +5 -1
  103. package/esm2015/overlay/overlay-container.js +69 -73
  104. package/esm2015/overlay/overlay-directives.js +245 -243
  105. package/esm2015/overlay/overlay-module.js +15 -19
  106. package/esm2015/overlay/overlay-ref.js +24 -2
  107. package/esm2015/overlay/overlay-reference.js +1 -1
  108. package/esm2015/overlay/overlay.js +93 -92
  109. package/esm2015/overlay/position/connected-position.js +14 -18
  110. package/esm2015/overlay/position/overlay-position-builder.js +43 -47
  111. package/esm2015/overlay/public-api.js +2 -2
  112. package/esm2015/overlay/scroll/scroll-strategy-options.js +33 -37
  113. package/esm2015/platform/features/scrolling.js +1 -2
  114. package/esm2015/platform/platform-module.js +6 -10
  115. package/esm2015/platform/platform.js +48 -52
  116. package/esm2015/portal/portal-directives.js +181 -201
  117. package/esm2015/scrolling/fixed-size-virtual-scroll.js +57 -47
  118. package/esm2015/scrolling/public-api.js +2 -1
  119. package/esm2015/scrolling/scroll-dispatcher.js +139 -143
  120. package/esm2015/scrolling/scrollable.js +135 -139
  121. package/esm2015/scrolling/scrolling-module.js +32 -40
  122. package/esm2015/scrolling/viewport-ruler.js +105 -109
  123. package/esm2015/scrolling/virtual-for-of.js +264 -268
  124. package/esm2015/scrolling/virtual-scroll-repeater.js +8 -0
  125. package/esm2015/scrolling/virtual-scroll-viewport.js +318 -322
  126. package/esm2015/stepper/step-header.js +20 -24
  127. package/esm2015/stepper/step-label.js +13 -17
  128. package/esm2015/stepper/stepper-button.js +59 -67
  129. package/esm2015/stepper/stepper-module.js +24 -28
  130. package/esm2015/stepper/stepper.js +313 -321
  131. package/esm2015/table/cell.js +129 -157
  132. package/esm2015/table/row.js +183 -219
  133. package/esm2015/table/table-module.js +9 -13
  134. package/esm2015/table/table.js +765 -785
  135. package/esm2015/table/text-column.js +85 -89
  136. package/esm2015/testing/component-harness.js +19 -1
  137. package/esm2015/testing/harness-environment.js +7 -1
  138. package/esm2015/text-field/autofill.js +89 -97
  139. package/esm2015/text-field/autosize.js +225 -229
  140. package/esm2015/text-field/text-field-module.js +10 -14
  141. package/esm2015/tree/control/nested-tree-control.js +7 -3
  142. package/esm2015/tree/nested-node.js +79 -83
  143. package/esm2015/tree/node.js +17 -21
  144. package/esm2015/tree/outlet.js +15 -19
  145. package/esm2015/tree/padding.js +88 -92
  146. package/esm2015/tree/toggle.js +32 -36
  147. package/esm2015/tree/tree-module.js +10 -14
  148. package/esm2015/tree/tree.js +266 -274
  149. package/esm2015/version.js +1 -1
  150. package/fesm2015/a11y.js +1021 -996
  151. package/fesm2015/a11y.js.map +1 -1
  152. package/fesm2015/accordion.js +173 -175
  153. package/fesm2015/accordion.js.map +1 -1
  154. package/fesm2015/bidi.js +74 -83
  155. package/fesm2015/bidi.js.map +1 -1
  156. package/fesm2015/cdk.js +1 -1
  157. package/fesm2015/cdk.js.map +1 -1
  158. package/fesm2015/clipboard.js +113 -122
  159. package/fesm2015/clipboard.js.map +1 -1
  160. package/fesm2015/collections.js +32 -35
  161. package/fesm2015/collections.js.map +1 -1
  162. package/fesm2015/drag-drop.js +1005 -961
  163. package/fesm2015/drag-drop.js.map +1 -1
  164. package/fesm2015/layout.js +111 -120
  165. package/fesm2015/layout.js.map +1 -1
  166. package/fesm2015/observers.js +146 -158
  167. package/fesm2015/observers.js.map +1 -1
  168. package/fesm2015/overlay.js +793 -659
  169. package/fesm2015/overlay.js.map +1 -1
  170. package/fesm2015/platform.js +52 -59
  171. package/fesm2015/platform.js.map +1 -1
  172. package/fesm2015/portal.js +180 -195
  173. package/fesm2015/portal.js.map +1 -1
  174. package/fesm2015/scrolling.js +1058 -1060
  175. package/fesm2015/scrolling.js.map +1 -1
  176. package/fesm2015/stepper.js +424 -445
  177. package/fesm2015/stepper.js.map +1 -1
  178. package/fesm2015/table.js +1178 -1247
  179. package/fesm2015/table.js.map +1 -1
  180. package/fesm2015/testing.js +25 -1
  181. package/fesm2015/testing.js.map +1 -1
  182. package/fesm2015/text-field.js +318 -330
  183. package/fesm2015/text-field.js.map +1 -1
  184. package/fesm2015/tree.js +517 -537
  185. package/fesm2015/tree.js.map +1 -1
  186. package/overlay/dispatchers/base-overlay-dispatcher.d.ts +28 -0
  187. package/overlay/dispatchers/index.d.ts +9 -0
  188. package/overlay/{keyboard → dispatchers}/overlay-keyboard-dispatcher.d.ts +4 -10
  189. package/overlay/dispatchers/overlay-outside-click-dispatcher.d.ts +27 -0
  190. package/overlay/index.d.ts +4 -3
  191. package/overlay/index.metadata.json +1 -1
  192. package/overlay/overlay-config.d.ts +4 -0
  193. package/overlay/overlay-directives.d.ts +4 -0
  194. package/overlay/overlay-ref.d.ts +8 -2
  195. package/overlay/overlay-reference.d.ts +1 -0
  196. package/overlay/overlay.d.ts +4 -2
  197. package/overlay/public-api.d.ts +1 -1
  198. package/package.json +3 -3
  199. package/schematics/index.js +1 -1
  200. package/schematics/migration.json +5 -0
  201. package/schematics/ng-add/index.js +1 -1
  202. package/schematics/ng-update/data/index.js +1 -1
  203. package/schematics/ng-update/devkit-file-system.d.ts +5 -5
  204. package/schematics/ng-update/devkit-file-system.js +21 -16
  205. package/schematics/ng-update/devkit-migration-rule.js +13 -20
  206. package/schematics/ng-update/devkit-migration.d.ts +0 -2
  207. package/schematics/ng-update/devkit-migration.js +1 -1
  208. package/schematics/ng-update/find-stylesheets.d.ts +10 -0
  209. package/schematics/ng-update/find-stylesheets.js +31 -0
  210. package/schematics/ng-update/index.d.ts +2 -0
  211. package/schematics/ng-update/index.js +7 -2
  212. package/schematics/ng-update/migrations/attribute-selectors.js +3 -3
  213. package/schematics/ng-update/migrations/css-selectors.js +3 -3
  214. package/schematics/ng-update/migrations/element-selectors.js +3 -3
  215. package/schematics/ng-update/public-api.js +1 -1
  216. package/schematics/update-tool/component-resource-collector.d.ts +1 -1
  217. package/schematics/update-tool/component-resource-collector.js +18 -14
  218. package/schematics/update-tool/file-system.d.ts +19 -14
  219. package/schematics/update-tool/file-system.js +1 -1
  220. package/schematics/update-tool/index.d.ts +21 -3
  221. package/schematics/update-tool/index.js +29 -23
  222. package/schematics/update-tool/public-api.js +1 -1
  223. package/schematics/update-tool/target-version.d.ts +2 -1
  224. package/schematics/update-tool/target-version.js +5 -3
  225. package/schematics/update-tool/utils/parse-tsconfig.d.ts +2 -1
  226. package/schematics/update-tool/utils/parse-tsconfig.js +6 -10
  227. package/schematics/update-tool/utils/virtual-host.d.ts +34 -0
  228. package/schematics/update-tool/utils/virtual-host.js +62 -0
  229. package/schematics/update-tool/version-changes.js +4 -6
  230. package/schematics/utils/index.js +1 -1
  231. package/schematics/utils/project-tsconfig-paths.d.ts +2 -1
  232. package/schematics/utils/project-tsconfig-paths.js +1 -1
  233. package/scrolling/index.metadata.json +1 -1
  234. package/scrolling/public-api.d.ts +1 -0
  235. package/scrolling/virtual-for-of.d.ts +2 -1
  236. package/scrolling/virtual-scroll-repeater.d.ts +16 -0
  237. package/scrolling/virtual-scroll-viewport.d.ts +4 -4
  238. package/testing/component-harness.d.ts +12 -0
  239. package/testing/harness-environment.d.ts +1 -0
  240. package/tree/control/nested-tree-control.d.ts +7 -2
  241. package/tree/index.metadata.json +1 -1
  242. package/esm2015/overlay/keyboard/overlay-keyboard-dispatcher.js +0 -100
package/fesm2015/a11y.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { DOCUMENT } from '@angular/common';
2
2
  import { ɵɵdefineInjectable, ɵɵinject, Injectable, Inject, QueryList, isDevMode, NgZone, Directive, ElementRef, Input, InjectionToken, Optional, EventEmitter, Output, NgModule } from '@angular/core';
3
+ import { Platform, normalizePassiveListenerOptions, _getShadowRoot, PlatformModule } from '@angular/cdk/platform';
3
4
  import { Subject, Subscription, of } from 'rxjs';
4
- import { hasModifierKey, A, Z, ZERO, NINE, LEFT_ARROW, RIGHT_ARROW, UP_ARROW, DOWN_ARROW, TAB } from '@angular/cdk/keycodes';
5
+ import { hasModifierKey, A, Z, ZERO, NINE, END, HOME, LEFT_ARROW, RIGHT_ARROW, UP_ARROW, DOWN_ARROW, TAB } from '@angular/cdk/keycodes';
5
6
  import { tap, debounceTime, filter, map, take } from 'rxjs/operators';
6
7
  import { coerceBooleanProperty, coerceElement } from '@angular/cdk/coercion';
7
- import { Platform, normalizePassiveListenerOptions, _getShadowRoot, PlatformModule } from '@angular/cdk/platform';
8
8
  import { ContentObserver, ObserversModule } from '@angular/cdk/observers';
9
9
 
10
10
  /**
@@ -75,183 +75,192 @@ let messagesContainer = null;
75
75
  * want to use aria-describedby to further describe themselves without adding additional visual
76
76
  * content.
77
77
  */
78
- let AriaDescriber = /** @class */ (() => {
79
- class AriaDescriber {
80
- constructor(_document) {
81
- this._document = _document;
78
+ class AriaDescriber {
79
+ constructor(_document,
80
+ /**
81
+ * @breaking-change 8.0.0 `_platform` parameter to be made required.
82
+ */
83
+ _platform) {
84
+ this._platform = _platform;
85
+ this._document = _document;
86
+ }
87
+ /**
88
+ * Adds to the host element an aria-describedby reference to a hidden element that contains
89
+ * the message. If the same message has already been registered, then it will reuse the created
90
+ * message element.
91
+ */
92
+ describe(hostElement, message) {
93
+ if (!this._canBeDescribed(hostElement, message)) {
94
+ return;
82
95
  }
83
- /**
84
- * Adds to the host element an aria-describedby reference to a hidden element that contains
85
- * the message. If the same message has already been registered, then it will reuse the created
86
- * message element.
87
- */
88
- describe(hostElement, message) {
89
- if (!this._canBeDescribed(hostElement, message)) {
90
- return;
91
- }
92
- if (typeof message !== 'string') {
93
- // We need to ensure that the element has an ID.
94
- this._setMessageId(message);
95
- messageRegistry.set(message, { messageElement: message, referenceCount: 0 });
96
- }
97
- else if (!messageRegistry.has(message)) {
98
- this._createMessageElement(message);
99
- }
100
- if (!this._isElementDescribedByMessage(hostElement, message)) {
101
- this._addMessageReference(hostElement, message);
102
- }
96
+ if (typeof message !== 'string') {
97
+ // We need to ensure that the element has an ID.
98
+ this._setMessageId(message);
99
+ messageRegistry.set(message, { messageElement: message, referenceCount: 0 });
103
100
  }
104
- /** Removes the host element's aria-describedby reference to the message element. */
105
- removeDescription(hostElement, message) {
106
- if (!this._isElementNode(hostElement)) {
107
- return;
108
- }
109
- if (this._isElementDescribedByMessage(hostElement, message)) {
110
- this._removeMessageReference(hostElement, message);
111
- }
112
- // If the message is a string, it means that it's one that we created for the
113
- // consumer so we can remove it safely, otherwise we should leave it in place.
114
- if (typeof message === 'string') {
115
- const registeredMessage = messageRegistry.get(message);
116
- if (registeredMessage && registeredMessage.referenceCount === 0) {
117
- this._deleteMessageElement(message);
118
- }
119
- }
120
- if (messagesContainer && messagesContainer.childNodes.length === 0) {
121
- this._deleteMessagesContainer();
122
- }
101
+ else if (!messageRegistry.has(message)) {
102
+ this._createMessageElement(message);
123
103
  }
124
- /** Unregisters all created message elements and removes the message container. */
125
- ngOnDestroy() {
126
- const describedElements = this._document.querySelectorAll(`[${CDK_DESCRIBEDBY_HOST_ATTRIBUTE}]`);
127
- for (let i = 0; i < describedElements.length; i++) {
128
- this._removeCdkDescribedByReferenceIds(describedElements[i]);
129
- describedElements[i].removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE);
130
- }
131
- if (messagesContainer) {
132
- this._deleteMessagesContainer();
133
- }
134
- messageRegistry.clear();
104
+ if (!this._isElementDescribedByMessage(hostElement, message)) {
105
+ this._addMessageReference(hostElement, message);
135
106
  }
136
- /**
137
- * Creates a new element in the visually hidden message container element with the message
138
- * as its content and adds it to the message registry.
139
- */
140
- _createMessageElement(message) {
141
- const messageElement = this._document.createElement('div');
142
- this._setMessageId(messageElement);
143
- messageElement.textContent = message;
144
- this._createMessagesContainer();
145
- messagesContainer.appendChild(messageElement);
146
- messageRegistry.set(message, { messageElement, referenceCount: 0 });
147
- }
148
- /** Assigns a unique ID to an element, if it doesn't have one already. */
149
- _setMessageId(element) {
150
- if (!element.id) {
151
- element.id = `${CDK_DESCRIBEDBY_ID_PREFIX}-${nextId++}`;
152
- }
107
+ }
108
+ /** Removes the host element's aria-describedby reference to the message element. */
109
+ removeDescription(hostElement, message) {
110
+ if (!this._isElementNode(hostElement)) {
111
+ return;
153
112
  }
154
- /** Deletes the message element from the global messages container. */
155
- _deleteMessageElement(message) {
156
- const registeredMessage = messageRegistry.get(message);
157
- const messageElement = registeredMessage && registeredMessage.messageElement;
158
- if (messagesContainer && messageElement) {
159
- messagesContainer.removeChild(messageElement);
160
- }
161
- messageRegistry.delete(message);
162
- }
163
- /** Creates the global container for all aria-describedby messages. */
164
- _createMessagesContainer() {
165
- if (!messagesContainer) {
166
- const preExistingContainer = this._document.getElementById(MESSAGES_CONTAINER_ID);
167
- // When going from the server to the client, we may end up in a situation where there's
168
- // already a container on the page, but we don't have a reference to it. Clear the
169
- // old container so we don't get duplicates. Doing this, instead of emptying the previous
170
- // container, should be slightly faster.
171
- if (preExistingContainer) {
172
- preExistingContainer.parentNode.removeChild(preExistingContainer);
173
- }
174
- messagesContainer = this._document.createElement('div');
175
- messagesContainer.id = MESSAGES_CONTAINER_ID;
176
- messagesContainer.setAttribute('aria-hidden', 'true');
177
- messagesContainer.style.display = 'none';
178
- this._document.body.appendChild(messagesContainer);
179
- }
113
+ if (this._isElementDescribedByMessage(hostElement, message)) {
114
+ this._removeMessageReference(hostElement, message);
180
115
  }
181
- /** Deletes the global messages container. */
182
- _deleteMessagesContainer() {
183
- if (messagesContainer && messagesContainer.parentNode) {
184
- messagesContainer.parentNode.removeChild(messagesContainer);
185
- messagesContainer = null;
116
+ // If the message is a string, it means that it's one that we created for the
117
+ // consumer so we can remove it safely, otherwise we should leave it in place.
118
+ if (typeof message === 'string') {
119
+ const registeredMessage = messageRegistry.get(message);
120
+ if (registeredMessage && registeredMessage.referenceCount === 0) {
121
+ this._deleteMessageElement(message);
186
122
  }
187
123
  }
188
- /** Removes all cdk-describedby messages that are hosted through the element. */
189
- _removeCdkDescribedByReferenceIds(element) {
190
- // Remove all aria-describedby reference IDs that are prefixed by CDK_DESCRIBEDBY_ID_PREFIX
191
- const originalReferenceIds = getAriaReferenceIds(element, 'aria-describedby')
192
- .filter(id => id.indexOf(CDK_DESCRIBEDBY_ID_PREFIX) != 0);
193
- element.setAttribute('aria-describedby', originalReferenceIds.join(' '));
124
+ if (messagesContainer && messagesContainer.childNodes.length === 0) {
125
+ this._deleteMessagesContainer();
194
126
  }
195
- /**
196
- * Adds a message reference to the element using aria-describedby and increments the registered
197
- * message's reference count.
198
- */
199
- _addMessageReference(element, message) {
200
- const registeredMessage = messageRegistry.get(message);
201
- // Add the aria-describedby reference and set the
202
- // describedby_host attribute to mark the element.
203
- addAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id);
204
- element.setAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE, '');
205
- registeredMessage.referenceCount++;
127
+ }
128
+ /** Unregisters all created message elements and removes the message container. */
129
+ ngOnDestroy() {
130
+ const describedElements = this._document.querySelectorAll(`[${CDK_DESCRIBEDBY_HOST_ATTRIBUTE}]`);
131
+ for (let i = 0; i < describedElements.length; i++) {
132
+ this._removeCdkDescribedByReferenceIds(describedElements[i]);
133
+ describedElements[i].removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE);
206
134
  }
207
- /**
208
- * Removes a message reference from the element using aria-describedby
209
- * and decrements the registered message's reference count.
210
- */
211
- _removeMessageReference(element, message) {
212
- const registeredMessage = messageRegistry.get(message);
213
- registeredMessage.referenceCount--;
214
- removeAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id);
215
- element.removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE);
135
+ if (messagesContainer) {
136
+ this._deleteMessagesContainer();
216
137
  }
217
- /** Returns true if the element has been described by the provided message ID. */
218
- _isElementDescribedByMessage(element, message) {
219
- const referenceIds = getAriaReferenceIds(element, 'aria-describedby');
220
- const registeredMessage = messageRegistry.get(message);
221
- const messageId = registeredMessage && registeredMessage.messageElement.id;
222
- return !!messageId && referenceIds.indexOf(messageId) != -1;
138
+ messageRegistry.clear();
139
+ }
140
+ /**
141
+ * Creates a new element in the visually hidden message container element with the message
142
+ * as its content and adds it to the message registry.
143
+ */
144
+ _createMessageElement(message) {
145
+ const messageElement = this._document.createElement('div');
146
+ this._setMessageId(messageElement);
147
+ messageElement.textContent = message;
148
+ this._createMessagesContainer();
149
+ messagesContainer.appendChild(messageElement);
150
+ messageRegistry.set(message, { messageElement, referenceCount: 0 });
151
+ }
152
+ /** Assigns a unique ID to an element, if it doesn't have one already. */
153
+ _setMessageId(element) {
154
+ if (!element.id) {
155
+ element.id = `${CDK_DESCRIBEDBY_ID_PREFIX}-${nextId++}`;
156
+ }
157
+ }
158
+ /** Deletes the message element from the global messages container. */
159
+ _deleteMessageElement(message) {
160
+ const registeredMessage = messageRegistry.get(message);
161
+ const messageElement = registeredMessage && registeredMessage.messageElement;
162
+ if (messagesContainer && messageElement) {
163
+ messagesContainer.removeChild(messageElement);
164
+ }
165
+ messageRegistry.delete(message);
166
+ }
167
+ /** Creates the global container for all aria-describedby messages. */
168
+ _createMessagesContainer() {
169
+ if (!messagesContainer) {
170
+ // @breaking-change 8.0.0 `_platform` null check can be removed once the parameter is required
171
+ const canBeAriaHidden = !this._platform || (!this._platform.EDGE && !this._platform.TRIDENT);
172
+ const preExistingContainer = this._document.getElementById(MESSAGES_CONTAINER_ID);
173
+ // When going from the server to the client, we may end up in a situation where there's
174
+ // already a container on the page, but we don't have a reference to it. Clear the
175
+ // old container so we don't get duplicates. Doing this, instead of emptying the previous
176
+ // container, should be slightly faster.
177
+ if (preExistingContainer) {
178
+ preExistingContainer.parentNode.removeChild(preExistingContainer);
179
+ }
180
+ messagesContainer = this._document.createElement('div');
181
+ messagesContainer.id = MESSAGES_CONTAINER_ID;
182
+ messagesContainer.classList.add('cdk-visually-hidden');
183
+ // IE and Edge won't read out the messages if they're in an `aria-hidden` container.
184
+ // We only disable `aria-hidden` for these platforms, because it comes with the
185
+ // disadvantage that people might hit the messages when they've navigated past
186
+ // the end of the document using the arrow keys.
187
+ messagesContainer.setAttribute('aria-hidden', canBeAriaHidden + '');
188
+ this._document.body.appendChild(messagesContainer);
189
+ }
190
+ }
191
+ /** Deletes the global messages container. */
192
+ _deleteMessagesContainer() {
193
+ if (messagesContainer && messagesContainer.parentNode) {
194
+ messagesContainer.parentNode.removeChild(messagesContainer);
195
+ messagesContainer = null;
196
+ }
197
+ }
198
+ /** Removes all cdk-describedby messages that are hosted through the element. */
199
+ _removeCdkDescribedByReferenceIds(element) {
200
+ // Remove all aria-describedby reference IDs that are prefixed by CDK_DESCRIBEDBY_ID_PREFIX
201
+ const originalReferenceIds = getAriaReferenceIds(element, 'aria-describedby')
202
+ .filter(id => id.indexOf(CDK_DESCRIBEDBY_ID_PREFIX) != 0);
203
+ element.setAttribute('aria-describedby', originalReferenceIds.join(' '));
204
+ }
205
+ /**
206
+ * Adds a message reference to the element using aria-describedby and increments the registered
207
+ * message's reference count.
208
+ */
209
+ _addMessageReference(element, message) {
210
+ const registeredMessage = messageRegistry.get(message);
211
+ // Add the aria-describedby reference and set the
212
+ // describedby_host attribute to mark the element.
213
+ addAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id);
214
+ element.setAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE, '');
215
+ registeredMessage.referenceCount++;
216
+ }
217
+ /**
218
+ * Removes a message reference from the element using aria-describedby
219
+ * and decrements the registered message's reference count.
220
+ */
221
+ _removeMessageReference(element, message) {
222
+ const registeredMessage = messageRegistry.get(message);
223
+ registeredMessage.referenceCount--;
224
+ removeAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id);
225
+ element.removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE);
226
+ }
227
+ /** Returns true if the element has been described by the provided message ID. */
228
+ _isElementDescribedByMessage(element, message) {
229
+ const referenceIds = getAriaReferenceIds(element, 'aria-describedby');
230
+ const registeredMessage = messageRegistry.get(message);
231
+ const messageId = registeredMessage && registeredMessage.messageElement.id;
232
+ return !!messageId && referenceIds.indexOf(messageId) != -1;
233
+ }
234
+ /** Determines whether a message can be described on a particular element. */
235
+ _canBeDescribed(element, message) {
236
+ if (!this._isElementNode(element)) {
237
+ return false;
238
+ }
239
+ if (message && typeof message === 'object') {
240
+ // We'd have to make some assumptions about the description element's text, if the consumer
241
+ // passed in an element. Assume that if an element is passed in, the consumer has verified
242
+ // that it can be used as a description.
243
+ return true;
223
244
  }
224
- /** Determines whether a message can be described on a particular element. */
225
- _canBeDescribed(element, message) {
226
- if (!this._isElementNode(element)) {
227
- return false;
228
- }
229
- if (message && typeof message === 'object') {
230
- // We'd have to make some assumptions about the description element's text, if the consumer
231
- // passed in an element. Assume that if an element is passed in, the consumer has verified
232
- // that it can be used as a description.
233
- return true;
234
- }
235
- const trimmedMessage = message == null ? '' : `${message}`.trim();
236
- const ariaLabel = element.getAttribute('aria-label');
237
- // We shouldn't set descriptions if they're exactly the same as the `aria-label` of the
238
- // element, because screen readers will end up reading out the same text twice in a row.
239
- return trimmedMessage ? (!ariaLabel || ariaLabel.trim() !== trimmedMessage) : false;
240
- }
241
- /** Checks whether a node is an Element node. */
242
- _isElementNode(element) {
243
- return element.nodeType === this._document.ELEMENT_NODE;
244
- }
245
- }
246
- AriaDescriber.ɵprov = ɵɵdefineInjectable({ factory: function AriaDescriber_Factory() { return new AriaDescriber(ɵɵinject(DOCUMENT)); }, token: AriaDescriber, providedIn: "root" });
247
- AriaDescriber.decorators = [
248
- { type: Injectable, args: [{ providedIn: 'root' },] }
249
- ];
250
- AriaDescriber.ctorParameters = () => [
251
- { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
252
- ];
253
- return AriaDescriber;
254
- })();
245
+ const trimmedMessage = message == null ? '' : `${message}`.trim();
246
+ const ariaLabel = element.getAttribute('aria-label');
247
+ // We shouldn't set descriptions if they're exactly the same as the `aria-label` of the
248
+ // element, because screen readers will end up reading out the same text twice in a row.
249
+ return trimmedMessage ? (!ariaLabel || ariaLabel.trim() !== trimmedMessage) : false;
250
+ }
251
+ /** Checks whether a node is an Element node. */
252
+ _isElementNode(element) {
253
+ return element.nodeType === this._document.ELEMENT_NODE;
254
+ }
255
+ }
256
+ AriaDescriber.ɵprov = ɵɵdefineInjectable({ factory: function AriaDescriber_Factory() { return new AriaDescriber(ɵɵinject(DOCUMENT), ɵɵinject(Platform)); }, token: AriaDescriber, providedIn: "root" });
257
+ AriaDescriber.decorators = [
258
+ { type: Injectable, args: [{ providedIn: 'root' },] }
259
+ ];
260
+ AriaDescriber.ctorParameters = () => [
261
+ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
262
+ { type: Platform }
263
+ ];
255
264
 
256
265
  /**
257
266
  * @license
@@ -274,6 +283,7 @@ class ListKeyManager {
274
283
  this._typeaheadSubscription = Subscription.EMPTY;
275
284
  this._vertical = true;
276
285
  this._allowedModifierKeys = [];
286
+ this._homeAndEnd = false;
277
287
  /**
278
288
  * Predicate function that can be used to check whether an item should be skipped
279
289
  * by the key manager. By default, disabled items are skipped.
@@ -375,10 +385,18 @@ class ListKeyManager {
375
385
  });
376
386
  return this;
377
387
  }
388
+ /**
389
+ * Configures the key manager to focus the first and last items
390
+ * respectively when the Home key and End Key are pressed.
391
+ */
392
+ withHomeAndEnd() {
393
+ this._homeAndEnd = true;
394
+ return this;
395
+ }
378
396
  setActiveItem(item) {
379
- const previousIndex = this._activeItemIndex;
397
+ const previousActiveItem = this._activeItem;
380
398
  this.updateActiveItem(item);
381
- if (this._activeItemIndex !== previousIndex) {
399
+ if (this._activeItem !== previousActiveItem) {
382
400
  this.change.next(this._activeItemIndex);
383
401
  }
384
402
  }
@@ -428,6 +446,22 @@ class ListKeyManager {
428
446
  else {
429
447
  return;
430
448
  }
449
+ case HOME:
450
+ if (this._homeAndEnd && isModifierAllowed) {
451
+ this.setFirstItemActive();
452
+ break;
453
+ }
454
+ else {
455
+ return;
456
+ }
457
+ case END:
458
+ if (this._homeAndEnd && isModifierAllowed) {
459
+ this.setLastItemActive();
460
+ break;
461
+ }
462
+ else {
463
+ return;
464
+ }
431
465
  default:
432
466
  if (isModifierAllowed || hasModifierKey(event, 'shiftKey')) {
433
467
  // Attempt to use the `event.key` which also maps it to the user's keyboard language,
@@ -593,6 +627,17 @@ class FocusKeyManager extends ListKeyManager {
593
627
  * Use of this source code is governed by an MIT-style license that can be
594
628
  * found in the LICENSE file at https://angular.io/license
595
629
  */
630
+ /**
631
+ * Configuration for the isFocusable method.
632
+ */
633
+ class IsFocusableConfig {
634
+ constructor() {
635
+ /**
636
+ * Whether to count an element as focusable even if it is not currently visible.
637
+ */
638
+ this.ignoreVisibility = false;
639
+ }
640
+ }
596
641
  // The InteractivityChecker leans heavily on the ally.js accessibility utilities.
597
642
  // Methods like `isTabbable` are only covering specific edge-cases for the browsers which are
598
643
  // supported.
@@ -600,122 +645,121 @@ class FocusKeyManager extends ListKeyManager {
600
645
  * Utility for checking the interactivity of an element, such as whether is is focusable or
601
646
  * tabbable.
602
647
  */
603
- let InteractivityChecker = /** @class */ (() => {
604
- class InteractivityChecker {
605
- constructor(_platform) {
606
- this._platform = _platform;
607
- }
608
- /**
609
- * Gets whether an element is disabled.
610
- *
611
- * @param element Element to be checked.
612
- * @returns Whether the element is disabled.
613
- */
614
- isDisabled(element) {
615
- // This does not capture some cases, such as a non-form control with a disabled attribute or
616
- // a form control inside of a disabled form, but should capture the most common cases.
617
- return element.hasAttribute('disabled');
618
- }
619
- /**
620
- * Gets whether an element is visible for the purposes of interactivity.
621
- *
622
- * This will capture states like `display: none` and `visibility: hidden`, but not things like
623
- * being clipped by an `overflow: hidden` parent or being outside the viewport.
624
- *
625
- * @returns Whether the element is visible.
626
- */
627
- isVisible(element) {
628
- return hasGeometry(element) && getComputedStyle(element).visibility === 'visible';
629
- }
630
- /**
631
- * Gets whether an element can be reached via Tab key.
632
- * Assumes that the element has already been checked with isFocusable.
633
- *
634
- * @param element Element to be checked.
635
- * @returns Whether the element is tabbable.
636
- */
637
- isTabbable(element) {
638
- // Nothing is tabbable on the server 😎
639
- if (!this._platform.isBrowser) {
648
+ class InteractivityChecker {
649
+ constructor(_platform) {
650
+ this._platform = _platform;
651
+ }
652
+ /**
653
+ * Gets whether an element is disabled.
654
+ *
655
+ * @param element Element to be checked.
656
+ * @returns Whether the element is disabled.
657
+ */
658
+ isDisabled(element) {
659
+ // This does not capture some cases, such as a non-form control with a disabled attribute or
660
+ // a form control inside of a disabled form, but should capture the most common cases.
661
+ return element.hasAttribute('disabled');
662
+ }
663
+ /**
664
+ * Gets whether an element is visible for the purposes of interactivity.
665
+ *
666
+ * This will capture states like `display: none` and `visibility: hidden`, but not things like
667
+ * being clipped by an `overflow: hidden` parent or being outside the viewport.
668
+ *
669
+ * @returns Whether the element is visible.
670
+ */
671
+ isVisible(element) {
672
+ return hasGeometry(element) && getComputedStyle(element).visibility === 'visible';
673
+ }
674
+ /**
675
+ * Gets whether an element can be reached via Tab key.
676
+ * Assumes that the element has already been checked with isFocusable.
677
+ *
678
+ * @param element Element to be checked.
679
+ * @returns Whether the element is tabbable.
680
+ */
681
+ isTabbable(element) {
682
+ // Nothing is tabbable on the server 😎
683
+ if (!this._platform.isBrowser) {
684
+ return false;
685
+ }
686
+ const frameElement = getFrameElement(getWindow(element));
687
+ if (frameElement) {
688
+ const frameType = frameElement && frameElement.nodeName.toLowerCase();
689
+ // Frame elements inherit their tabindex onto all child elements.
690
+ if (getTabIndexValue(frameElement) === -1) {
640
691
  return false;
641
692
  }
642
- const frameElement = getFrameElement(getWindow(element));
643
- if (frameElement) {
644
- const frameType = frameElement && frameElement.nodeName.toLowerCase();
645
- // Frame elements inherit their tabindex onto all child elements.
646
- if (getTabIndexValue(frameElement) === -1) {
647
- return false;
648
- }
649
- // Webkit and Blink consider anything inside of an <object> element as non-tabbable.
650
- if ((this._platform.BLINK || this._platform.WEBKIT) && frameType === 'object') {
651
- return false;
652
- }
653
- // Webkit and Blink disable tabbing to an element inside of an invisible frame.
654
- if ((this._platform.BLINK || this._platform.WEBKIT) && !this.isVisible(frameElement)) {
655
- return false;
656
- }
657
- }
658
- let nodeName = element.nodeName.toLowerCase();
659
- let tabIndexValue = getTabIndexValue(element);
660
- if (element.hasAttribute('contenteditable')) {
661
- return tabIndexValue !== -1;
693
+ // Webkit and Blink consider anything inside of an <object> element as non-tabbable.
694
+ if ((this._platform.BLINK || this._platform.WEBKIT) && frameType === 'object') {
695
+ return false;
662
696
  }
663
- if (nodeName === 'iframe') {
664
- // The frames may be tabbable depending on content, but it's not possibly to reliably
665
- // investigate the content of the frames.
697
+ // Webkit and Blink disable tabbing to an element inside of an invisible frame.
698
+ if ((this._platform.BLINK || this._platform.WEBKIT) && !this.isVisible(frameElement)) {
666
699
  return false;
667
700
  }
668
- if (nodeName === 'audio') {
669
- if (!element.hasAttribute('controls')) {
670
- // By default an <audio> element without the controls enabled is not tabbable.
671
- return false;
672
- }
673
- else if (this._platform.BLINK) {
674
- // In Blink <audio controls> elements are always tabbable.
675
- return true;
676
- }
701
+ }
702
+ let nodeName = element.nodeName.toLowerCase();
703
+ let tabIndexValue = getTabIndexValue(element);
704
+ if (element.hasAttribute('contenteditable')) {
705
+ return tabIndexValue !== -1;
706
+ }
707
+ if (nodeName === 'iframe') {
708
+ // The frames may be tabbable depending on content, but it's not possibly to reliably
709
+ // investigate the content of the frames.
710
+ return false;
711
+ }
712
+ if (nodeName === 'audio') {
713
+ if (!element.hasAttribute('controls')) {
714
+ // By default an <audio> element without the controls enabled is not tabbable.
715
+ return false;
677
716
  }
678
- if (nodeName === 'video') {
679
- if (!element.hasAttribute('controls') && this._platform.TRIDENT) {
680
- // In Trident a <video> element without the controls enabled is not tabbable.
681
- return false;
682
- }
683
- else if (this._platform.BLINK || this._platform.FIREFOX) {
684
- // In Chrome and Firefox <video controls> elements are always tabbable.
685
- return true;
686
- }
717
+ else if (this._platform.BLINK) {
718
+ // In Blink <audio controls> elements are always tabbable.
719
+ return true;
687
720
  }
688
- if (nodeName === 'object' && (this._platform.BLINK || this._platform.WEBKIT)) {
689
- // In all Blink and WebKit based browsers <object> elements are never tabbable.
721
+ }
722
+ if (nodeName === 'video') {
723
+ if (!element.hasAttribute('controls') && this._platform.TRIDENT) {
724
+ // In Trident a <video> element without the controls enabled is not tabbable.
690
725
  return false;
691
726
  }
692
- // In iOS the browser only considers some specific elements as tabbable.
693
- if (this._platform.WEBKIT && this._platform.IOS && !isPotentiallyTabbableIOS(element)) {
694
- return false;
727
+ else if (this._platform.BLINK || this._platform.FIREFOX) {
728
+ // In Chrome and Firefox <video controls> elements are always tabbable.
729
+ return true;
695
730
  }
696
- return element.tabIndex >= 0;
697
731
  }
698
- /**
699
- * Gets whether an element can be focused by the user.
700
- *
701
- * @param element Element to be checked.
702
- * @returns Whether the element is focusable.
703
- */
704
- isFocusable(element) {
705
- // Perform checks in order of left to most expensive.
706
- // Again, naive approach that does not capture many edge cases and browser quirks.
707
- return isPotentiallyFocusable(element) && !this.isDisabled(element) && this.isVisible(element);
708
- }
709
- }
710
- InteractivityChecker.ɵprov = ɵɵdefineInjectable({ factory: function InteractivityChecker_Factory() { return new InteractivityChecker(ɵɵinject(Platform)); }, token: InteractivityChecker, providedIn: "root" });
711
- InteractivityChecker.decorators = [
712
- { type: Injectable, args: [{ providedIn: 'root' },] }
713
- ];
714
- InteractivityChecker.ctorParameters = () => [
715
- { type: Platform }
716
- ];
717
- return InteractivityChecker;
718
- })();
732
+ if (nodeName === 'object' && (this._platform.BLINK || this._platform.WEBKIT)) {
733
+ // In all Blink and WebKit based browsers <object> elements are never tabbable.
734
+ return false;
735
+ }
736
+ // In iOS the browser only considers some specific elements as tabbable.
737
+ if (this._platform.WEBKIT && this._platform.IOS && !isPotentiallyTabbableIOS(element)) {
738
+ return false;
739
+ }
740
+ return element.tabIndex >= 0;
741
+ }
742
+ /**
743
+ * Gets whether an element can be focused by the user.
744
+ *
745
+ * @param element Element to be checked.
746
+ * @param config The config object with options to customize this method's behavior
747
+ * @returns Whether the element is focusable.
748
+ */
749
+ isFocusable(element, config) {
750
+ // Perform checks in order of left to most expensive.
751
+ // Again, naive approach that does not capture many edge cases and browser quirks.
752
+ return isPotentiallyFocusable(element) && !this.isDisabled(element) &&
753
+ ((config === null || config === void 0 ? void 0 : config.ignoreVisibility) || this.isVisible(element));
754
+ }
755
+ }
756
+ InteractivityChecker.ɵprov = ɵɵdefineInjectable({ factory: function InteractivityChecker_Factory() { return new InteractivityChecker(ɵɵinject(Platform)); }, token: InteractivityChecker, providedIn: "root" });
757
+ InteractivityChecker.decorators = [
758
+ { type: Injectable, args: [{ providedIn: 'root' },] }
759
+ ];
760
+ InteractivityChecker.ctorParameters = () => [
761
+ { type: Platform }
762
+ ];
719
763
  /**
720
764
  * Returns the frame element from a window object. Since browsers like MS Edge throw errors if
721
765
  * the frameElement property is being accessed from a different host address, this property
@@ -871,6 +915,7 @@ class FocusTrap {
871
915
  }
872
916
  }
873
917
  this._startAnchor = this._endAnchor = null;
918
+ this._hasAttached = false;
874
919
  }
875
920
  /**
876
921
  * Inserts the anchors into the DOM. This is usually done automatically
@@ -1094,94 +1139,98 @@ class FocusTrap {
1094
1139
  * @deprecated Use `ConfigurableFocusTrapFactory` instead.
1095
1140
  * @breaking-change for 11.0.0 Remove this class.
1096
1141
  */
1097
- let FocusTrapFactory = /** @class */ (() => {
1098
- class FocusTrapFactory {
1099
- constructor(_checker, _ngZone, _document) {
1100
- this._checker = _checker;
1101
- this._ngZone = _ngZone;
1102
- this._document = _document;
1103
- }
1104
- /**
1105
- * Creates a focus-trapped region around the given element.
1106
- * @param element The element around which focus will be trapped.
1107
- * @param deferCaptureElements Defers the creation of focus-capturing elements to be done
1108
- * manually by the user.
1109
- * @returns The created focus trap instance.
1110
- */
1111
- create(element, deferCaptureElements = false) {
1112
- return new FocusTrap(element, this._checker, this._ngZone, this._document, deferCaptureElements);
1113
- }
1114
- }
1115
- FocusTrapFactory.ɵprov = ɵɵdefineInjectable({ factory: function FocusTrapFactory_Factory() { return new FocusTrapFactory(ɵɵinject(InteractivityChecker), ɵɵinject(NgZone), ɵɵinject(DOCUMENT)); }, token: FocusTrapFactory, providedIn: "root" });
1116
- FocusTrapFactory.decorators = [
1117
- { type: Injectable, args: [{ providedIn: 'root' },] }
1118
- ];
1119
- FocusTrapFactory.ctorParameters = () => [
1120
- { type: InteractivityChecker },
1121
- { type: NgZone },
1122
- { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
1123
- ];
1124
- return FocusTrapFactory;
1125
- })();
1142
+ class FocusTrapFactory {
1143
+ constructor(_checker, _ngZone, _document) {
1144
+ this._checker = _checker;
1145
+ this._ngZone = _ngZone;
1146
+ this._document = _document;
1147
+ }
1148
+ /**
1149
+ * Creates a focus-trapped region around the given element.
1150
+ * @param element The element around which focus will be trapped.
1151
+ * @param deferCaptureElements Defers the creation of focus-capturing elements to be done
1152
+ * manually by the user.
1153
+ * @returns The created focus trap instance.
1154
+ */
1155
+ create(element, deferCaptureElements = false) {
1156
+ return new FocusTrap(element, this._checker, this._ngZone, this._document, deferCaptureElements);
1157
+ }
1158
+ }
1159
+ FocusTrapFactory.ɵprov = ɵɵdefineInjectable({ factory: function FocusTrapFactory_Factory() { return new FocusTrapFactory(ɵɵinject(InteractivityChecker), ɵɵinject(NgZone), ɵɵinject(DOCUMENT)); }, token: FocusTrapFactory, providedIn: "root" });
1160
+ FocusTrapFactory.decorators = [
1161
+ { type: Injectable, args: [{ providedIn: 'root' },] }
1162
+ ];
1163
+ FocusTrapFactory.ctorParameters = () => [
1164
+ { type: InteractivityChecker },
1165
+ { type: NgZone },
1166
+ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
1167
+ ];
1126
1168
  /** Directive for trapping focus within a region. */
1127
- let CdkTrapFocus = /** @class */ (() => {
1128
- class CdkTrapFocus {
1129
- constructor(_elementRef, _focusTrapFactory, _document) {
1130
- this._elementRef = _elementRef;
1131
- this._focusTrapFactory = _focusTrapFactory;
1132
- /** Previously focused element to restore focus to upon destroy when using autoCapture. */
1169
+ class CdkTrapFocus {
1170
+ constructor(_elementRef, _focusTrapFactory, _document) {
1171
+ this._elementRef = _elementRef;
1172
+ this._focusTrapFactory = _focusTrapFactory;
1173
+ /** Previously focused element to restore focus to upon destroy when using autoCapture. */
1174
+ this._previouslyFocusedElement = null;
1175
+ this._document = _document;
1176
+ this.focusTrap = this._focusTrapFactory.create(this._elementRef.nativeElement, true);
1177
+ }
1178
+ /** Whether the focus trap is active. */
1179
+ get enabled() { return this.focusTrap.enabled; }
1180
+ set enabled(value) { this.focusTrap.enabled = coerceBooleanProperty(value); }
1181
+ /**
1182
+ * Whether the directive should automatially move focus into the trapped region upon
1183
+ * initialization and return focus to the previous activeElement upon destruction.
1184
+ */
1185
+ get autoCapture() { return this._autoCapture; }
1186
+ set autoCapture(value) { this._autoCapture = coerceBooleanProperty(value); }
1187
+ ngOnDestroy() {
1188
+ this.focusTrap.destroy();
1189
+ // If we stored a previously focused element when using autoCapture, return focus to that
1190
+ // element now that the trapped region is being destroyed.
1191
+ if (this._previouslyFocusedElement) {
1192
+ this._previouslyFocusedElement.focus();
1133
1193
  this._previouslyFocusedElement = null;
1134
- this._document = _document;
1135
- this.focusTrap = this._focusTrapFactory.create(this._elementRef.nativeElement, true);
1136
1194
  }
1137
- /** Whether the focus trap is active. */
1138
- get enabled() { return this.focusTrap.enabled; }
1139
- set enabled(value) { this.focusTrap.enabled = coerceBooleanProperty(value); }
1140
- /**
1141
- * Whether the directive should automatially move focus into the trapped region upon
1142
- * initialization and return focus to the previous activeElement upon destruction.
1143
- */
1144
- get autoCapture() { return this._autoCapture; }
1145
- set autoCapture(value) { this._autoCapture = coerceBooleanProperty(value); }
1146
- ngOnDestroy() {
1147
- this.focusTrap.destroy();
1148
- // If we stored a previously focused element when using autoCapture, return focus to that
1149
- // element now that the trapped region is being destroyed.
1150
- if (this._previouslyFocusedElement) {
1151
- this._previouslyFocusedElement.focus();
1152
- this._previouslyFocusedElement = null;
1153
- }
1195
+ }
1196
+ ngAfterContentInit() {
1197
+ this.focusTrap.attachAnchors();
1198
+ if (this.autoCapture) {
1199
+ this._captureFocus();
1154
1200
  }
1155
- ngAfterContentInit() {
1201
+ }
1202
+ ngDoCheck() {
1203
+ if (!this.focusTrap.hasAttached()) {
1156
1204
  this.focusTrap.attachAnchors();
1157
- if (this.autoCapture) {
1158
- this._previouslyFocusedElement = this._document.activeElement;
1159
- this.focusTrap.focusInitialElementWhenReady();
1160
- }
1161
1205
  }
1162
- ngDoCheck() {
1163
- if (!this.focusTrap.hasAttached()) {
1164
- this.focusTrap.attachAnchors();
1165
- }
1206
+ }
1207
+ ngOnChanges(changes) {
1208
+ const autoCaptureChange = changes['autoCapture'];
1209
+ if (autoCaptureChange && !autoCaptureChange.firstChange && this.autoCapture &&
1210
+ this.focusTrap.hasAttached()) {
1211
+ this._captureFocus();
1166
1212
  }
1167
1213
  }
1168
- CdkTrapFocus.decorators = [
1169
- { type: Directive, args: [{
1170
- selector: '[cdkTrapFocus]',
1171
- exportAs: 'cdkTrapFocus',
1172
- },] }
1173
- ];
1174
- CdkTrapFocus.ctorParameters = () => [
1175
- { type: ElementRef },
1176
- { type: FocusTrapFactory },
1177
- { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
1178
- ];
1179
- CdkTrapFocus.propDecorators = {
1180
- enabled: [{ type: Input, args: ['cdkTrapFocus',] }],
1181
- autoCapture: [{ type: Input, args: ['cdkTrapFocusAutoCapture',] }]
1182
- };
1183
- return CdkTrapFocus;
1184
- })();
1214
+ _captureFocus() {
1215
+ this._previouslyFocusedElement = this._document.activeElement;
1216
+ this.focusTrap.focusInitialElementWhenReady();
1217
+ }
1218
+ }
1219
+ CdkTrapFocus.decorators = [
1220
+ { type: Directive, args: [{
1221
+ selector: '[cdkTrapFocus]',
1222
+ exportAs: 'cdkTrapFocus',
1223
+ },] }
1224
+ ];
1225
+ CdkTrapFocus.ctorParameters = () => [
1226
+ { type: ElementRef },
1227
+ { type: FocusTrapFactory },
1228
+ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
1229
+ ];
1230
+ CdkTrapFocus.propDecorators = {
1231
+ enabled: [{ type: Input, args: ['cdkTrapFocus',] }],
1232
+ autoCapture: [{ type: Input, args: ['cdkTrapFocusAutoCapture',] }]
1233
+ };
1185
1234
 
1186
1235
  /**
1187
1236
  * @license
@@ -1366,49 +1415,46 @@ const FOCUS_TRAP_INERT_STRATEGY = new InjectionToken('FOCUS_TRAP_INERT_STRATEGY'
1366
1415
  * found in the LICENSE file at https://angular.io/license
1367
1416
  */
1368
1417
  /** Injectable that ensures only the most recently enabled FocusTrap is active. */
1369
- let FocusTrapManager = /** @class */ (() => {
1370
- class FocusTrapManager {
1371
- constructor() {
1372
- // A stack of the FocusTraps on the page. Only the FocusTrap at the
1373
- // top of the stack is active.
1374
- this._focusTrapStack = [];
1418
+ class FocusTrapManager {
1419
+ constructor() {
1420
+ // A stack of the FocusTraps on the page. Only the FocusTrap at the
1421
+ // top of the stack is active.
1422
+ this._focusTrapStack = [];
1423
+ }
1424
+ /**
1425
+ * Disables the FocusTrap at the top of the stack, and then pushes
1426
+ * the new FocusTrap onto the stack.
1427
+ */
1428
+ register(focusTrap) {
1429
+ // Dedupe focusTraps that register multiple times.
1430
+ this._focusTrapStack = this._focusTrapStack.filter((ft) => ft !== focusTrap);
1431
+ let stack = this._focusTrapStack;
1432
+ if (stack.length) {
1433
+ stack[stack.length - 1]._disable();
1375
1434
  }
1376
- /**
1377
- * Disables the FocusTrap at the top of the stack, and then pushes
1378
- * the new FocusTrap onto the stack.
1379
- */
1380
- register(focusTrap) {
1381
- // Dedupe focusTraps that register multiple times.
1382
- this._focusTrapStack = this._focusTrapStack.filter((ft) => ft !== focusTrap);
1383
- let stack = this._focusTrapStack;
1435
+ stack.push(focusTrap);
1436
+ focusTrap._enable();
1437
+ }
1438
+ /**
1439
+ * Removes the FocusTrap from the stack, and activates the
1440
+ * FocusTrap that is the new top of the stack.
1441
+ */
1442
+ deregister(focusTrap) {
1443
+ focusTrap._disable();
1444
+ const stack = this._focusTrapStack;
1445
+ const i = stack.indexOf(focusTrap);
1446
+ if (i !== -1) {
1447
+ stack.splice(i, 1);
1384
1448
  if (stack.length) {
1385
- stack[stack.length - 1]._disable();
1386
- }
1387
- stack.push(focusTrap);
1388
- focusTrap._enable();
1389
- }
1390
- /**
1391
- * Removes the FocusTrap from the stack, and activates the
1392
- * FocusTrap that is the new top of the stack.
1393
- */
1394
- deregister(focusTrap) {
1395
- focusTrap._disable();
1396
- const stack = this._focusTrapStack;
1397
- const i = stack.indexOf(focusTrap);
1398
- if (i !== -1) {
1399
- stack.splice(i, 1);
1400
- if (stack.length) {
1401
- stack[stack.length - 1]._enable();
1402
- }
1449
+ stack[stack.length - 1]._enable();
1403
1450
  }
1404
1451
  }
1405
1452
  }
1406
- FocusTrapManager.ɵprov = ɵɵdefineInjectable({ factory: function FocusTrapManager_Factory() { return new FocusTrapManager(); }, token: FocusTrapManager, providedIn: "root" });
1407
- FocusTrapManager.decorators = [
1408
- { type: Injectable, args: [{ providedIn: 'root' },] }
1409
- ];
1410
- return FocusTrapManager;
1411
- })();
1453
+ }
1454
+ FocusTrapManager.ɵprov = ɵɵdefineInjectable({ factory: function FocusTrapManager_Factory() { return new FocusTrapManager(); }, token: FocusTrapManager, providedIn: "root" });
1455
+ FocusTrapManager.decorators = [
1456
+ { type: Injectable, args: [{ providedIn: 'root' },] }
1457
+ ];
1412
1458
 
1413
1459
  /**
1414
1460
  * @license
@@ -1418,41 +1464,38 @@ let FocusTrapManager = /** @class */ (() => {
1418
1464
  * found in the LICENSE file at https://angular.io/license
1419
1465
  */
1420
1466
  /** Factory that allows easy instantiation of configurable focus traps. */
1421
- let ConfigurableFocusTrapFactory = /** @class */ (() => {
1422
- class ConfigurableFocusTrapFactory {
1423
- constructor(_checker, _ngZone, _focusTrapManager, _document, _inertStrategy) {
1424
- this._checker = _checker;
1425
- this._ngZone = _ngZone;
1426
- this._focusTrapManager = _focusTrapManager;
1427
- this._document = _document;
1428
- // TODO split up the strategies into different modules, similar to DateAdapter.
1429
- this._inertStrategy = _inertStrategy || new EventListenerFocusTrapInertStrategy();
1430
- }
1431
- create(element, config = new ConfigurableFocusTrapConfig()) {
1432
- let configObject;
1433
- if (typeof config === 'boolean') {
1434
- configObject = new ConfigurableFocusTrapConfig();
1435
- configObject.defer = config;
1436
- }
1437
- else {
1438
- configObject = config;
1439
- }
1440
- return new ConfigurableFocusTrap(element, this._checker, this._ngZone, this._document, this._focusTrapManager, this._inertStrategy, configObject);
1441
- }
1442
- }
1443
- ConfigurableFocusTrapFactory.ɵprov = ɵɵdefineInjectable({ factory: function ConfigurableFocusTrapFactory_Factory() { return new ConfigurableFocusTrapFactory(ɵɵinject(InteractivityChecker), ɵɵinject(NgZone), ɵɵinject(FocusTrapManager), ɵɵinject(DOCUMENT), ɵɵinject(FOCUS_TRAP_INERT_STRATEGY, 8)); }, token: ConfigurableFocusTrapFactory, providedIn: "root" });
1444
- ConfigurableFocusTrapFactory.decorators = [
1445
- { type: Injectable, args: [{ providedIn: 'root' },] }
1446
- ];
1447
- ConfigurableFocusTrapFactory.ctorParameters = () => [
1448
- { type: InteractivityChecker },
1449
- { type: NgZone },
1450
- { type: FocusTrapManager },
1451
- { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
1452
- { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [FOCUS_TRAP_INERT_STRATEGY,] }] }
1453
- ];
1454
- return ConfigurableFocusTrapFactory;
1455
- })();
1467
+ class ConfigurableFocusTrapFactory {
1468
+ constructor(_checker, _ngZone, _focusTrapManager, _document, _inertStrategy) {
1469
+ this._checker = _checker;
1470
+ this._ngZone = _ngZone;
1471
+ this._focusTrapManager = _focusTrapManager;
1472
+ this._document = _document;
1473
+ // TODO split up the strategies into different modules, similar to DateAdapter.
1474
+ this._inertStrategy = _inertStrategy || new EventListenerFocusTrapInertStrategy();
1475
+ }
1476
+ create(element, config = new ConfigurableFocusTrapConfig()) {
1477
+ let configObject;
1478
+ if (typeof config === 'boolean') {
1479
+ configObject = new ConfigurableFocusTrapConfig();
1480
+ configObject.defer = config;
1481
+ }
1482
+ else {
1483
+ configObject = config;
1484
+ }
1485
+ return new ConfigurableFocusTrap(element, this._checker, this._ngZone, this._document, this._focusTrapManager, this._inertStrategy, configObject);
1486
+ }
1487
+ }
1488
+ ConfigurableFocusTrapFactory.ɵprov = ɵɵdefineInjectable({ factory: function ConfigurableFocusTrapFactory_Factory() { return new ConfigurableFocusTrapFactory(ɵɵinject(InteractivityChecker), ɵɵinject(NgZone), ɵɵinject(FocusTrapManager), ɵɵinject(DOCUMENT), ɵɵinject(FOCUS_TRAP_INERT_STRATEGY, 8)); }, token: ConfigurableFocusTrapFactory, providedIn: "root" });
1489
+ ConfigurableFocusTrapFactory.decorators = [
1490
+ { type: Injectable, args: [{ providedIn: 'root' },] }
1491
+ ];
1492
+ ConfigurableFocusTrapFactory.ctorParameters = () => [
1493
+ { type: InteractivityChecker },
1494
+ { type: NgZone },
1495
+ { type: FocusTrapManager },
1496
+ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
1497
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [FOCUS_TRAP_INERT_STRATEGY,] }] }
1498
+ ];
1456
1499
 
1457
1500
  /**
1458
1501
  * @license
@@ -1479,164 +1522,158 @@ const LIVE_ANNOUNCER_DEFAULT_OPTIONS = new InjectionToken('LIVE_ANNOUNCER_DEFAUL
1479
1522
  * Use of this source code is governed by an MIT-style license that can be
1480
1523
  * found in the LICENSE file at https://angular.io/license
1481
1524
  */
1482
- let LiveAnnouncer = /** @class */ (() => {
1483
- class LiveAnnouncer {
1484
- constructor(elementToken, _ngZone, _document, _defaultOptions) {
1485
- this._ngZone = _ngZone;
1486
- this._defaultOptions = _defaultOptions;
1487
- // We inject the live element and document as `any` because the constructor signature cannot
1488
- // reference browser globals (HTMLElement, Document) on non-browser environments, since having
1489
- // a class decorator causes TypeScript to preserve the constructor signature types.
1490
- this._document = _document;
1491
- this._liveElement = elementToken || this._createLiveElement();
1492
- }
1493
- announce(message, ...args) {
1494
- const defaultOptions = this._defaultOptions;
1495
- let politeness;
1496
- let duration;
1497
- if (args.length === 1 && typeof args[0] === 'number') {
1498
- duration = args[0];
1499
- }
1500
- else {
1501
- [politeness, duration] = args;
1502
- }
1503
- this.clear();
1504
- clearTimeout(this._previousTimeout);
1505
- if (!politeness) {
1506
- politeness =
1507
- (defaultOptions && defaultOptions.politeness) ? defaultOptions.politeness : 'polite';
1508
- }
1509
- if (duration == null && defaultOptions) {
1510
- duration = defaultOptions.duration;
1511
- }
1512
- // TODO: ensure changing the politeness works on all environments we support.
1513
- this._liveElement.setAttribute('aria-live', politeness);
1514
- // This 100ms timeout is necessary for some browser + screen-reader combinations:
1515
- // - Both JAWS and NVDA over IE11 will not announce anything without a non-zero timeout.
1516
- // - With Chrome and IE11 with NVDA or JAWS, a repeated (identical) message won't be read a
1517
- // second time without clearing and then using a non-zero delay.
1518
- // (using JAWS 17 at time of this writing).
1519
- return this._ngZone.runOutsideAngular(() => {
1520
- return new Promise(resolve => {
1521
- clearTimeout(this._previousTimeout);
1522
- this._previousTimeout = setTimeout(() => {
1523
- this._liveElement.textContent = message;
1524
- resolve();
1525
- if (typeof duration === 'number') {
1526
- this._previousTimeout = setTimeout(() => this.clear(), duration);
1527
- }
1528
- }, 100);
1529
- });
1525
+ class LiveAnnouncer {
1526
+ constructor(elementToken, _ngZone, _document, _defaultOptions) {
1527
+ this._ngZone = _ngZone;
1528
+ this._defaultOptions = _defaultOptions;
1529
+ // We inject the live element and document as `any` because the constructor signature cannot
1530
+ // reference browser globals (HTMLElement, Document) on non-browser environments, since having
1531
+ // a class decorator causes TypeScript to preserve the constructor signature types.
1532
+ this._document = _document;
1533
+ this._liveElement = elementToken || this._createLiveElement();
1534
+ }
1535
+ announce(message, ...args) {
1536
+ const defaultOptions = this._defaultOptions;
1537
+ let politeness;
1538
+ let duration;
1539
+ if (args.length === 1 && typeof args[0] === 'number') {
1540
+ duration = args[0];
1541
+ }
1542
+ else {
1543
+ [politeness, duration] = args;
1544
+ }
1545
+ this.clear();
1546
+ clearTimeout(this._previousTimeout);
1547
+ if (!politeness) {
1548
+ politeness =
1549
+ (defaultOptions && defaultOptions.politeness) ? defaultOptions.politeness : 'polite';
1550
+ }
1551
+ if (duration == null && defaultOptions) {
1552
+ duration = defaultOptions.duration;
1553
+ }
1554
+ // TODO: ensure changing the politeness works on all environments we support.
1555
+ this._liveElement.setAttribute('aria-live', politeness);
1556
+ // This 100ms timeout is necessary for some browser + screen-reader combinations:
1557
+ // - Both JAWS and NVDA over IE11 will not announce anything without a non-zero timeout.
1558
+ // - With Chrome and IE11 with NVDA or JAWS, a repeated (identical) message won't be read a
1559
+ // second time without clearing and then using a non-zero delay.
1560
+ // (using JAWS 17 at time of this writing).
1561
+ return this._ngZone.runOutsideAngular(() => {
1562
+ return new Promise(resolve => {
1563
+ clearTimeout(this._previousTimeout);
1564
+ this._previousTimeout = setTimeout(() => {
1565
+ this._liveElement.textContent = message;
1566
+ resolve();
1567
+ if (typeof duration === 'number') {
1568
+ this._previousTimeout = setTimeout(() => this.clear(), duration);
1569
+ }
1570
+ }, 100);
1530
1571
  });
1572
+ });
1573
+ }
1574
+ /**
1575
+ * Clears the current text from the announcer element. Can be used to prevent
1576
+ * screen readers from reading the text out again while the user is going
1577
+ * through the page landmarks.
1578
+ */
1579
+ clear() {
1580
+ if (this._liveElement) {
1581
+ this._liveElement.textContent = '';
1531
1582
  }
1532
- /**
1533
- * Clears the current text from the announcer element. Can be used to prevent
1534
- * screen readers from reading the text out again while the user is going
1535
- * through the page landmarks.
1536
- */
1537
- clear() {
1538
- if (this._liveElement) {
1539
- this._liveElement.textContent = '';
1540
- }
1583
+ }
1584
+ ngOnDestroy() {
1585
+ clearTimeout(this._previousTimeout);
1586
+ if (this._liveElement && this._liveElement.parentNode) {
1587
+ this._liveElement.parentNode.removeChild(this._liveElement);
1588
+ this._liveElement = null;
1541
1589
  }
1542
- ngOnDestroy() {
1543
- clearTimeout(this._previousTimeout);
1544
- if (this._liveElement && this._liveElement.parentNode) {
1545
- this._liveElement.parentNode.removeChild(this._liveElement);
1546
- this._liveElement = null;
1547
- }
1590
+ }
1591
+ _createLiveElement() {
1592
+ const elementClass = 'cdk-live-announcer-element';
1593
+ const previousElements = this._document.getElementsByClassName(elementClass);
1594
+ const liveEl = this._document.createElement('div');
1595
+ // Remove any old containers. This can happen when coming in from a server-side-rendered page.
1596
+ for (let i = 0; i < previousElements.length; i++) {
1597
+ previousElements[i].parentNode.removeChild(previousElements[i]);
1548
1598
  }
1549
- _createLiveElement() {
1550
- const elementClass = 'cdk-live-announcer-element';
1551
- const previousElements = this._document.getElementsByClassName(elementClass);
1552
- const liveEl = this._document.createElement('div');
1553
- // Remove any old containers. This can happen when coming in from a server-side-rendered page.
1554
- for (let i = 0; i < previousElements.length; i++) {
1555
- previousElements[i].parentNode.removeChild(previousElements[i]);
1556
- }
1557
- liveEl.classList.add(elementClass);
1558
- liveEl.classList.add('cdk-visually-hidden');
1559
- liveEl.setAttribute('aria-atomic', 'true');
1560
- liveEl.setAttribute('aria-live', 'polite');
1561
- this._document.body.appendChild(liveEl);
1562
- return liveEl;
1563
- }
1564
- }
1565
- LiveAnnouncer.ɵprov = ɵɵdefineInjectable({ factory: function LiveAnnouncer_Factory() { return new LiveAnnouncer(ɵɵinject(LIVE_ANNOUNCER_ELEMENT_TOKEN, 8), ɵɵinject(NgZone), ɵɵinject(DOCUMENT), ɵɵinject(LIVE_ANNOUNCER_DEFAULT_OPTIONS, 8)); }, token: LiveAnnouncer, providedIn: "root" });
1566
- LiveAnnouncer.decorators = [
1567
- { type: Injectable, args: [{ providedIn: 'root' },] }
1568
- ];
1569
- LiveAnnouncer.ctorParameters = () => [
1570
- { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [LIVE_ANNOUNCER_ELEMENT_TOKEN,] }] },
1571
- { type: NgZone },
1572
- { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
1573
- { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [LIVE_ANNOUNCER_DEFAULT_OPTIONS,] }] }
1574
- ];
1575
- return LiveAnnouncer;
1576
- })();
1599
+ liveEl.classList.add(elementClass);
1600
+ liveEl.classList.add('cdk-visually-hidden');
1601
+ liveEl.setAttribute('aria-atomic', 'true');
1602
+ liveEl.setAttribute('aria-live', 'polite');
1603
+ this._document.body.appendChild(liveEl);
1604
+ return liveEl;
1605
+ }
1606
+ }
1607
+ LiveAnnouncer.ɵprov = ɵɵdefineInjectable({ factory: function LiveAnnouncer_Factory() { return new LiveAnnouncer(ɵɵinject(LIVE_ANNOUNCER_ELEMENT_TOKEN, 8), ɵɵinject(NgZone), ɵɵinject(DOCUMENT), ɵɵinject(LIVE_ANNOUNCER_DEFAULT_OPTIONS, 8)); }, token: LiveAnnouncer, providedIn: "root" });
1608
+ LiveAnnouncer.decorators = [
1609
+ { type: Injectable, args: [{ providedIn: 'root' },] }
1610
+ ];
1611
+ LiveAnnouncer.ctorParameters = () => [
1612
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [LIVE_ANNOUNCER_ELEMENT_TOKEN,] }] },
1613
+ { type: NgZone },
1614
+ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
1615
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [LIVE_ANNOUNCER_DEFAULT_OPTIONS,] }] }
1616
+ ];
1577
1617
  /**
1578
1618
  * A directive that works similarly to aria-live, but uses the LiveAnnouncer to ensure compatibility
1579
1619
  * with a wider range of browsers and screen readers.
1580
1620
  */
1581
- let CdkAriaLive = /** @class */ (() => {
1582
- class CdkAriaLive {
1583
- constructor(_elementRef, _liveAnnouncer, _contentObserver, _ngZone) {
1584
- this._elementRef = _elementRef;
1585
- this._liveAnnouncer = _liveAnnouncer;
1586
- this._contentObserver = _contentObserver;
1587
- this._ngZone = _ngZone;
1588
- this._politeness = 'off';
1589
- }
1590
- /** The aria-live politeness level to use when announcing messages. */
1591
- get politeness() { return this._politeness; }
1592
- set politeness(value) {
1593
- this._politeness = value === 'polite' || value === 'assertive' ? value : 'off';
1594
- if (this._politeness === 'off') {
1595
- if (this._subscription) {
1596
- this._subscription.unsubscribe();
1597
- this._subscription = null;
1598
- }
1599
- }
1600
- else if (!this._subscription) {
1601
- this._subscription = this._ngZone.runOutsideAngular(() => {
1602
- return this._contentObserver
1603
- .observe(this._elementRef)
1604
- .subscribe(() => {
1605
- // Note that we use textContent here, rather than innerText, in order to avoid a reflow.
1606
- const elementText = this._elementRef.nativeElement.textContent;
1607
- // The `MutationObserver` fires also for attribute
1608
- // changes which we don't want to announce.
1609
- if (elementText !== this._previousAnnouncedText) {
1610
- this._liveAnnouncer.announce(elementText, this._politeness);
1611
- this._previousAnnouncedText = elementText;
1612
- }
1613
- });
1614
- });
1615
- }
1616
- }
1617
- ngOnDestroy() {
1621
+ class CdkAriaLive {
1622
+ constructor(_elementRef, _liveAnnouncer, _contentObserver, _ngZone) {
1623
+ this._elementRef = _elementRef;
1624
+ this._liveAnnouncer = _liveAnnouncer;
1625
+ this._contentObserver = _contentObserver;
1626
+ this._ngZone = _ngZone;
1627
+ this._politeness = 'off';
1628
+ }
1629
+ /** The aria-live politeness level to use when announcing messages. */
1630
+ get politeness() { return this._politeness; }
1631
+ set politeness(value) {
1632
+ this._politeness = value === 'polite' || value === 'assertive' ? value : 'off';
1633
+ if (this._politeness === 'off') {
1618
1634
  if (this._subscription) {
1619
1635
  this._subscription.unsubscribe();
1620
- }
1636
+ this._subscription = null;
1637
+ }
1638
+ }
1639
+ else if (!this._subscription) {
1640
+ this._subscription = this._ngZone.runOutsideAngular(() => {
1641
+ return this._contentObserver
1642
+ .observe(this._elementRef)
1643
+ .subscribe(() => {
1644
+ // Note that we use textContent here, rather than innerText, in order to avoid a reflow.
1645
+ const elementText = this._elementRef.nativeElement.textContent;
1646
+ // The `MutationObserver` fires also for attribute
1647
+ // changes which we don't want to announce.
1648
+ if (elementText !== this._previousAnnouncedText) {
1649
+ this._liveAnnouncer.announce(elementText, this._politeness);
1650
+ this._previousAnnouncedText = elementText;
1651
+ }
1652
+ });
1653
+ });
1621
1654
  }
1622
1655
  }
1623
- CdkAriaLive.decorators = [
1624
- { type: Directive, args: [{
1625
- selector: '[cdkAriaLive]',
1626
- exportAs: 'cdkAriaLive',
1627
- },] }
1628
- ];
1629
- CdkAriaLive.ctorParameters = () => [
1630
- { type: ElementRef },
1631
- { type: LiveAnnouncer },
1632
- { type: ContentObserver },
1633
- { type: NgZone }
1634
- ];
1635
- CdkAriaLive.propDecorators = {
1636
- politeness: [{ type: Input, args: ['cdkAriaLive',] }]
1637
- };
1638
- return CdkAriaLive;
1639
- })();
1656
+ ngOnDestroy() {
1657
+ if (this._subscription) {
1658
+ this._subscription.unsubscribe();
1659
+ }
1660
+ }
1661
+ }
1662
+ CdkAriaLive.decorators = [
1663
+ { type: Directive, args: [{
1664
+ selector: '[cdkAriaLive]',
1665
+ exportAs: 'cdkAriaLive',
1666
+ },] }
1667
+ ];
1668
+ CdkAriaLive.ctorParameters = () => [
1669
+ { type: ElementRef },
1670
+ { type: LiveAnnouncer },
1671
+ { type: ContentObserver },
1672
+ { type: NgZone }
1673
+ ];
1674
+ CdkAriaLive.propDecorators = {
1675
+ politeness: [{ type: Input, args: ['cdkAriaLive',] }]
1676
+ };
1640
1677
 
1641
1678
  /**
1642
1679
  * @license
@@ -1677,342 +1714,339 @@ const captureEventListenerOptions = normalizePassiveListenerOptions({
1677
1714
  capture: true
1678
1715
  });
1679
1716
  /** Monitors mouse and keyboard events to determine the cause of focus events. */
1680
- let FocusMonitor = /** @class */ (() => {
1681
- class FocusMonitor {
1682
- constructor(_ngZone, _platform,
1683
- /** @breaking-change 11.0.0 make document required */
1684
- document, options) {
1685
- this._ngZone = _ngZone;
1686
- this._platform = _platform;
1687
- /** The focus origin that the next focus event is a result of. */
1688
- this._origin = null;
1689
- /** Whether the window has just been focused. */
1690
- this._windowFocused = false;
1691
- /** Map of elements being monitored to their info. */
1692
- this._elementInfo = new Map();
1693
- /** The number of elements currently being monitored. */
1694
- this._monitoredElementCount = 0;
1695
- /**
1696
- * Keeps track of the root nodes to which we've currently bound a focus/blur handler,
1697
- * as well as the number of monitored elements that they contain. We have to treat focus/blur
1698
- * handlers differently from the rest of the events, because the browser won't emit events
1699
- * to the document when focus moves inside of a shadow root.
1700
- */
1701
- this._rootNodeFocusListenerCount = new Map();
1702
- /**
1703
- * Event listener for `keydown` events on the document.
1704
- * Needs to be an arrow function in order to preserve the context when it gets bound.
1705
- */
1706
- this._documentKeydownListener = () => {
1707
- // On keydown record the origin and clear any touch event that may be in progress.
1708
- this._lastTouchTarget = null;
1709
- this._setOriginForCurrentEventQueue('keyboard');
1710
- };
1711
- /**
1712
- * Event listener for `mousedown` events on the document.
1713
- * Needs to be an arrow function in order to preserve the context when it gets bound.
1714
- */
1715
- this._documentMousedownListener = (event) => {
1716
- // On mousedown record the origin only if there is not touch
1717
- // target, since a mousedown can happen as a result of a touch event.
1718
- if (!this._lastTouchTarget) {
1719
- // In some cases screen readers fire fake `mousedown` events instead of `keydown`.
1720
- // Resolve the focus source to `keyboard` if we detect one of them.
1721
- const source = isFakeMousedownFromScreenReader(event) ? 'keyboard' : 'mouse';
1722
- this._setOriginForCurrentEventQueue(source);
1723
- }
1724
- };
1725
- /**
1726
- * Event listener for `touchstart` events on the document.
1727
- * Needs to be an arrow function in order to preserve the context when it gets bound.
1728
- */
1729
- this._documentTouchstartListener = (event) => {
1730
- // When the touchstart event fires the focus event is not yet in the event queue. This means
1731
- // we can't rely on the trick used above (setting timeout of 1ms). Instead we wait 650ms to
1732
- // see if a focus happens.
1733
- if (this._touchTimeoutId != null) {
1734
- clearTimeout(this._touchTimeoutId);
1735
- }
1736
- this._lastTouchTarget = getTarget(event);
1737
- this._touchTimeoutId = setTimeout(() => this._lastTouchTarget = null, TOUCH_BUFFER_MS);
1738
- };
1739
- /**
1740
- * Event listener for `focus` events on the window.
1741
- * Needs to be an arrow function in order to preserve the context when it gets bound.
1742
- */
1743
- this._windowFocusListener = () => {
1744
- // Make a note of when the window regains focus, so we can
1745
- // restore the origin info for the focused element.
1746
- this._windowFocused = true;
1747
- this._windowFocusTimeoutId = setTimeout(() => this._windowFocused = false);
1748
- };
1749
- /**
1750
- * Event listener for `focus` and 'blur' events on the document.
1751
- * Needs to be an arrow function in order to preserve the context when it gets bound.
1752
- */
1753
- this._rootNodeFocusAndBlurListener = (event) => {
1754
- const target = getTarget(event);
1755
- const handler = event.type === 'focus' ? this._onFocus : this._onBlur;
1756
- // We need to walk up the ancestor chain in order to support `checkChildren`.
1757
- for (let element = target; element; element = element.parentElement) {
1758
- handler.call(this, event, element);
1759
- }
1760
- };
1761
- this._document = document;
1762
- this._detectionMode = (options === null || options === void 0 ? void 0 : options.detectionMode) || 0 /* IMMEDIATE */;
1763
- }
1764
- monitor(element, checkChildren = false) {
1765
- // Do nothing if we're not on the browser platform.
1766
- if (!this._platform.isBrowser) {
1767
- return of(null);
1768
- }
1769
- const nativeElement = coerceElement(element);
1770
- // If the element is inside the shadow DOM, we need to bind our focus/blur listeners to
1771
- // the shadow root, rather than the `document`, because the browser won't emit focus events
1772
- // to the `document`, if focus is moving within the same shadow root.
1773
- const rootNode = _getShadowRoot(nativeElement) || this._getDocument();
1774
- const cachedInfo = this._elementInfo.get(nativeElement);
1775
- // Check if we're already monitoring this element.
1776
- if (cachedInfo) {
1777
- if (checkChildren) {
1778
- // TODO(COMP-318): this can be problematic, because it'll turn all non-checkChildren
1779
- // observers into ones that behave as if `checkChildren` was turned on. We need a more
1780
- // robust solution.
1781
- cachedInfo.checkChildren = true;
1782
- }
1783
- return cachedInfo.subject.asObservable();
1784
- }
1785
- // Create monitored element info.
1786
- const info = {
1787
- checkChildren: checkChildren,
1788
- subject: new Subject(),
1789
- rootNode
1790
- };
1791
- this._elementInfo.set(nativeElement, info);
1792
- this._registerGlobalListeners(info);
1793
- return info.subject.asObservable();
1794
- }
1795
- stopMonitoring(element) {
1796
- const nativeElement = coerceElement(element);
1797
- const elementInfo = this._elementInfo.get(nativeElement);
1798
- if (elementInfo) {
1799
- elementInfo.subject.complete();
1800
- this._setClasses(nativeElement);
1801
- this._elementInfo.delete(nativeElement);
1802
- this._removeGlobalListeners(elementInfo);
1803
- }
1804
- }
1805
- focusVia(element, origin, options) {
1806
- const nativeElement = coerceElement(element);
1807
- this._setOriginForCurrentEventQueue(origin);
1808
- // `focus` isn't available on the server
1809
- if (typeof nativeElement.focus === 'function') {
1810
- // Cast the element to `any`, because the TS typings don't have the `options` parameter yet.
1811
- nativeElement.focus(options);
1812
- }
1813
- }
1814
- ngOnDestroy() {
1815
- this._elementInfo.forEach((_info, element) => this.stopMonitoring(element));
1816
- }
1817
- /** Access injected document if available or fallback to global document reference */
1818
- _getDocument() {
1819
- return this._document || document;
1820
- }
1821
- /** Use defaultView of injected document if available or fallback to global window reference */
1822
- _getWindow() {
1823
- const doc = this._getDocument();
1824
- return doc.defaultView || window;
1825
- }
1826
- _toggleClass(element, className, shouldSet) {
1827
- if (shouldSet) {
1828
- element.classList.add(className);
1829
- }
1830
- else {
1831
- element.classList.remove(className);
1832
- }
1833
- }
1834
- _getFocusOrigin(event) {
1835
- // If we couldn't detect a cause for the focus event, it's due to one of three reasons:
1836
- // 1) The window has just regained focus, in which case we want to restore the focused state of
1837
- // the element from before the window blurred.
1838
- // 2) It was caused by a touch event, in which case we mark the origin as 'touch'.
1839
- // 3) The element was programmatically focused, in which case we should mark the origin as
1840
- // 'program'.
1841
- if (this._origin) {
1842
- return this._origin;
1843
- }
1844
- if (this._windowFocused && this._lastFocusOrigin) {
1845
- return this._lastFocusOrigin;
1846
- }
1847
- else if (this._wasCausedByTouch(event)) {
1848
- return 'touch';
1849
- }
1850
- else {
1851
- return 'program';
1852
- }
1853
- }
1717
+ class FocusMonitor {
1718
+ constructor(_ngZone, _platform,
1719
+ /** @breaking-change 11.0.0 make document required */
1720
+ document, options) {
1721
+ this._ngZone = _ngZone;
1722
+ this._platform = _platform;
1723
+ /** The focus origin that the next focus event is a result of. */
1724
+ this._origin = null;
1725
+ /** Whether the window has just been focused. */
1726
+ this._windowFocused = false;
1727
+ /** Map of elements being monitored to their info. */
1728
+ this._elementInfo = new Map();
1729
+ /** The number of elements currently being monitored. */
1730
+ this._monitoredElementCount = 0;
1854
1731
  /**
1855
- * Sets the focus classes on the element based on the given focus origin.
1856
- * @param element The element to update the classes on.
1857
- * @param origin The focus origin.
1732
+ * Keeps track of the root nodes to which we've currently bound a focus/blur handler,
1733
+ * as well as the number of monitored elements that they contain. We have to treat focus/blur
1734
+ * handlers differently from the rest of the events, because the browser won't emit events
1735
+ * to the document when focus moves inside of a shadow root.
1858
1736
  */
1859
- _setClasses(element, origin) {
1860
- this._toggleClass(element, 'cdk-focused', !!origin);
1861
- this._toggleClass(element, 'cdk-touch-focused', origin === 'touch');
1862
- this._toggleClass(element, 'cdk-keyboard-focused', origin === 'keyboard');
1863
- this._toggleClass(element, 'cdk-mouse-focused', origin === 'mouse');
1864
- this._toggleClass(element, 'cdk-program-focused', origin === 'program');
1865
- }
1737
+ this._rootNodeFocusListenerCount = new Map();
1866
1738
  /**
1867
- * Sets the origin and schedules an async function to clear it at the end of the event queue.
1868
- * If the detection mode is 'eventual', the origin is never cleared.
1869
- * @param origin The origin to set.
1739
+ * Event listener for `keydown` events on the document.
1740
+ * Needs to be an arrow function in order to preserve the context when it gets bound.
1870
1741
  */
1871
- _setOriginForCurrentEventQueue(origin) {
1872
- this._ngZone.runOutsideAngular(() => {
1873
- this._origin = origin;
1874
- if (this._detectionMode === 0 /* IMMEDIATE */) {
1875
- // Sometimes the focus origin won't be valid in Firefox because Firefox seems to focus *one*
1876
- // tick after the interaction event fired. To ensure the focus origin is always correct,
1877
- // the focus origin will be determined at the beginning of the next tick.
1878
- this._originTimeoutId = setTimeout(() => this._origin = null, 1);
1879
- }
1880
- });
1881
- }
1742
+ this._documentKeydownListener = () => {
1743
+ // On keydown record the origin and clear any touch event that may be in progress.
1744
+ this._lastTouchTarget = null;
1745
+ this._setOriginForCurrentEventQueue('keyboard');
1746
+ };
1882
1747
  /**
1883
- * Checks whether the given focus event was caused by a touchstart event.
1884
- * @param event The focus event to check.
1885
- * @returns Whether the event was caused by a touch.
1748
+ * Event listener for `mousedown` events on the document.
1749
+ * Needs to be an arrow function in order to preserve the context when it gets bound.
1886
1750
  */
1887
- _wasCausedByTouch(event) {
1888
- // Note(mmalerba): This implementation is not quite perfect, there is a small edge case.
1889
- // Consider the following dom structure:
1890
- //
1891
- // <div #parent tabindex="0" cdkFocusClasses>
1892
- // <div #child (click)="#parent.focus()"></div>
1893
- // </div>
1894
- //
1895
- // If the user touches the #child element and the #parent is programmatically focused as a
1896
- // result, this code will still consider it to have been caused by the touch event and will
1897
- // apply the cdk-touch-focused class rather than the cdk-program-focused class. This is a
1898
- // relatively small edge-case that can be worked around by using
1899
- // focusVia(parentEl, 'program') to focus the parent element.
1900
- //
1901
- // If we decide that we absolutely must handle this case correctly, we can do so by listening
1902
- // for the first focus event after the touchstart, and then the first blur event after that
1903
- // focus event. When that blur event fires we know that whatever follows is not a result of the
1904
- // touchstart.
1905
- const focusTarget = getTarget(event);
1906
- return this._lastTouchTarget instanceof Node && focusTarget instanceof Node &&
1907
- (focusTarget === this._lastTouchTarget || focusTarget.contains(this._lastTouchTarget));
1908
- }
1751
+ this._documentMousedownListener = (event) => {
1752
+ // On mousedown record the origin only if there is not touch
1753
+ // target, since a mousedown can happen as a result of a touch event.
1754
+ if (!this._lastTouchTarget) {
1755
+ // In some cases screen readers fire fake `mousedown` events instead of `keydown`.
1756
+ // Resolve the focus source to `keyboard` if we detect one of them.
1757
+ const source = isFakeMousedownFromScreenReader(event) ? 'keyboard' : 'mouse';
1758
+ this._setOriginForCurrentEventQueue(source);
1759
+ }
1760
+ };
1909
1761
  /**
1910
- * Handles focus events on a registered element.
1911
- * @param event The focus event.
1912
- * @param element The monitored element.
1762
+ * Event listener for `touchstart` events on the document.
1763
+ * Needs to be an arrow function in order to preserve the context when it gets bound.
1913
1764
  */
1914
- _onFocus(event, element) {
1915
- // NOTE(mmalerba): We currently set the classes based on the focus origin of the most recent
1916
- // focus event affecting the monitored element. If we want to use the origin of the first event
1917
- // instead we should check for the cdk-focused class here and return if the element already has
1918
- // it. (This only matters for elements that have includesChildren = true).
1919
- // If we are not counting child-element-focus as focused, make sure that the event target is the
1920
- // monitored element itself.
1921
- const elementInfo = this._elementInfo.get(element);
1922
- if (!elementInfo || (!elementInfo.checkChildren && element !== getTarget(event))) {
1923
- return;
1765
+ this._documentTouchstartListener = (event) => {
1766
+ // When the touchstart event fires the focus event is not yet in the event queue. This means
1767
+ // we can't rely on the trick used above (setting timeout of 1ms). Instead we wait 650ms to
1768
+ // see if a focus happens.
1769
+ if (this._touchTimeoutId != null) {
1770
+ clearTimeout(this._touchTimeoutId);
1924
1771
  }
1925
- const origin = this._getFocusOrigin(event);
1926
- this._setClasses(element, origin);
1927
- this._emitOrigin(elementInfo.subject, origin);
1928
- this._lastFocusOrigin = origin;
1929
- }
1772
+ this._lastTouchTarget = getTarget(event);
1773
+ this._touchTimeoutId = setTimeout(() => this._lastTouchTarget = null, TOUCH_BUFFER_MS);
1774
+ };
1930
1775
  /**
1931
- * Handles blur events on a registered element.
1932
- * @param event The blur event.
1933
- * @param element The monitored element.
1776
+ * Event listener for `focus` events on the window.
1777
+ * Needs to be an arrow function in order to preserve the context when it gets bound.
1934
1778
  */
1935
- _onBlur(event, element) {
1936
- // If we are counting child-element-focus as focused, make sure that we aren't just blurring in
1937
- // order to focus another child of the monitored element.
1938
- const elementInfo = this._elementInfo.get(element);
1939
- if (!elementInfo || (elementInfo.checkChildren && event.relatedTarget instanceof Node &&
1940
- element.contains(event.relatedTarget))) {
1941
- return;
1942
- }
1943
- this._setClasses(element);
1944
- this._emitOrigin(elementInfo.subject, null);
1779
+ this._windowFocusListener = () => {
1780
+ // Make a note of when the window regains focus, so we can
1781
+ // restore the origin info for the focused element.
1782
+ this._windowFocused = true;
1783
+ this._windowFocusTimeoutId = setTimeout(() => this._windowFocused = false);
1784
+ };
1785
+ /**
1786
+ * Event listener for `focus` and 'blur' events on the document.
1787
+ * Needs to be an arrow function in order to preserve the context when it gets bound.
1788
+ */
1789
+ this._rootNodeFocusAndBlurListener = (event) => {
1790
+ const target = getTarget(event);
1791
+ const handler = event.type === 'focus' ? this._onFocus : this._onBlur;
1792
+ // We need to walk up the ancestor chain in order to support `checkChildren`.
1793
+ for (let element = target; element; element = element.parentElement) {
1794
+ handler.call(this, event, element);
1795
+ }
1796
+ };
1797
+ this._document = document;
1798
+ this._detectionMode = (options === null || options === void 0 ? void 0 : options.detectionMode) || 0 /* IMMEDIATE */;
1799
+ }
1800
+ monitor(element, checkChildren = false) {
1801
+ // Do nothing if we're not on the browser platform.
1802
+ if (!this._platform.isBrowser) {
1803
+ return of(null);
1804
+ }
1805
+ const nativeElement = coerceElement(element);
1806
+ // If the element is inside the shadow DOM, we need to bind our focus/blur listeners to
1807
+ // the shadow root, rather than the `document`, because the browser won't emit focus events
1808
+ // to the `document`, if focus is moving within the same shadow root.
1809
+ const rootNode = _getShadowRoot(nativeElement) || this._getDocument();
1810
+ const cachedInfo = this._elementInfo.get(nativeElement);
1811
+ // Check if we're already monitoring this element.
1812
+ if (cachedInfo) {
1813
+ if (checkChildren) {
1814
+ // TODO(COMP-318): this can be problematic, because it'll turn all non-checkChildren
1815
+ // observers into ones that behave as if `checkChildren` was turned on. We need a more
1816
+ // robust solution.
1817
+ cachedInfo.checkChildren = true;
1818
+ }
1819
+ return cachedInfo.subject.asObservable();
1820
+ }
1821
+ // Create monitored element info.
1822
+ const info = {
1823
+ checkChildren: checkChildren,
1824
+ subject: new Subject(),
1825
+ rootNode
1826
+ };
1827
+ this._elementInfo.set(nativeElement, info);
1828
+ this._registerGlobalListeners(info);
1829
+ return info.subject.asObservable();
1830
+ }
1831
+ stopMonitoring(element) {
1832
+ const nativeElement = coerceElement(element);
1833
+ const elementInfo = this._elementInfo.get(nativeElement);
1834
+ if (elementInfo) {
1835
+ elementInfo.subject.complete();
1836
+ this._setClasses(nativeElement);
1837
+ this._elementInfo.delete(nativeElement);
1838
+ this._removeGlobalListeners(elementInfo);
1839
+ }
1840
+ }
1841
+ focusVia(element, origin, options) {
1842
+ const nativeElement = coerceElement(element);
1843
+ this._setOriginForCurrentEventQueue(origin);
1844
+ // `focus` isn't available on the server
1845
+ if (typeof nativeElement.focus === 'function') {
1846
+ // Cast the element to `any`, because the TS typings don't have the `options` parameter yet.
1847
+ nativeElement.focus(options);
1848
+ }
1849
+ }
1850
+ ngOnDestroy() {
1851
+ this._elementInfo.forEach((_info, element) => this.stopMonitoring(element));
1852
+ }
1853
+ /** Access injected document if available or fallback to global document reference */
1854
+ _getDocument() {
1855
+ return this._document || document;
1856
+ }
1857
+ /** Use defaultView of injected document if available or fallback to global window reference */
1858
+ _getWindow() {
1859
+ const doc = this._getDocument();
1860
+ return doc.defaultView || window;
1861
+ }
1862
+ _toggleClass(element, className, shouldSet) {
1863
+ if (shouldSet) {
1864
+ element.classList.add(className);
1945
1865
  }
1946
- _emitOrigin(subject, origin) {
1947
- this._ngZone.run(() => subject.next(origin));
1866
+ else {
1867
+ element.classList.remove(className);
1948
1868
  }
1949
- _registerGlobalListeners(elementInfo) {
1950
- if (!this._platform.isBrowser) {
1951
- return;
1952
- }
1953
- const rootNode = elementInfo.rootNode;
1954
- const rootNodeFocusListeners = this._rootNodeFocusListenerCount.get(rootNode) || 0;
1955
- if (!rootNodeFocusListeners) {
1956
- this._ngZone.runOutsideAngular(() => {
1957
- rootNode.addEventListener('focus', this._rootNodeFocusAndBlurListener, captureEventListenerOptions);
1958
- rootNode.addEventListener('blur', this._rootNodeFocusAndBlurListener, captureEventListenerOptions);
1959
- });
1960
- }
1961
- this._rootNodeFocusListenerCount.set(rootNode, rootNodeFocusListeners + 1);
1962
- // Register global listeners when first element is monitored.
1963
- if (++this._monitoredElementCount === 1) {
1964
- // Note: we listen to events in the capture phase so we
1965
- // can detect them even if the user stops propagation.
1966
- this._ngZone.runOutsideAngular(() => {
1967
- const document = this._getDocument();
1968
- const window = this._getWindow();
1969
- document.addEventListener('keydown', this._documentKeydownListener, captureEventListenerOptions);
1970
- document.addEventListener('mousedown', this._documentMousedownListener, captureEventListenerOptions);
1971
- document.addEventListener('touchstart', this._documentTouchstartListener, captureEventListenerOptions);
1972
- window.addEventListener('focus', this._windowFocusListener);
1973
- });
1974
- }
1869
+ }
1870
+ _getFocusOrigin(event) {
1871
+ // If we couldn't detect a cause for the focus event, it's due to one of three reasons:
1872
+ // 1) The window has just regained focus, in which case we want to restore the focused state of
1873
+ // the element from before the window blurred.
1874
+ // 2) It was caused by a touch event, in which case we mark the origin as 'touch'.
1875
+ // 3) The element was programmatically focused, in which case we should mark the origin as
1876
+ // 'program'.
1877
+ if (this._origin) {
1878
+ return this._origin;
1975
1879
  }
1976
- _removeGlobalListeners(elementInfo) {
1977
- const rootNode = elementInfo.rootNode;
1978
- if (this._rootNodeFocusListenerCount.has(rootNode)) {
1979
- const rootNodeFocusListeners = this._rootNodeFocusListenerCount.get(rootNode);
1980
- if (rootNodeFocusListeners > 1) {
1981
- this._rootNodeFocusListenerCount.set(rootNode, rootNodeFocusListeners - 1);
1982
- }
1983
- else {
1984
- rootNode.removeEventListener('focus', this._rootNodeFocusAndBlurListener, captureEventListenerOptions);
1985
- rootNode.removeEventListener('blur', this._rootNodeFocusAndBlurListener, captureEventListenerOptions);
1986
- this._rootNodeFocusListenerCount.delete(rootNode);
1987
- }
1880
+ if (this._windowFocused && this._lastFocusOrigin) {
1881
+ return this._lastFocusOrigin;
1882
+ }
1883
+ else if (this._wasCausedByTouch(event)) {
1884
+ return 'touch';
1885
+ }
1886
+ else {
1887
+ return 'program';
1888
+ }
1889
+ }
1890
+ /**
1891
+ * Sets the focus classes on the element based on the given focus origin.
1892
+ * @param element The element to update the classes on.
1893
+ * @param origin The focus origin.
1894
+ */
1895
+ _setClasses(element, origin) {
1896
+ this._toggleClass(element, 'cdk-focused', !!origin);
1897
+ this._toggleClass(element, 'cdk-touch-focused', origin === 'touch');
1898
+ this._toggleClass(element, 'cdk-keyboard-focused', origin === 'keyboard');
1899
+ this._toggleClass(element, 'cdk-mouse-focused', origin === 'mouse');
1900
+ this._toggleClass(element, 'cdk-program-focused', origin === 'program');
1901
+ }
1902
+ /**
1903
+ * Sets the origin and schedules an async function to clear it at the end of the event queue.
1904
+ * If the detection mode is 'eventual', the origin is never cleared.
1905
+ * @param origin The origin to set.
1906
+ */
1907
+ _setOriginForCurrentEventQueue(origin) {
1908
+ this._ngZone.runOutsideAngular(() => {
1909
+ this._origin = origin;
1910
+ if (this._detectionMode === 0 /* IMMEDIATE */) {
1911
+ // Sometimes the focus origin won't be valid in Firefox because Firefox seems to focus *one*
1912
+ // tick after the interaction event fired. To ensure the focus origin is always correct,
1913
+ // the focus origin will be determined at the beginning of the next tick.
1914
+ this._originTimeoutId = setTimeout(() => this._origin = null, 1);
1988
1915
  }
1989
- // Unregister global listeners when last element is unmonitored.
1990
- if (!--this._monitoredElementCount) {
1916
+ });
1917
+ }
1918
+ /**
1919
+ * Checks whether the given focus event was caused by a touchstart event.
1920
+ * @param event The focus event to check.
1921
+ * @returns Whether the event was caused by a touch.
1922
+ */
1923
+ _wasCausedByTouch(event) {
1924
+ // Note(mmalerba): This implementation is not quite perfect, there is a small edge case.
1925
+ // Consider the following dom structure:
1926
+ //
1927
+ // <div #parent tabindex="0" cdkFocusClasses>
1928
+ // <div #child (click)="#parent.focus()"></div>
1929
+ // </div>
1930
+ //
1931
+ // If the user touches the #child element and the #parent is programmatically focused as a
1932
+ // result, this code will still consider it to have been caused by the touch event and will
1933
+ // apply the cdk-touch-focused class rather than the cdk-program-focused class. This is a
1934
+ // relatively small edge-case that can be worked around by using
1935
+ // focusVia(parentEl, 'program') to focus the parent element.
1936
+ //
1937
+ // If we decide that we absolutely must handle this case correctly, we can do so by listening
1938
+ // for the first focus event after the touchstart, and then the first blur event after that
1939
+ // focus event. When that blur event fires we know that whatever follows is not a result of the
1940
+ // touchstart.
1941
+ const focusTarget = getTarget(event);
1942
+ return this._lastTouchTarget instanceof Node && focusTarget instanceof Node &&
1943
+ (focusTarget === this._lastTouchTarget || focusTarget.contains(this._lastTouchTarget));
1944
+ }
1945
+ /**
1946
+ * Handles focus events on a registered element.
1947
+ * @param event The focus event.
1948
+ * @param element The monitored element.
1949
+ */
1950
+ _onFocus(event, element) {
1951
+ // NOTE(mmalerba): We currently set the classes based on the focus origin of the most recent
1952
+ // focus event affecting the monitored element. If we want to use the origin of the first event
1953
+ // instead we should check for the cdk-focused class here and return if the element already has
1954
+ // it. (This only matters for elements that have includesChildren = true).
1955
+ // If we are not counting child-element-focus as focused, make sure that the event target is the
1956
+ // monitored element itself.
1957
+ const elementInfo = this._elementInfo.get(element);
1958
+ if (!elementInfo || (!elementInfo.checkChildren && element !== getTarget(event))) {
1959
+ return;
1960
+ }
1961
+ const origin = this._getFocusOrigin(event);
1962
+ this._setClasses(element, origin);
1963
+ this._emitOrigin(elementInfo.subject, origin);
1964
+ this._lastFocusOrigin = origin;
1965
+ }
1966
+ /**
1967
+ * Handles blur events on a registered element.
1968
+ * @param event The blur event.
1969
+ * @param element The monitored element.
1970
+ */
1971
+ _onBlur(event, element) {
1972
+ // If we are counting child-element-focus as focused, make sure that we aren't just blurring in
1973
+ // order to focus another child of the monitored element.
1974
+ const elementInfo = this._elementInfo.get(element);
1975
+ if (!elementInfo || (elementInfo.checkChildren && event.relatedTarget instanceof Node &&
1976
+ element.contains(event.relatedTarget))) {
1977
+ return;
1978
+ }
1979
+ this._setClasses(element);
1980
+ this._emitOrigin(elementInfo.subject, null);
1981
+ }
1982
+ _emitOrigin(subject, origin) {
1983
+ this._ngZone.run(() => subject.next(origin));
1984
+ }
1985
+ _registerGlobalListeners(elementInfo) {
1986
+ if (!this._platform.isBrowser) {
1987
+ return;
1988
+ }
1989
+ const rootNode = elementInfo.rootNode;
1990
+ const rootNodeFocusListeners = this._rootNodeFocusListenerCount.get(rootNode) || 0;
1991
+ if (!rootNodeFocusListeners) {
1992
+ this._ngZone.runOutsideAngular(() => {
1993
+ rootNode.addEventListener('focus', this._rootNodeFocusAndBlurListener, captureEventListenerOptions);
1994
+ rootNode.addEventListener('blur', this._rootNodeFocusAndBlurListener, captureEventListenerOptions);
1995
+ });
1996
+ }
1997
+ this._rootNodeFocusListenerCount.set(rootNode, rootNodeFocusListeners + 1);
1998
+ // Register global listeners when first element is monitored.
1999
+ if (++this._monitoredElementCount === 1) {
2000
+ // Note: we listen to events in the capture phase so we
2001
+ // can detect them even if the user stops propagation.
2002
+ this._ngZone.runOutsideAngular(() => {
1991
2003
  const document = this._getDocument();
1992
2004
  const window = this._getWindow();
1993
- document.removeEventListener('keydown', this._documentKeydownListener, captureEventListenerOptions);
1994
- document.removeEventListener('mousedown', this._documentMousedownListener, captureEventListenerOptions);
1995
- document.removeEventListener('touchstart', this._documentTouchstartListener, captureEventListenerOptions);
1996
- window.removeEventListener('focus', this._windowFocusListener);
1997
- // Clear timeouts for all potentially pending timeouts to prevent the leaks.
1998
- clearTimeout(this._windowFocusTimeoutId);
1999
- clearTimeout(this._touchTimeoutId);
2000
- clearTimeout(this._originTimeoutId);
2005
+ document.addEventListener('keydown', this._documentKeydownListener, captureEventListenerOptions);
2006
+ document.addEventListener('mousedown', this._documentMousedownListener, captureEventListenerOptions);
2007
+ document.addEventListener('touchstart', this._documentTouchstartListener, captureEventListenerOptions);
2008
+ window.addEventListener('focus', this._windowFocusListener);
2009
+ });
2010
+ }
2011
+ }
2012
+ _removeGlobalListeners(elementInfo) {
2013
+ const rootNode = elementInfo.rootNode;
2014
+ if (this._rootNodeFocusListenerCount.has(rootNode)) {
2015
+ const rootNodeFocusListeners = this._rootNodeFocusListenerCount.get(rootNode);
2016
+ if (rootNodeFocusListeners > 1) {
2017
+ this._rootNodeFocusListenerCount.set(rootNode, rootNodeFocusListeners - 1);
2001
2018
  }
2019
+ else {
2020
+ rootNode.removeEventListener('focus', this._rootNodeFocusAndBlurListener, captureEventListenerOptions);
2021
+ rootNode.removeEventListener('blur', this._rootNodeFocusAndBlurListener, captureEventListenerOptions);
2022
+ this._rootNodeFocusListenerCount.delete(rootNode);
2023
+ }
2024
+ }
2025
+ // Unregister global listeners when last element is unmonitored.
2026
+ if (!--this._monitoredElementCount) {
2027
+ const document = this._getDocument();
2028
+ const window = this._getWindow();
2029
+ document.removeEventListener('keydown', this._documentKeydownListener, captureEventListenerOptions);
2030
+ document.removeEventListener('mousedown', this._documentMousedownListener, captureEventListenerOptions);
2031
+ document.removeEventListener('touchstart', this._documentTouchstartListener, captureEventListenerOptions);
2032
+ window.removeEventListener('focus', this._windowFocusListener);
2033
+ // Clear timeouts for all potentially pending timeouts to prevent the leaks.
2034
+ clearTimeout(this._windowFocusTimeoutId);
2035
+ clearTimeout(this._touchTimeoutId);
2036
+ clearTimeout(this._originTimeoutId);
2002
2037
  }
2003
2038
  }
2004
- FocusMonitor.ɵprov = ɵɵdefineInjectable({ factory: function FocusMonitor_Factory() { return new FocusMonitor(ɵɵinject(NgZone), ɵɵinject(Platform), ɵɵinject(DOCUMENT, 8), ɵɵinject(FOCUS_MONITOR_DEFAULT_OPTIONS, 8)); }, token: FocusMonitor, providedIn: "root" });
2005
- FocusMonitor.decorators = [
2006
- { type: Injectable, args: [{ providedIn: 'root' },] }
2007
- ];
2008
- FocusMonitor.ctorParameters = () => [
2009
- { type: NgZone },
2010
- { type: Platform },
2011
- { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DOCUMENT,] }] },
2012
- { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [FOCUS_MONITOR_DEFAULT_OPTIONS,] }] }
2013
- ];
2014
- return FocusMonitor;
2015
- })();
2039
+ }
2040
+ FocusMonitor.ɵprov = ɵɵdefineInjectable({ factory: function FocusMonitor_Factory() { return new FocusMonitor(ɵɵinject(NgZone), ɵɵinject(Platform), ɵɵinject(DOCUMENT, 8), ɵɵinject(FOCUS_MONITOR_DEFAULT_OPTIONS, 8)); }, token: FocusMonitor, providedIn: "root" });
2041
+ FocusMonitor.decorators = [
2042
+ { type: Injectable, args: [{ providedIn: 'root' },] }
2043
+ ];
2044
+ FocusMonitor.ctorParameters = () => [
2045
+ { type: NgZone },
2046
+ { type: Platform },
2047
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DOCUMENT,] }] },
2048
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [FOCUS_MONITOR_DEFAULT_OPTIONS,] }] }
2049
+ ];
2016
2050
  /** Gets the target of an event, accounting for Shadow DOM. */
2017
2051
  function getTarget(event) {
2018
2052
  // If an event is bound outside the Shadow DOM, the `event.target` will
@@ -2028,38 +2062,35 @@ function getTarget(event) {
2028
2062
  * focused.
2029
2063
  * 2) cdkMonitorSubtreeFocus: considers an element focused if it or any of its children are focused.
2030
2064
  */
2031
- let CdkMonitorFocus = /** @class */ (() => {
2032
- class CdkMonitorFocus {
2033
- constructor(_elementRef, _focusMonitor) {
2034
- this._elementRef = _elementRef;
2035
- this._focusMonitor = _focusMonitor;
2036
- this.cdkFocusChange = new EventEmitter();
2037
- }
2038
- ngAfterViewInit() {
2039
- this._monitorSubscription = this._focusMonitor.monitor(this._elementRef, this._elementRef.nativeElement.hasAttribute('cdkMonitorSubtreeFocus'))
2040
- .subscribe(origin => this.cdkFocusChange.emit(origin));
2041
- }
2042
- ngOnDestroy() {
2043
- this._focusMonitor.stopMonitoring(this._elementRef);
2044
- if (this._monitorSubscription) {
2045
- this._monitorSubscription.unsubscribe();
2046
- }
2065
+ class CdkMonitorFocus {
2066
+ constructor(_elementRef, _focusMonitor) {
2067
+ this._elementRef = _elementRef;
2068
+ this._focusMonitor = _focusMonitor;
2069
+ this.cdkFocusChange = new EventEmitter();
2070
+ }
2071
+ ngAfterViewInit() {
2072
+ this._monitorSubscription = this._focusMonitor.monitor(this._elementRef, this._elementRef.nativeElement.hasAttribute('cdkMonitorSubtreeFocus'))
2073
+ .subscribe(origin => this.cdkFocusChange.emit(origin));
2074
+ }
2075
+ ngOnDestroy() {
2076
+ this._focusMonitor.stopMonitoring(this._elementRef);
2077
+ if (this._monitorSubscription) {
2078
+ this._monitorSubscription.unsubscribe();
2047
2079
  }
2048
2080
  }
2049
- CdkMonitorFocus.decorators = [
2050
- { type: Directive, args: [{
2051
- selector: '[cdkMonitorElementFocus], [cdkMonitorSubtreeFocus]',
2052
- },] }
2053
- ];
2054
- CdkMonitorFocus.ctorParameters = () => [
2055
- { type: ElementRef },
2056
- { type: FocusMonitor }
2057
- ];
2058
- CdkMonitorFocus.propDecorators = {
2059
- cdkFocusChange: [{ type: Output }]
2060
- };
2061
- return CdkMonitorFocus;
2062
- })();
2081
+ }
2082
+ CdkMonitorFocus.decorators = [
2083
+ { type: Directive, args: [{
2084
+ selector: '[cdkMonitorElementFocus], [cdkMonitorSubtreeFocus]',
2085
+ },] }
2086
+ ];
2087
+ CdkMonitorFocus.ctorParameters = () => [
2088
+ { type: ElementRef },
2089
+ { type: FocusMonitor }
2090
+ ];
2091
+ CdkMonitorFocus.propDecorators = {
2092
+ cdkFocusChange: [{ type: Output }]
2093
+ };
2063
2094
 
2064
2095
  /**
2065
2096
  * @license
@@ -2085,69 +2116,66 @@ const HIGH_CONTRAST_MODE_ACTIVE_CSS_CLASS = 'cdk-high-contrast-active';
2085
2116
  * Mode. This service does not detect high-contrast mode as added by the Chrome "High Contrast"
2086
2117
  * browser extension.
2087
2118
  */
2088
- let HighContrastModeDetector = /** @class */ (() => {
2089
- class HighContrastModeDetector {
2090
- constructor(_platform, document) {
2091
- this._platform = _platform;
2092
- this._document = document;
2093
- }
2094
- /** Gets the current high-contrast-mode for the page. */
2095
- getHighContrastMode() {
2096
- if (!this._platform.isBrowser) {
2097
- return 0 /* NONE */;
2098
- }
2099
- // Create a test element with an arbitrary background-color that is neither black nor
2100
- // white; high-contrast mode will coerce the color to either black or white. Also ensure that
2101
- // appending the test element to the DOM does not affect layout by absolutely positioning it
2102
- const testElement = this._document.createElement('div');
2103
- testElement.style.backgroundColor = 'rgb(1,2,3)';
2104
- testElement.style.position = 'absolute';
2105
- this._document.body.appendChild(testElement);
2106
- // Get the computed style for the background color, collapsing spaces to normalize between
2107
- // browsers. Once we get this color, we no longer need the test element. Access the `window`
2108
- // via the document so we can fake it in tests. Note that we have extra null checks, because
2109
- // this logic will likely run during app bootstrap and throwing can break the entire app.
2110
- const documentWindow = this._document.defaultView || window;
2111
- const computedStyle = (documentWindow && documentWindow.getComputedStyle) ?
2112
- documentWindow.getComputedStyle(testElement) : null;
2113
- const computedColor = (computedStyle && computedStyle.backgroundColor || '').replace(/ /g, '');
2114
- this._document.body.removeChild(testElement);
2115
- switch (computedColor) {
2116
- case 'rgb(0,0,0)': return 2 /* WHITE_ON_BLACK */;
2117
- case 'rgb(255,255,255)': return 1 /* BLACK_ON_WHITE */;
2118
- }
2119
+ class HighContrastModeDetector {
2120
+ constructor(_platform, document) {
2121
+ this._platform = _platform;
2122
+ this._document = document;
2123
+ }
2124
+ /** Gets the current high-contrast-mode for the page. */
2125
+ getHighContrastMode() {
2126
+ if (!this._platform.isBrowser) {
2119
2127
  return 0 /* NONE */;
2120
2128
  }
2121
- /** Applies CSS classes indicating high-contrast mode to document body (browser-only). */
2122
- _applyBodyHighContrastModeCssClasses() {
2123
- if (this._platform.isBrowser && this._document.body) {
2124
- const bodyClasses = this._document.body.classList;
2125
- // IE11 doesn't support `classList` operations with multiple arguments
2126
- bodyClasses.remove(HIGH_CONTRAST_MODE_ACTIVE_CSS_CLASS);
2127
- bodyClasses.remove(BLACK_ON_WHITE_CSS_CLASS);
2128
- bodyClasses.remove(WHITE_ON_BLACK_CSS_CLASS);
2129
- const mode = this.getHighContrastMode();
2130
- if (mode === 1 /* BLACK_ON_WHITE */) {
2131
- bodyClasses.add(HIGH_CONTRAST_MODE_ACTIVE_CSS_CLASS);
2132
- bodyClasses.add(BLACK_ON_WHITE_CSS_CLASS);
2133
- }
2134
- else if (mode === 2 /* WHITE_ON_BLACK */) {
2135
- bodyClasses.add(HIGH_CONTRAST_MODE_ACTIVE_CSS_CLASS);
2136
- bodyClasses.add(WHITE_ON_BLACK_CSS_CLASS);
2137
- }
2129
+ // Create a test element with an arbitrary background-color that is neither black nor
2130
+ // white; high-contrast mode will coerce the color to either black or white. Also ensure that
2131
+ // appending the test element to the DOM does not affect layout by absolutely positioning it
2132
+ const testElement = this._document.createElement('div');
2133
+ testElement.style.backgroundColor = 'rgb(1,2,3)';
2134
+ testElement.style.position = 'absolute';
2135
+ this._document.body.appendChild(testElement);
2136
+ // Get the computed style for the background color, collapsing spaces to normalize between
2137
+ // browsers. Once we get this color, we no longer need the test element. Access the `window`
2138
+ // via the document so we can fake it in tests. Note that we have extra null checks, because
2139
+ // this logic will likely run during app bootstrap and throwing can break the entire app.
2140
+ const documentWindow = this._document.defaultView || window;
2141
+ const computedStyle = (documentWindow && documentWindow.getComputedStyle) ?
2142
+ documentWindow.getComputedStyle(testElement) : null;
2143
+ const computedColor = (computedStyle && computedStyle.backgroundColor || '').replace(/ /g, '');
2144
+ this._document.body.removeChild(testElement);
2145
+ switch (computedColor) {
2146
+ case 'rgb(0,0,0)': return 2 /* WHITE_ON_BLACK */;
2147
+ case 'rgb(255,255,255)': return 1 /* BLACK_ON_WHITE */;
2148
+ }
2149
+ return 0 /* NONE */;
2150
+ }
2151
+ /** Applies CSS classes indicating high-contrast mode to document body (browser-only). */
2152
+ _applyBodyHighContrastModeCssClasses() {
2153
+ if (this._platform.isBrowser && this._document.body) {
2154
+ const bodyClasses = this._document.body.classList;
2155
+ // IE11 doesn't support `classList` operations with multiple arguments
2156
+ bodyClasses.remove(HIGH_CONTRAST_MODE_ACTIVE_CSS_CLASS);
2157
+ bodyClasses.remove(BLACK_ON_WHITE_CSS_CLASS);
2158
+ bodyClasses.remove(WHITE_ON_BLACK_CSS_CLASS);
2159
+ const mode = this.getHighContrastMode();
2160
+ if (mode === 1 /* BLACK_ON_WHITE */) {
2161
+ bodyClasses.add(HIGH_CONTRAST_MODE_ACTIVE_CSS_CLASS);
2162
+ bodyClasses.add(BLACK_ON_WHITE_CSS_CLASS);
2163
+ }
2164
+ else if (mode === 2 /* WHITE_ON_BLACK */) {
2165
+ bodyClasses.add(HIGH_CONTRAST_MODE_ACTIVE_CSS_CLASS);
2166
+ bodyClasses.add(WHITE_ON_BLACK_CSS_CLASS);
2138
2167
  }
2139
2168
  }
2140
2169
  }
2141
- HighContrastModeDetector.ɵprov = ɵɵdefineInjectable({ factory: function HighContrastModeDetector_Factory() { return new HighContrastModeDetector(ɵɵinject(Platform), ɵɵinject(DOCUMENT)); }, token: HighContrastModeDetector, providedIn: "root" });
2142
- HighContrastModeDetector.decorators = [
2143
- { type: Injectable, args: [{ providedIn: 'root' },] }
2144
- ];
2145
- HighContrastModeDetector.ctorParameters = () => [
2146
- { type: Platform },
2147
- { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
2148
- ];
2149
- return HighContrastModeDetector;
2150
- })();
2170
+ }
2171
+ HighContrastModeDetector.ɵprov = ɵɵdefineInjectable({ factory: function HighContrastModeDetector_Factory() { return new HighContrastModeDetector(ɵɵinject(Platform), ɵɵinject(DOCUMENT)); }, token: HighContrastModeDetector, providedIn: "root" });
2172
+ HighContrastModeDetector.decorators = [
2173
+ { type: Injectable, args: [{ providedIn: 'root' },] }
2174
+ ];
2175
+ HighContrastModeDetector.ctorParameters = () => [
2176
+ { type: Platform },
2177
+ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
2178
+ ];
2151
2179
 
2152
2180
  /**
2153
2181
  * @license
@@ -2156,24 +2184,21 @@ let HighContrastModeDetector = /** @class */ (() => {
2156
2184
  * Use of this source code is governed by an MIT-style license that can be
2157
2185
  * found in the LICENSE file at https://angular.io/license
2158
2186
  */
2159
- let A11yModule = /** @class */ (() => {
2160
- class A11yModule {
2161
- constructor(highContrastModeDetector) {
2162
- highContrastModeDetector._applyBodyHighContrastModeCssClasses();
2163
- }
2164
- }
2165
- A11yModule.decorators = [
2166
- { type: NgModule, args: [{
2167
- imports: [PlatformModule, ObserversModule],
2168
- declarations: [CdkAriaLive, CdkTrapFocus, CdkMonitorFocus],
2169
- exports: [CdkAriaLive, CdkTrapFocus, CdkMonitorFocus],
2170
- },] }
2171
- ];
2172
- A11yModule.ctorParameters = () => [
2173
- { type: HighContrastModeDetector }
2174
- ];
2175
- return A11yModule;
2176
- })();
2187
+ class A11yModule {
2188
+ constructor(highContrastModeDetector) {
2189
+ highContrastModeDetector._applyBodyHighContrastModeCssClasses();
2190
+ }
2191
+ }
2192
+ A11yModule.decorators = [
2193
+ { type: NgModule, args: [{
2194
+ imports: [PlatformModule, ObserversModule],
2195
+ declarations: [CdkAriaLive, CdkTrapFocus, CdkMonitorFocus],
2196
+ exports: [CdkAriaLive, CdkTrapFocus, CdkMonitorFocus],
2197
+ },] }
2198
+ ];
2199
+ A11yModule.ctorParameters = () => [
2200
+ { type: HighContrastModeDetector }
2201
+ ];
2177
2202
 
2178
2203
  /**
2179
2204
  * @license
@@ -2187,5 +2212,5 @@ let A11yModule = /** @class */ (() => {
2187
2212
  * Generated bundle index. Do not edit.
2188
2213
  */
2189
2214
 
2190
- export { A11yModule, ActiveDescendantKeyManager, AriaDescriber, CDK_DESCRIBEDBY_HOST_ATTRIBUTE, CDK_DESCRIBEDBY_ID_PREFIX, CdkAriaLive, CdkMonitorFocus, CdkTrapFocus, ConfigurableFocusTrap, ConfigurableFocusTrapFactory, EventListenerFocusTrapInertStrategy, FOCUS_MONITOR_DEFAULT_OPTIONS, FOCUS_TRAP_INERT_STRATEGY, FocusKeyManager, FocusMonitor, FocusTrap, FocusTrapFactory, HighContrastModeDetector, InteractivityChecker, LIVE_ANNOUNCER_DEFAULT_OPTIONS, LIVE_ANNOUNCER_ELEMENT_TOKEN, LIVE_ANNOUNCER_ELEMENT_TOKEN_FACTORY, ListKeyManager, LiveAnnouncer, MESSAGES_CONTAINER_ID, TOUCH_BUFFER_MS, isFakeMousedownFromScreenReader, FocusTrapManager as ɵangular_material_src_cdk_a11y_a11y_a, ConfigurableFocusTrapConfig as ɵangular_material_src_cdk_a11y_a11y_b };
2215
+ export { A11yModule, ActiveDescendantKeyManager, AriaDescriber, CDK_DESCRIBEDBY_HOST_ATTRIBUTE, CDK_DESCRIBEDBY_ID_PREFIX, CdkAriaLive, CdkMonitorFocus, CdkTrapFocus, ConfigurableFocusTrap, ConfigurableFocusTrapFactory, EventListenerFocusTrapInertStrategy, FOCUS_MONITOR_DEFAULT_OPTIONS, FOCUS_TRAP_INERT_STRATEGY, FocusKeyManager, FocusMonitor, FocusTrap, FocusTrapFactory, HighContrastModeDetector, InteractivityChecker, IsFocusableConfig, LIVE_ANNOUNCER_DEFAULT_OPTIONS, LIVE_ANNOUNCER_ELEMENT_TOKEN, LIVE_ANNOUNCER_ELEMENT_TOKEN_FACTORY, ListKeyManager, LiveAnnouncer, MESSAGES_CONTAINER_ID, TOUCH_BUFFER_MS, isFakeMousedownFromScreenReader, FocusTrapManager as ɵangular_material_src_cdk_a11y_a11y_a, ConfigurableFocusTrapConfig as ɵangular_material_src_cdk_a11y_a11y_b };
2191
2216
  //# sourceMappingURL=a11y.js.map