@angular/cdk 7.0.3 → 7.2.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 (252) hide show
  1. package/a11y/typings/focus-monitor/focus-monitor.d.ts +20 -4
  2. package/a11y/typings/index.metadata.json +1 -1
  3. package/a11y/typings/key-manager/list-key-manager.d.ts +8 -0
  4. package/a11y/typings/live-announcer/live-announcer.d.ts +37 -4
  5. package/bidi/typings/dir.d.ts +4 -1
  6. package/bidi/typings/index.metadata.json +1 -1
  7. package/bundles/cdk-a11y.umd.js +503 -210
  8. package/bundles/cdk-a11y.umd.js.map +1 -1
  9. package/bundles/cdk-a11y.umd.min.js +1 -1
  10. package/bundles/cdk-a11y.umd.min.js.map +1 -1
  11. package/bundles/cdk-accordion.umd.js +16 -9
  12. package/bundles/cdk-accordion.umd.js.map +1 -1
  13. package/bundles/cdk-accordion.umd.min.js.map +1 -1
  14. package/bundles/cdk-bidi.umd.js +16 -7
  15. package/bundles/cdk-bidi.umd.js.map +1 -1
  16. package/bundles/cdk-bidi.umd.min.js +1 -1
  17. package/bundles/cdk-bidi.umd.min.js.map +1 -1
  18. package/bundles/cdk-coercion.umd.js +5 -5
  19. package/bundles/cdk-coercion.umd.js.map +1 -1
  20. package/bundles/cdk-collections.umd.js +28 -5
  21. package/bundles/cdk-collections.umd.js.map +1 -1
  22. package/bundles/cdk-collections.umd.min.js.map +1 -1
  23. package/bundles/cdk-drag-drop.umd.js +2251 -853
  24. package/bundles/cdk-drag-drop.umd.js.map +1 -1
  25. package/bundles/cdk-drag-drop.umd.min.js +2 -1
  26. package/bundles/cdk-drag-drop.umd.min.js.map +1 -1
  27. package/bundles/cdk-keycodes.umd.js +33 -1
  28. package/bundles/cdk-keycodes.umd.js.map +1 -1
  29. package/bundles/cdk-keycodes.umd.min.js +1 -1
  30. package/bundles/cdk-keycodes.umd.min.js.map +1 -1
  31. package/bundles/cdk-layout.umd.js +29 -22
  32. package/bundles/cdk-layout.umd.js.map +1 -1
  33. package/bundles/cdk-layout.umd.min.js +1 -1
  34. package/bundles/cdk-layout.umd.min.js.map +1 -1
  35. package/bundles/cdk-observers.umd.js +25 -6
  36. package/bundles/cdk-observers.umd.js.map +1 -1
  37. package/bundles/cdk-observers.umd.min.js.map +1 -1
  38. package/bundles/cdk-overlay.umd.js +600 -243
  39. package/bundles/cdk-overlay.umd.js.map +1 -1
  40. package/bundles/cdk-overlay.umd.min.js +2 -2
  41. package/bundles/cdk-overlay.umd.min.js.map +1 -1
  42. package/bundles/cdk-platform.umd.js +50 -28
  43. package/bundles/cdk-platform.umd.js.map +1 -1
  44. package/bundles/cdk-platform.umd.min.js.map +1 -1
  45. package/bundles/cdk-portal.umd.js +14 -7
  46. package/bundles/cdk-portal.umd.js.map +1 -1
  47. package/bundles/cdk-portal.umd.min.js.map +1 -1
  48. package/bundles/cdk-scrolling.umd.js +143 -48
  49. package/bundles/cdk-scrolling.umd.js.map +1 -1
  50. package/bundles/cdk-scrolling.umd.min.js +1 -1
  51. package/bundles/cdk-scrolling.umd.min.js.map +1 -1
  52. package/bundles/cdk-stepper.umd.js +103 -19
  53. package/bundles/cdk-stepper.umd.js.map +1 -1
  54. package/bundles/cdk-stepper.umd.min.js +1 -1
  55. package/bundles/cdk-stepper.umd.min.js.map +1 -1
  56. package/bundles/cdk-table.umd.js +182 -48
  57. package/bundles/cdk-table.umd.js.map +1 -1
  58. package/bundles/cdk-table.umd.min.js.map +1 -1
  59. package/bundles/cdk-text-field.umd.js +70 -32
  60. package/bundles/cdk-text-field.umd.js.map +1 -1
  61. package/bundles/cdk-text-field.umd.min.js +1 -1
  62. package/bundles/cdk-text-field.umd.min.js.map +1 -1
  63. package/bundles/cdk-tree.umd.js +71 -34
  64. package/bundles/cdk-tree.umd.js.map +1 -1
  65. package/bundles/cdk-tree.umd.min.js +1 -1
  66. package/bundles/cdk-tree.umd.min.js.map +1 -1
  67. package/bundles/cdk.umd.js +5 -4
  68. package/bundles/cdk.umd.js.map +1 -1
  69. package/bundles/cdk.umd.min.js +1 -1
  70. package/bundles/cdk.umd.min.js.map +1 -1
  71. package/drag-drop/typings/{drag-handle.d.ts → directives/drag-handle.d.ts} +3 -0
  72. package/drag-drop/typings/{drag-placeholder.d.ts → directives/drag-placeholder.d.ts} +0 -0
  73. package/drag-drop/typings/{drag-preview.d.ts → directives/drag-preview.d.ts} +0 -0
  74. package/drag-drop/typings/directives/drag.d.ts +108 -0
  75. package/drag-drop/typings/directives/drop-list-group.d.ts +22 -0
  76. package/drag-drop/typings/directives/drop-list.d.ts +135 -0
  77. package/drag-drop/typings/drag-drop-registry.d.ts +8 -5
  78. package/drag-drop/typings/drag-events.d.ts +24 -6
  79. package/{typings/esm5/drag-drop/drag.d.ts → drag-drop/typings/drag-ref.d.ts} +153 -77
  80. package/drag-drop/typings/drop-list-container.d.ts +21 -3
  81. package/drag-drop/typings/{drop-list.d.ts → drop-list-ref.d.ts} +133 -77
  82. package/drag-drop/typings/index.d.ts +1 -0
  83. package/drag-drop/typings/index.metadata.json +1 -1
  84. package/drag-drop/typings/public-api.d.ts +13 -5
  85. package/esm2015/a11y.js +353 -189
  86. package/esm2015/a11y.js.map +1 -1
  87. package/esm2015/accordion.js +16 -11
  88. package/esm2015/accordion.js.map +1 -1
  89. package/esm2015/bidi.js +18 -9
  90. package/esm2015/bidi.js.map +1 -1
  91. package/esm2015/cdk.js +7 -6
  92. package/esm2015/cdk.js.map +1 -1
  93. package/esm2015/coercion.js +7 -7
  94. package/esm2015/coercion.js.map +1 -1
  95. package/esm2015/collections.js +22 -7
  96. package/esm2015/collections.js.map +1 -1
  97. package/esm2015/drag-drop.js +1768 -751
  98. package/esm2015/drag-drop.js.map +1 -1
  99. package/esm2015/keycodes.js +31 -4
  100. package/esm2015/keycodes.js.map +1 -1
  101. package/esm2015/layout.js +29 -19
  102. package/esm2015/layout.js.map +1 -1
  103. package/esm2015/observers.js +13 -8
  104. package/esm2015/observers.js.map +1 -1
  105. package/esm2015/overlay.js +384 -219
  106. package/esm2015/overlay.js.map +1 -1
  107. package/esm2015/platform.js +53 -31
  108. package/esm2015/platform.js.map +1 -1
  109. package/esm2015/portal.js +13 -9
  110. package/esm2015/portal.js.map +1 -1
  111. package/esm2015/scrolling.js +106 -49
  112. package/esm2015/scrolling.js.map +1 -1
  113. package/esm2015/stepper.js +93 -24
  114. package/esm2015/stepper.js.map +1 -1
  115. package/esm2015/table.js +89 -45
  116. package/esm2015/table.js.map +1 -1
  117. package/esm2015/text-field.js +51 -34
  118. package/esm2015/text-field.js.map +1 -1
  119. package/esm2015/tree.js +55 -36
  120. package/esm2015/tree.js.map +1 -1
  121. package/esm5/a11y.es5.js +507 -214
  122. package/esm5/a11y.es5.js.map +1 -1
  123. package/esm5/accordion.es5.js +18 -11
  124. package/esm5/accordion.es5.js.map +1 -1
  125. package/esm5/bidi.es5.js +18 -9
  126. package/esm5/bidi.es5.js.map +1 -1
  127. package/esm5/cdk.es5.js +7 -6
  128. package/esm5/cdk.es5.js.map +1 -1
  129. package/esm5/coercion.es5.js +7 -7
  130. package/esm5/coercion.es5.js.map +1 -1
  131. package/esm5/collections.es5.js +35 -7
  132. package/esm5/collections.es5.js.map +1 -1
  133. package/esm5/drag-drop.es5.js +2125 -729
  134. package/esm5/drag-drop.es5.js.map +1 -1
  135. package/esm5/keycodes.es5.js +35 -4
  136. package/esm5/keycodes.es5.js.map +1 -1
  137. package/esm5/layout.es5.js +31 -24
  138. package/esm5/layout.es5.js.map +1 -1
  139. package/esm5/observers.es5.js +27 -8
  140. package/esm5/observers.es5.js.map +1 -1
  141. package/esm5/overlay.es5.js +602 -245
  142. package/esm5/overlay.es5.js.map +1 -1
  143. package/esm5/platform.es5.js +52 -30
  144. package/esm5/platform.es5.js.map +1 -1
  145. package/esm5/portal.es5.js +16 -9
  146. package/esm5/portal.es5.js.map +1 -1
  147. package/esm5/scrolling.es5.js +145 -50
  148. package/esm5/scrolling.es5.js.map +1 -1
  149. package/esm5/stepper.es5.js +106 -24
  150. package/esm5/stepper.es5.js.map +1 -1
  151. package/esm5/table.es5.js +184 -50
  152. package/esm5/table.es5.js.map +1 -1
  153. package/esm5/text-field.es5.js +72 -34
  154. package/esm5/text-field.es5.js.map +1 -1
  155. package/esm5/tree.es5.js +74 -37
  156. package/esm5/tree.es5.js.map +1 -1
  157. package/keycodes/typings/index.metadata.json +1 -1
  158. package/keycodes/typings/modifiers.d.ts +14 -0
  159. package/keycodes/typings/public-api.d.ts +1 -0
  160. package/overlay/typings/index.metadata.json +1 -1
  161. package/package.json +4 -4
  162. package/schematics/ng-generate/drag-drop/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.component.ts +2 -2
  163. package/schematics/ng-update/upgrade-data.js +2 -1
  164. package/schematics/ng-update/upgrade-data.js.map +1 -1
  165. package/schematics/ng-update/upgrade-rules/index.js +3 -2
  166. package/schematics/ng-update/upgrade-rules/index.js.map +1 -1
  167. package/schematics/utils/ast/ng-module-imports.d.ts +1 -1
  168. package/schematics/utils/ast/ng-module-imports.js +25 -13
  169. package/schematics/utils/ast/ng-module-imports.js.map +1 -1
  170. package/schematics/utils/get-project.js +2 -1
  171. package/schematics/utils/get-project.js.map +1 -1
  172. package/schematics/utils/parse5-element.js +3 -2
  173. package/schematics/utils/parse5-element.js.map +1 -1
  174. package/schematics/utils/project-targets.js +2 -1
  175. package/schematics/utils/project-targets.js.map +1 -1
  176. package/schematics/utils/version-agnostic-typescript.js +3 -2
  177. package/schematics/utils/version-agnostic-typescript.js.map +1 -1
  178. package/scrolling/typings/index.metadata.json +1 -1
  179. package/stepper/typings/index.metadata.json +1 -1
  180. package/stepper/typings/public-api.d.ts +1 -0
  181. package/stepper/typings/step-header.d.ts +15 -0
  182. package/stepper/typings/stepper.d.ts +11 -1
  183. package/text-field/typings/autosize.d.ts +6 -0
  184. package/text-field/typings/index.metadata.json +1 -1
  185. package/tree/typings/nested-node.d.ts +5 -5
  186. package/typings/a11y/focus-monitor/focus-monitor.d.ts +20 -4
  187. package/typings/a11y/index.metadata.json +1 -1
  188. package/typings/a11y/key-manager/list-key-manager.d.ts +8 -0
  189. package/typings/a11y/live-announcer/live-announcer.d.ts +37 -4
  190. package/typings/bidi/dir.d.ts +4 -1
  191. package/typings/bidi/index.metadata.json +1 -1
  192. package/typings/{esm5/drag-drop → drag-drop/directives}/drag-handle.d.ts +3 -0
  193. package/typings/drag-drop/{drag-placeholder.d.ts → directives/drag-placeholder.d.ts} +0 -0
  194. package/typings/drag-drop/{drag-preview.d.ts → directives/drag-preview.d.ts} +0 -0
  195. package/typings/drag-drop/directives/drag.d.ts +108 -0
  196. package/typings/drag-drop/directives/drop-list-group.d.ts +22 -0
  197. package/typings/drag-drop/directives/drop-list.d.ts +135 -0
  198. package/typings/drag-drop/drag-drop-registry.d.ts +8 -5
  199. package/typings/drag-drop/drag-events.d.ts +24 -6
  200. package/typings/drag-drop/{drag.d.ts → drag-ref.d.ts} +153 -77
  201. package/typings/drag-drop/drop-list-container.d.ts +21 -3
  202. package/typings/{esm5/drag-drop/drop-list.d.ts → drag-drop/drop-list-ref.d.ts} +133 -77
  203. package/typings/drag-drop/index.d.ts +1 -0
  204. package/typings/drag-drop/index.metadata.json +1 -1
  205. package/typings/drag-drop/public-api.d.ts +13 -5
  206. package/typings/esm5/a11y/focus-monitor/focus-monitor.d.ts +20 -4
  207. package/typings/esm5/a11y/index.metadata.json +1 -1
  208. package/typings/esm5/a11y/key-manager/list-key-manager.d.ts +8 -0
  209. package/typings/esm5/a11y/live-announcer/live-announcer.d.ts +37 -4
  210. package/typings/esm5/bidi/dir.d.ts +4 -1
  211. package/typings/esm5/bidi/index.metadata.json +1 -1
  212. package/typings/{drag-drop → esm5/drag-drop/directives}/drag-handle.d.ts +3 -0
  213. package/typings/esm5/drag-drop/{drag-placeholder.d.ts → directives/drag-placeholder.d.ts} +0 -0
  214. package/typings/esm5/drag-drop/{drag-preview.d.ts → directives/drag-preview.d.ts} +0 -0
  215. package/typings/esm5/drag-drop/directives/drag.d.ts +108 -0
  216. package/typings/esm5/drag-drop/directives/drop-list-group.d.ts +22 -0
  217. package/typings/esm5/drag-drop/directives/drop-list.d.ts +135 -0
  218. package/typings/esm5/drag-drop/drag-drop-registry.d.ts +8 -5
  219. package/typings/esm5/drag-drop/drag-events.d.ts +24 -6
  220. package/{drag-drop/typings/drag.d.ts → typings/esm5/drag-drop/drag-ref.d.ts} +153 -77
  221. package/typings/esm5/drag-drop/drop-list-container.d.ts +21 -3
  222. package/typings/{drag-drop/drop-list.d.ts → esm5/drag-drop/drop-list-ref.d.ts} +133 -77
  223. package/typings/esm5/drag-drop/index.d.ts +1 -0
  224. package/typings/esm5/drag-drop/index.metadata.json +1 -1
  225. package/typings/esm5/drag-drop/public-api.d.ts +13 -5
  226. package/typings/esm5/index.metadata.json +1 -1
  227. package/typings/esm5/keycodes/index.metadata.json +1 -1
  228. package/typings/esm5/keycodes/modifiers.d.ts +14 -0
  229. package/typings/esm5/keycodes/public-api.d.ts +1 -0
  230. package/typings/esm5/overlay/index.metadata.json +1 -1
  231. package/typings/esm5/scrolling/index.metadata.json +1 -1
  232. package/typings/esm5/stepper/index.metadata.json +1 -1
  233. package/typings/esm5/stepper/public-api.d.ts +1 -0
  234. package/typings/esm5/stepper/step-header.d.ts +15 -0
  235. package/typings/esm5/stepper/stepper.d.ts +11 -1
  236. package/typings/esm5/text-field/autosize.d.ts +6 -0
  237. package/typings/esm5/text-field/index.metadata.json +1 -1
  238. package/typings/esm5/tree/nested-node.d.ts +5 -5
  239. package/typings/index.metadata.json +1 -1
  240. package/typings/keycodes/index.metadata.json +1 -1
  241. package/typings/keycodes/modifiers.d.ts +14 -0
  242. package/typings/keycodes/public-api.d.ts +1 -0
  243. package/typings/overlay/index.metadata.json +1 -1
  244. package/typings/schematics/utils/ast/ng-module-imports.d.ts +1 -1
  245. package/typings/scrolling/index.metadata.json +1 -1
  246. package/typings/stepper/index.metadata.json +1 -1
  247. package/typings/stepper/public-api.d.ts +1 -0
  248. package/typings/stepper/step-header.d.ts +15 -0
  249. package/typings/stepper/stepper.d.ts +11 -1
  250. package/typings/text-field/autosize.d.ts +6 -0
  251. package/typings/text-field/index.metadata.json +1 -1
  252. package/typings/tree/nested-node.d.ts +5 -5
package/esm2015/a11y.js CHANGED
@@ -6,9 +6,9 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  import { DOCUMENT, CommonModule } from '@angular/common';
9
- import { Inject, Injectable, Optional, SkipSelf, QueryList, Directive, ElementRef, Input, NgZone, InjectionToken, EventEmitter, Output, NgModule, defineInjectable, inject } from '@angular/core';
9
+ import { Inject, Injectable, Optional, SkipSelf, QueryList, Directive, ElementRef, Input, NgZone, isDevMode, InjectionToken, EventEmitter, Output, NgModule, defineInjectable, inject } from '@angular/core';
10
10
  import { Subject, Subscription, of } from 'rxjs';
11
- import { UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW, TAB, A, Z, ZERO, NINE } from '@angular/cdk/keycodes';
11
+ import { UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW, TAB, A, Z, ZERO, NINE, hasModifierKey } from '@angular/cdk/keycodes';
12
12
  import { debounceTime, filter, map, tap, take } from 'rxjs/operators';
13
13
  import { Platform, normalizePassiveListenerOptions, PlatformModule } from '@angular/cdk/platform';
14
14
  import { coerceBooleanProperty } from '@angular/cdk/coercion';
@@ -16,12 +16,13 @@ import { ContentObserver, ObserversModule } from '@angular/cdk/observers';
16
16
 
17
17
  /**
18
18
  * @fileoverview added by tsickle
19
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
19
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
20
20
  */
21
21
 
22
- /** *
22
+ /**
23
23
  * IDs are deliminated by an empty space, as per the spec.
24
- @type {?} */
24
+ * @type {?}
25
+ */
25
26
  const ID_DELIMINATOR = ' ';
26
27
  /**
27
28
  * Adds the given ID to the specified ARIA attribute on an element.
@@ -69,31 +70,37 @@ function getAriaReferenceIds(el, attr) {
69
70
 
70
71
  /**
71
72
  * @fileoverview added by tsickle
72
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
73
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
73
74
  */
74
- /** *
75
+ /**
75
76
  * ID used for the body container where all messages are appended.
76
- @type {?} */
77
+ * @type {?}
78
+ */
77
79
  const MESSAGES_CONTAINER_ID = 'cdk-describedby-message-container';
78
- /** *
80
+ /**
79
81
  * ID prefix used for each created message element.
80
- @type {?} */
82
+ * @type {?}
83
+ */
81
84
  const CDK_DESCRIBEDBY_ID_PREFIX = 'cdk-describedby-message';
82
- /** *
85
+ /**
83
86
  * Attribute given to each host element that is described by a message element.
84
- @type {?} */
87
+ * @type {?}
88
+ */
85
89
  const CDK_DESCRIBEDBY_HOST_ATTRIBUTE = 'cdk-describedby-host';
86
- /** *
90
+ /**
87
91
  * Global incremental identifier for each registered message element.
88
- @type {?} */
92
+ * @type {?}
93
+ */
89
94
  let nextId = 0;
90
- /** *
95
+ /**
91
96
  * Global map of all registered message elements that have been placed into the document.
92
- @type {?} */
97
+ * @type {?}
98
+ */
93
99
  const messageRegistry = new Map();
94
- /** *
100
+ /**
95
101
  * Container for all registered messages.
96
- @type {?} */
102
+ * @type {?}
103
+ */
97
104
  let messagesContainer = null;
98
105
  /**
99
106
  * Utility that creates visually hidden elements with a message content. Useful for elements that
@@ -168,6 +175,7 @@ class AriaDescriber {
168
175
  /**
169
176
  * Creates a new element in the visually hidden message container element with the message
170
177
  * as its content and adds it to the message registry.
178
+ * @private
171
179
  * @param {?} message
172
180
  * @return {?}
173
181
  */
@@ -175,13 +183,14 @@ class AriaDescriber {
175
183
  /** @type {?} */
176
184
  const messageElement = this._document.createElement('div');
177
185
  messageElement.setAttribute('id', `${CDK_DESCRIBEDBY_ID_PREFIX}-${nextId++}`);
178
- messageElement.appendChild(/** @type {?} */ ((this._document.createTextNode(message))));
179
- this._createMessagesContainer(); /** @type {?} */
180
- ((messagesContainer)).appendChild(messageElement);
186
+ messageElement.appendChild((/** @type {?} */ (this._document.createTextNode(message))));
187
+ this._createMessagesContainer();
188
+ (/** @type {?} */ (messagesContainer)).appendChild(messageElement);
181
189
  messageRegistry.set(message, { messageElement, referenceCount: 0 });
182
190
  }
183
191
  /**
184
192
  * Deletes the message element from the global messages container.
193
+ * @private
185
194
  * @param {?} message
186
195
  * @return {?}
187
196
  */
@@ -197,6 +206,7 @@ class AriaDescriber {
197
206
  }
198
207
  /**
199
208
  * Creates the global container for all aria-describedby messages.
209
+ * @private
200
210
  * @return {?}
201
211
  */
202
212
  _createMessagesContainer() {
@@ -208,7 +218,7 @@ class AriaDescriber {
208
218
  // old container so we don't get duplicates. Doing this, instead of emptying the previous
209
219
  // container, should be slightly faster.
210
220
  if (preExistingContainer) {
211
- /** @type {?} */ ((preExistingContainer.parentNode)).removeChild(preExistingContainer);
221
+ (/** @type {?} */ (preExistingContainer.parentNode)).removeChild(preExistingContainer);
212
222
  }
213
223
  messagesContainer = this._document.createElement('div');
214
224
  messagesContainer.id = MESSAGES_CONTAINER_ID;
@@ -219,6 +229,7 @@ class AriaDescriber {
219
229
  }
220
230
  /**
221
231
  * Deletes the global messages container.
232
+ * @private
222
233
  * @return {?}
223
234
  */
224
235
  _deleteMessagesContainer() {
@@ -229,10 +240,12 @@ class AriaDescriber {
229
240
  }
230
241
  /**
231
242
  * Removes all cdk-describedby messages that are hosted through the element.
243
+ * @private
232
244
  * @param {?} element
233
245
  * @return {?}
234
246
  */
235
247
  _removeCdkDescribedByReferenceIds(element) {
248
+ // Remove all aria-describedby reference IDs that are prefixed by CDK_DESCRIBEDBY_ID_PREFIX
236
249
  /** @type {?} */
237
250
  const originalReferenceIds = getAriaReferenceIds(element, 'aria-describedby')
238
251
  .filter(id => id.indexOf(CDK_DESCRIBEDBY_ID_PREFIX) != 0);
@@ -241,13 +254,14 @@ class AriaDescriber {
241
254
  /**
242
255
  * Adds a message reference to the element using aria-describedby and increments the registered
243
256
  * message's reference count.
257
+ * @private
244
258
  * @param {?} element
245
259
  * @param {?} message
246
260
  * @return {?}
247
261
  */
248
262
  _addMessageReference(element, message) {
249
263
  /** @type {?} */
250
- const registeredMessage = /** @type {?} */ ((messageRegistry.get(message)));
264
+ const registeredMessage = (/** @type {?} */ (messageRegistry.get(message)));
251
265
  // Add the aria-describedby reference and set the
252
266
  // describedby_host attribute to mark the element.
253
267
  addAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id);
@@ -257,19 +271,21 @@ class AriaDescriber {
257
271
  /**
258
272
  * Removes a message reference from the element using aria-describedby
259
273
  * and decrements the registered message's reference count.
274
+ * @private
260
275
  * @param {?} element
261
276
  * @param {?} message
262
277
  * @return {?}
263
278
  */
264
279
  _removeMessageReference(element, message) {
265
280
  /** @type {?} */
266
- const registeredMessage = /** @type {?} */ ((messageRegistry.get(message)));
281
+ const registeredMessage = (/** @type {?} */ (messageRegistry.get(message)));
267
282
  registeredMessage.referenceCount--;
268
283
  removeAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id);
269
284
  element.removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE);
270
285
  }
271
286
  /**
272
287
  * Returns true if the element has been described by the provided message ID.
288
+ * @private
273
289
  * @param {?} element
274
290
  * @param {?} message
275
291
  * @return {?}
@@ -285,6 +301,7 @@ class AriaDescriber {
285
301
  }
286
302
  /**
287
303
  * Determines whether a message can be described on a particular element.
304
+ * @private
288
305
  * @param {?} element
289
306
  * @param {?} message
290
307
  * @return {?}
@@ -311,24 +328,24 @@ AriaDescriber.ctorParameters = () => [
311
328
  function ARIA_DESCRIBER_PROVIDER_FACTORY(parentDispatcher, _document) {
312
329
  return parentDispatcher || new AriaDescriber(_document);
313
330
  }
314
- /** *
331
+ /**
315
332
  * \@docs-private \@deprecated \@breaking-change 8.0.0
316
- @type {?} */
333
+ * @type {?}
334
+ */
317
335
  const ARIA_DESCRIBER_PROVIDER = {
318
336
  // If there is already an AriaDescriber available, use that. Otherwise, provide a new one.
319
337
  provide: AriaDescriber,
320
338
  deps: [
321
339
  [new Optional(), new SkipSelf(), AriaDescriber],
322
- /** @type {?} */ (DOCUMENT)
340
+ (/** @type {?} */ (DOCUMENT))
323
341
  ],
324
342
  useFactory: ARIA_DESCRIBER_PROVIDER_FACTORY
325
343
  };
326
344
 
327
345
  /**
328
346
  * @fileoverview added by tsickle
329
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
347
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
330
348
  */
331
- // unsupported: template constraints.
332
349
  /**
333
350
  * This class manages keyboard events for selectable lists. If you pass it a query list
334
351
  * of items, it will set the active item correctly when arrow events occur.
@@ -341,15 +358,18 @@ class ListKeyManager {
341
358
  constructor(_items) {
342
359
  this._items = _items;
343
360
  this._activeItemIndex = -1;
361
+ this._activeItem = null;
344
362
  this._wrap = false;
345
363
  this._letterKeyStream = new Subject();
346
364
  this._typeaheadSubscription = Subscription.EMPTY;
347
365
  this._vertical = true;
366
+ this._allowedModifierKeys = [];
348
367
  /**
349
368
  * Predicate function that can be used to check whether an item should be skipped
350
369
  * by the key manager. By default, disabled items are skipped.
351
370
  */
352
371
  this._skipPredicateFn = (item) => item.disabled;
372
+ // Buffer for the letters that the user has pressed when the typeahead option is turned on.
353
373
  this._pressedLetters = [];
354
374
  /**
355
375
  * Stream that emits any time the TAB key is pressed, so components can react
@@ -380,73 +400,96 @@ class ListKeyManager {
380
400
  /**
381
401
  * Sets the predicate function that determines which items should be skipped by the
382
402
  * list key manager.
403
+ * @template THIS
404
+ * @this {THIS}
383
405
  * @param {?} predicate Function that determines whether the given item should be skipped.
384
- * @return {?}
406
+ * @return {THIS}
385
407
  */
386
408
  skipPredicate(predicate) {
387
- this._skipPredicateFn = predicate;
388
- return this;
409
+ (/** @type {?} */ (this))._skipPredicateFn = predicate;
410
+ return (/** @type {?} */ (this));
389
411
  }
390
412
  /**
391
413
  * Configures wrapping mode, which determines whether the active item will wrap to
392
414
  * the other end of list when there are no more items in the given direction.
415
+ * @template THIS
416
+ * @this {THIS}
393
417
  * @param {?=} shouldWrap Whether the list should wrap when reaching the end.
394
- * @return {?}
418
+ * @return {THIS}
395
419
  */
396
420
  withWrap(shouldWrap = true) {
397
- this._wrap = shouldWrap;
398
- return this;
421
+ (/** @type {?} */ (this))._wrap = shouldWrap;
422
+ return (/** @type {?} */ (this));
399
423
  }
400
424
  /**
401
425
  * Configures whether the key manager should be able to move the selection vertically.
426
+ * @template THIS
427
+ * @this {THIS}
402
428
  * @param {?=} enabled Whether vertical selection should be enabled.
403
- * @return {?}
429
+ * @return {THIS}
404
430
  */
405
431
  withVerticalOrientation(enabled = true) {
406
- this._vertical = enabled;
407
- return this;
432
+ (/** @type {?} */ (this))._vertical = enabled;
433
+ return (/** @type {?} */ (this));
408
434
  }
409
435
  /**
410
436
  * Configures the key manager to move the selection horizontally.
411
437
  * Passing in `null` will disable horizontal movement.
438
+ * @template THIS
439
+ * @this {THIS}
412
440
  * @param {?} direction Direction in which the selection can be moved.
413
- * @return {?}
441
+ * @return {THIS}
414
442
  */
415
443
  withHorizontalOrientation(direction) {
416
- this._horizontal = direction;
417
- return this;
444
+ (/** @type {?} */ (this))._horizontal = direction;
445
+ return (/** @type {?} */ (this));
446
+ }
447
+ /**
448
+ * Modifier keys which are allowed to be held down and whose default actions will be prevented
449
+ * as the user is pressing the arrow keys. Defaults to not allowing any modifier keys.
450
+ * @template THIS
451
+ * @this {THIS}
452
+ * @param {?} keys
453
+ * @return {THIS}
454
+ */
455
+ withAllowedModifierKeys(keys) {
456
+ (/** @type {?} */ (this))._allowedModifierKeys = keys;
457
+ return (/** @type {?} */ (this));
418
458
  }
419
459
  /**
420
460
  * Turns on typeahead mode which allows users to set the active item by typing.
461
+ * @template THIS
462
+ * @this {THIS}
421
463
  * @param {?=} debounceInterval Time to wait after the last keystroke before setting the active item.
422
- * @return {?}
464
+ * @return {THIS}
423
465
  */
424
466
  withTypeAhead(debounceInterval = 200) {
425
- if (this._items.length && this._items.some(item => typeof item.getLabel !== 'function')) {
467
+ if ((/** @type {?} */ (this))._items.length && (/** @type {?} */ (this))._items.some(item => typeof item.getLabel !== 'function')) {
426
468
  throw Error('ListKeyManager items in typeahead mode must implement the `getLabel` method.');
427
469
  }
428
- this._typeaheadSubscription.unsubscribe();
470
+ (/** @type {?} */ (this))._typeaheadSubscription.unsubscribe();
429
471
  // Debounce the presses of non-navigational keys, collect the ones that correspond to letters
430
472
  // and convert those letters back into a string. Afterwards find the first item that starts
431
473
  // with that string and select it.
432
- this._typeaheadSubscription = this._letterKeyStream.pipe(tap(keyCode => this._pressedLetters.push(keyCode)), debounceTime(debounceInterval), filter(() => this._pressedLetters.length > 0), map(() => this._pressedLetters.join(''))).subscribe(inputString => {
474
+ (/** @type {?} */ (this))._typeaheadSubscription = (/** @type {?} */ (this))._letterKeyStream.pipe(tap(keyCode => (/** @type {?} */ (this))._pressedLetters.push(keyCode)), debounceTime(debounceInterval), filter(() => (/** @type {?} */ (this))._pressedLetters.length > 0), map(() => (/** @type {?} */ (this))._pressedLetters.join(''))).subscribe(inputString => {
433
475
  /** @type {?} */
434
- const items = this._getItemsArray();
476
+ const items = (/** @type {?} */ (this))._getItemsArray();
435
477
  // Start at 1 because we want to start searching at the item immediately
436
478
  // following the current active item.
437
479
  for (let i = 1; i < items.length + 1; i++) {
438
480
  /** @type {?} */
439
- const index = (this._activeItemIndex + i) % items.length;
481
+ const index = ((/** @type {?} */ (this))._activeItemIndex + i) % items.length;
440
482
  /** @type {?} */
441
483
  const item = items[index];
442
- if (!this._skipPredicateFn(item) && /** @type {?} */ ((item.getLabel))().toUpperCase().trim().indexOf(inputString) === 0) {
443
- this.setActiveItem(index);
484
+ if (!(/** @type {?} */ (this))._skipPredicateFn(item) &&
485
+ (/** @type {?} */ (item.getLabel))().toUpperCase().trim().indexOf(inputString) === 0) {
486
+ (/** @type {?} */ (this)).setActiveItem(index);
444
487
  break;
445
488
  }
446
489
  }
447
- this._pressedLetters = [];
490
+ (/** @type {?} */ (this))._pressedLetters = [];
448
491
  });
449
- return this;
492
+ return (/** @type {?} */ (this));
450
493
  }
451
494
  /**
452
495
  * @param {?} item
@@ -468,12 +511,18 @@ class ListKeyManager {
468
511
  onKeydown(event) {
469
512
  /** @type {?} */
470
513
  const keyCode = event.keyCode;
514
+ /** @type {?} */
515
+ const modifiers = ['altKey', 'ctrlKey', 'metaKey', 'shiftKey'];
516
+ /** @type {?} */
517
+ const isModifierAllowed = modifiers.every(modifier => {
518
+ return !event[modifier] || this._allowedModifierKeys.indexOf(modifier) > -1;
519
+ });
471
520
  switch (keyCode) {
472
521
  case TAB:
473
522
  this.tabOut.next();
474
523
  return;
475
524
  case DOWN_ARROW:
476
- if (this._vertical) {
525
+ if (this._vertical && isModifierAllowed) {
477
526
  this.setNextItemActive();
478
527
  break;
479
528
  }
@@ -481,7 +530,7 @@ class ListKeyManager {
481
530
  return;
482
531
  }
483
532
  case UP_ARROW:
484
- if (this._vertical) {
533
+ if (this._vertical && isModifierAllowed) {
485
534
  this.setPreviousItemActive();
486
535
  break;
487
536
  }
@@ -489,37 +538,31 @@ class ListKeyManager {
489
538
  return;
490
539
  }
491
540
  case RIGHT_ARROW:
492
- if (this._horizontal === 'ltr') {
493
- this.setNextItemActive();
494
- break;
495
- }
496
- else if (this._horizontal === 'rtl') {
497
- this.setPreviousItemActive();
541
+ if (this._horizontal && isModifierAllowed) {
542
+ this._horizontal === 'rtl' ? this.setPreviousItemActive() : this.setNextItemActive();
498
543
  break;
499
544
  }
500
545
  else {
501
546
  return;
502
547
  }
503
548
  case LEFT_ARROW:
504
- if (this._horizontal === 'ltr') {
505
- this.setPreviousItemActive();
506
- break;
507
- }
508
- else if (this._horizontal === 'rtl') {
509
- this.setNextItemActive();
549
+ if (this._horizontal && isModifierAllowed) {
550
+ this._horizontal === 'rtl' ? this.setNextItemActive() : this.setPreviousItemActive();
510
551
  break;
511
552
  }
512
553
  else {
513
554
  return;
514
555
  }
515
556
  default:
516
- // Attempt to use the `event.key` which also maps it to the user's keyboard language,
517
- // otherwise fall back to resolving alphanumeric characters via the keyCode.
518
- if (event.key && event.key.length === 1) {
519
- this._letterKeyStream.next(event.key.toLocaleUpperCase());
520
- }
521
- else if ((keyCode >= A && keyCode <= Z) || (keyCode >= ZERO && keyCode <= NINE)) {
522
- this._letterKeyStream.next(String.fromCharCode(keyCode));
557
+ if (isModifierAllowed || hasModifierKey(event, 'shiftKey')) {
558
+ // Attempt to use the `event.key` which also maps it to the user's keyboard language,
559
+ // otherwise fall back to resolving alphanumeric characters via the keyCode.
560
+ if (event.key && event.key.length === 1) {
561
+ this._letterKeyStream.next(event.key.toLocaleUpperCase());
562
+ }
563
+ else if ((keyCode >= A && keyCode <= Z) || (keyCode >= ZERO && keyCode <= NINE)) {
564
+ this._letterKeyStream.next(String.fromCharCode(keyCode));
565
+ }
523
566
  }
524
567
  // Note that we return here, in order to avoid preventing
525
568
  // the default action of non-navigational keys.
@@ -580,8 +623,11 @@ class ListKeyManager {
580
623
  const itemArray = this._getItemsArray();
581
624
  /** @type {?} */
582
625
  const index = typeof item === 'number' ? item : itemArray.indexOf(item);
626
+ /** @type {?} */
627
+ const activeItem = itemArray[index];
628
+ // Explicitly check for `null` and `undefined` because other falsy values are valid.
629
+ this._activeItem = activeItem == null ? null : activeItem;
583
630
  this._activeItemIndex = index;
584
- this._activeItem = itemArray[index];
585
631
  }
586
632
  /**
587
633
  * Allows setting of the activeItemIndex without any other effects.
@@ -597,6 +643,7 @@ class ListKeyManager {
597
643
  * This method sets the active item, given a list of items and the delta between the
598
644
  * currently active item and the new active item. It will calculate differently
599
645
  * depending on whether wrap mode is turned on.
646
+ * @private
600
647
  * @param {?} delta
601
648
  * @return {?}
602
649
  */
@@ -607,6 +654,7 @@ class ListKeyManager {
607
654
  * Sets the active item properly given "wrap" mode. In other words, it will continue to move
608
655
  * down the list until it finds an item that is not disabled, and it will wrap if it
609
656
  * encounters either end of the list.
657
+ * @private
610
658
  * @param {?} delta
611
659
  * @return {?}
612
660
  */
@@ -628,6 +676,7 @@ class ListKeyManager {
628
676
  * Sets the active item properly given the default mode. In other words, it will
629
677
  * continue to move down the list until it finds an item that is not disabled. If
630
678
  * it encounters either end of the list, it will stop and not wrap.
679
+ * @private
631
680
  * @param {?} delta
632
681
  * @return {?}
633
682
  */
@@ -638,6 +687,7 @@ class ListKeyManager {
638
687
  * Sets the active item to the first enabled item starting at the index specified. If the
639
688
  * item is disabled, it will move in the fallbackDelta direction until it either
640
689
  * finds an enabled item or encounters the end of the list.
690
+ * @private
641
691
  * @param {?} index
642
692
  * @param {?} fallbackDelta
643
693
  * @return {?}
@@ -658,6 +708,7 @@ class ListKeyManager {
658
708
  }
659
709
  /**
660
710
  * Returns the items as an array.
711
+ * @private
661
712
  * @return {?}
662
713
  */
663
714
  _getItemsArray() {
@@ -667,7 +718,7 @@ class ListKeyManager {
667
718
 
668
719
  /**
669
720
  * @fileoverview added by tsickle
670
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
721
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
671
722
  */
672
723
  /**
673
724
  * @template T
@@ -690,7 +741,7 @@ class ActiveDescendantKeyManager extends ListKeyManager {
690
741
 
691
742
  /**
692
743
  * @fileoverview added by tsickle
693
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
744
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
694
745
  */
695
746
  /**
696
747
  * @template T
@@ -702,12 +753,14 @@ class FocusKeyManager extends ListKeyManager {
702
753
  }
703
754
  /**
704
755
  * Sets the focus origin that will be passed in to the items for any subsequent `focus` calls.
756
+ * @template THIS
757
+ * @this {THIS}
705
758
  * @param {?} origin Focus origin to be used when focusing items.
706
- * @return {?}
759
+ * @return {THIS}
707
760
  */
708
761
  setFocusOrigin(origin) {
709
- this._origin = origin;
710
- return this;
762
+ (/** @type {?} */ (this))._origin = origin;
763
+ return (/** @type {?} */ (this));
711
764
  }
712
765
  /**
713
766
  * @param {?} item
@@ -723,8 +776,11 @@ class FocusKeyManager extends ListKeyManager {
723
776
 
724
777
  /**
725
778
  * @fileoverview added by tsickle
726
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
779
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
727
780
  */
781
+ // The InteractivityChecker leans heavily on the ally.js accessibility utilities.
782
+ // Methods like `isTabbable` are only covering specific edge-cases for the browsers which are
783
+ // supported.
728
784
  /**
729
785
  * Utility for checking the interactivity of an element, such as whether is is focusable or
730
786
  * tabbable.
@@ -860,7 +916,7 @@ InteractivityChecker.ctorParameters = () => [
860
916
  */
861
917
  function getFrameElement(window) {
862
918
  try {
863
- return /** @type {?} */ (window.frameElement);
919
+ return (/** @type {?} */ (window.frameElement));
864
920
  }
865
921
  catch (_a) {
866
922
  return null;
@@ -949,6 +1005,7 @@ function getTabIndexValue(element) {
949
1005
  if (!hasValidTabIndex(element)) {
950
1006
  return null;
951
1007
  }
1008
+ // See browser issue in Gecko https://bugzilla.mozilla.org/show_bug.cgi?id=1128054
952
1009
  /** @type {?} */
953
1010
  const tabIndex = parseInt(element.getAttribute('tabindex') || '', 10);
954
1011
  return isNaN(tabIndex) ? -1 : tabIndex;
@@ -962,7 +1019,7 @@ function isPotentiallyTabbableIOS(element) {
962
1019
  /** @type {?} */
963
1020
  let nodeName = element.nodeName.toLowerCase();
964
1021
  /** @type {?} */
965
- let inputType = nodeName === 'input' && (/** @type {?} */ (element)).type;
1022
+ let inputType = nodeName === 'input' && ((/** @type {?} */ (element))).type;
966
1023
  return inputType === 'text'
967
1024
  || inputType === 'password'
968
1025
  || nodeName === 'select'
@@ -996,7 +1053,7 @@ function getWindow(node) {
996
1053
 
997
1054
  /**
998
1055
  * @fileoverview added by tsickle
999
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
1056
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1000
1057
  */
1001
1058
  /**
1002
1059
  * Class that allows for trapping focus within a DOM element.
@@ -1066,17 +1123,17 @@ class FocusTrap {
1066
1123
  }
1067
1124
  this._ngZone.runOutsideAngular(() => {
1068
1125
  if (!this._startAnchor) {
1069
- this._startAnchor = this._createAnchor(); /** @type {?} */
1070
- ((this._startAnchor)).addEventListener('focus', () => this.focusLastTabbableElement());
1126
+ this._startAnchor = this._createAnchor();
1127
+ (/** @type {?} */ (this._startAnchor)).addEventListener('focus', () => this.focusLastTabbableElement());
1071
1128
  }
1072
1129
  if (!this._endAnchor) {
1073
- this._endAnchor = this._createAnchor(); /** @type {?} */
1074
- ((this._endAnchor)).addEventListener('focus', () => this.focusFirstTabbableElement());
1130
+ this._endAnchor = this._createAnchor();
1131
+ (/** @type {?} */ (this._endAnchor)).addEventListener('focus', () => this.focusFirstTabbableElement());
1075
1132
  }
1076
1133
  });
1077
1134
  if (this._element.parentNode) {
1078
- this._element.parentNode.insertBefore(/** @type {?} */ ((this._startAnchor)), this._element);
1079
- this._element.parentNode.insertBefore(/** @type {?} */ ((this._endAnchor)), this._element.nextSibling);
1135
+ this._element.parentNode.insertBefore((/** @type {?} */ (this._startAnchor)), this._element);
1136
+ this._element.parentNode.insertBefore((/** @type {?} */ (this._endAnchor)), this._element.nextSibling);
1080
1137
  this._hasAttached = true;
1081
1138
  }
1082
1139
  return this._hasAttached;
@@ -1116,14 +1173,16 @@ class FocusTrap {
1116
1173
  }
1117
1174
  /**
1118
1175
  * Get the specified boundary element of the trapped region.
1176
+ * @private
1119
1177
  * @param {?} bound The boundary to get (start or end of trapped region).
1120
1178
  * @return {?} The boundary element.
1121
1179
  */
1122
1180
  _getRegionBoundary(bound) {
1181
+ // Contains the deprecated version of selector, for temporary backwards comparability.
1123
1182
  /** @type {?} */
1124
- let markers = /** @type {?} */ (this._element.querySelectorAll(`[cdk-focus-region-${bound}], ` +
1183
+ let markers = (/** @type {?} */ (this._element.querySelectorAll(`[cdk-focus-region-${bound}], ` +
1125
1184
  `[cdkFocusRegion${bound}], ` +
1126
- `[cdk-focus-${bound}]`));
1185
+ `[cdk-focus-${bound}]`)));
1127
1186
  for (let i = 0; i < markers.length; i++) {
1128
1187
  // @breaking-change 8.0.0
1129
1188
  if (markers[i].hasAttribute(`cdk-focus-${bound}`)) {
@@ -1148,9 +1207,10 @@ class FocusTrap {
1148
1207
  * @return {?} Whether focus was moved successfuly.
1149
1208
  */
1150
1209
  focusInitialElement() {
1210
+ // Contains the deprecated version of selector, for temporary backwards comparability.
1151
1211
  /** @type {?} */
1152
- const redirectToElement = /** @type {?} */ (this._element.querySelector(`[cdk-focus-initial], ` +
1153
- `[cdkFocusInitial]`));
1212
+ const redirectToElement = (/** @type {?} */ (this._element.querySelector(`[cdk-focus-initial], ` +
1213
+ `[cdkFocusInitial]`)));
1154
1214
  if (redirectToElement) {
1155
1215
  // @breaking-change 8.0.0
1156
1216
  if (redirectToElement.hasAttribute(`cdk-focus-initial`)) {
@@ -1158,6 +1218,11 @@ class FocusTrap {
1158
1218
  `use 'cdkFocusInitial' instead. The deprecated attribute ` +
1159
1219
  `will be removed in 8.0.0`, redirectToElement);
1160
1220
  }
1221
+ // Warn the consumer if the element they've pointed to
1222
+ // isn't focusable, when not in production mode.
1223
+ if (isDevMode() && !this._checker.isFocusable(redirectToElement)) {
1224
+ console.warn(`Element matching '[cdkFocusInitial]' is not focusable.`, redirectToElement);
1225
+ }
1161
1226
  redirectToElement.focus();
1162
1227
  return true;
1163
1228
  }
@@ -1196,6 +1261,7 @@ class FocusTrap {
1196
1261
  }
1197
1262
  /**
1198
1263
  * Get the first tabbable element from a DOM subtree (inclusive).
1264
+ * @private
1199
1265
  * @param {?} root
1200
1266
  * @return {?}
1201
1267
  */
@@ -1203,12 +1269,14 @@ class FocusTrap {
1203
1269
  if (this._checker.isFocusable(root) && this._checker.isTabbable(root)) {
1204
1270
  return root;
1205
1271
  }
1272
+ // Iterate in DOM order. Note that IE doesn't have `children` for SVG so we fall
1273
+ // back to `childNodes` which includes text nodes, comments etc.
1206
1274
  /** @type {?} */
1207
1275
  let children = root.children || root.childNodes;
1208
1276
  for (let i = 0; i < children.length; i++) {
1209
1277
  /** @type {?} */
1210
1278
  let tabbableChild = children[i].nodeType === this._document.ELEMENT_NODE ?
1211
- this._getFirstTabbableElement(/** @type {?} */ (children[i])) :
1279
+ this._getFirstTabbableElement((/** @type {?} */ (children[i]))) :
1212
1280
  null;
1213
1281
  if (tabbableChild) {
1214
1282
  return tabbableChild;
@@ -1218,6 +1286,7 @@ class FocusTrap {
1218
1286
  }
1219
1287
  /**
1220
1288
  * Get the last tabbable element from a DOM subtree (inclusive).
1289
+ * @private
1221
1290
  * @param {?} root
1222
1291
  * @return {?}
1223
1292
  */
@@ -1225,12 +1294,13 @@ class FocusTrap {
1225
1294
  if (this._checker.isFocusable(root) && this._checker.isTabbable(root)) {
1226
1295
  return root;
1227
1296
  }
1297
+ // Iterate in reverse DOM order.
1228
1298
  /** @type {?} */
1229
1299
  let children = root.children || root.childNodes;
1230
1300
  for (let i = children.length - 1; i >= 0; i--) {
1231
1301
  /** @type {?} */
1232
1302
  let tabbableChild = children[i].nodeType === this._document.ELEMENT_NODE ?
1233
- this._getLastTabbableElement(/** @type {?} */ (children[i])) :
1303
+ this._getLastTabbableElement((/** @type {?} */ (children[i]))) :
1234
1304
  null;
1235
1305
  if (tabbableChild) {
1236
1306
  return tabbableChild;
@@ -1240,6 +1310,7 @@ class FocusTrap {
1240
1310
  }
1241
1311
  /**
1242
1312
  * Creates an anchor element.
1313
+ * @private
1243
1314
  * @return {?}
1244
1315
  */
1245
1316
  _createAnchor() {
@@ -1252,6 +1323,7 @@ class FocusTrap {
1252
1323
  }
1253
1324
  /**
1254
1325
  * Toggles the `tabindex` of an anchor, based on the enabled state of the focus trap.
1326
+ * @private
1255
1327
  * @param {?} isEnabled Whether the focus trap is enabled.
1256
1328
  * @param {?} anchor Anchor on which to toggle the tabindex.
1257
1329
  * @return {?}
@@ -1263,6 +1335,7 @@ class FocusTrap {
1263
1335
  }
1264
1336
  /**
1265
1337
  * Executes a function when the zone is stable.
1338
+ * @private
1266
1339
  * @param {?} fn
1267
1340
  * @return {?}
1268
1341
  */
@@ -1368,7 +1441,7 @@ class CdkTrapFocus {
1368
1441
  ngAfterContentInit() {
1369
1442
  this.focusTrap.attachAnchors();
1370
1443
  if (this.autoCapture) {
1371
- this._previouslyFocusedElement = /** @type {?} */ (this._document.activeElement);
1444
+ this._previouslyFocusedElement = (/** @type {?} */ (this._document.activeElement));
1372
1445
  this.focusTrap.focusInitialElementWhenReady();
1373
1446
  }
1374
1447
  }
@@ -1400,8 +1473,10 @@ CdkTrapFocus.propDecorators = {
1400
1473
 
1401
1474
  /**
1402
1475
  * @fileoverview added by tsickle
1403
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
1476
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1404
1477
  */
1478
+ // The token for the live announcer element is defined in a separate file from LiveAnnouncer
1479
+ // as a workaround for https://github.com/angular/angular/issues/22559
1405
1480
  /** @type {?} */
1406
1481
  const LIVE_ANNOUNCER_ELEMENT_TOKEN = new InjectionToken('liveAnnouncerElement', {
1407
1482
  providedIn: 'root',
@@ -1417,7 +1492,7 @@ function LIVE_ANNOUNCER_ELEMENT_TOKEN_FACTORY() {
1417
1492
 
1418
1493
  /**
1419
1494
  * @fileoverview added by tsickle
1420
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
1495
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1421
1496
  */
1422
1497
  class LiveAnnouncer {
1423
1498
  /**
@@ -1434,15 +1509,25 @@ class LiveAnnouncer {
1434
1509
  this._liveElement = elementToken || this._createLiveElement();
1435
1510
  }
1436
1511
  /**
1437
- * Announces a message to screenreaders.
1438
- * @param {?} message Message to be announced to the screenreader
1439
- * @param {?=} politeness The politeness of the announcer element
1440
- * @return {?} Promise that will be resolved when the message is added to the DOM.
1512
+ * @param {?} message
1513
+ * @param {...?} args
1514
+ * @return {?}
1441
1515
  */
1442
- announce(message, politeness = 'polite') {
1443
- this._liveElement.textContent = '';
1516
+ announce(message, ...args) {
1517
+ /** @type {?} */
1518
+ let politeness;
1519
+ /** @type {?} */
1520
+ let duration;
1521
+ if (args.length === 1 && typeof args[0] === 'number') {
1522
+ duration = args[0];
1523
+ }
1524
+ else {
1525
+ [politeness, duration] = args;
1526
+ }
1527
+ this.clear();
1528
+ clearTimeout(this._previousTimeout);
1444
1529
  // TODO: ensure changing the politeness works on all environments we support.
1445
- this._liveElement.setAttribute('aria-live', politeness);
1530
+ this._liveElement.setAttribute('aria-live', (/** @type {?} */ (politeness)) || 'polite');
1446
1531
  // This 100ms timeout is necessary for some browser + screen-reader combinations:
1447
1532
  // - Both JAWS and NVDA over IE11 will not announce anything without a non-zero timeout.
1448
1533
  // - With Chrome and IE11 with NVDA or JAWS, a repeated (identical) message won't be read a
@@ -1450,22 +1535,40 @@ class LiveAnnouncer {
1450
1535
  // (using JAWS 17 at time of this writing).
1451
1536
  return this._ngZone.runOutsideAngular(() => {
1452
1537
  return new Promise(resolve => {
1453
- setTimeout(() => {
1538
+ clearTimeout(this._previousTimeout);
1539
+ this._previousTimeout = setTimeout(() => {
1454
1540
  this._liveElement.textContent = message;
1455
1541
  resolve();
1542
+ if (typeof duration === 'number') {
1543
+ this._previousTimeout = setTimeout(() => this.clear(), duration);
1544
+ }
1456
1545
  }, 100);
1457
1546
  });
1458
1547
  });
1459
1548
  }
1549
+ /**
1550
+ * Clears the current text from the announcer element. Can be used to prevent
1551
+ * screen readers from reading the text out again while the user is going
1552
+ * through the page landmarks.
1553
+ * @return {?}
1554
+ */
1555
+ clear() {
1556
+ if (this._liveElement) {
1557
+ this._liveElement.textContent = '';
1558
+ }
1559
+ }
1460
1560
  /**
1461
1561
  * @return {?}
1462
1562
  */
1463
1563
  ngOnDestroy() {
1564
+ clearTimeout(this._previousTimeout);
1464
1565
  if (this._liveElement && this._liveElement.parentNode) {
1465
1566
  this._liveElement.parentNode.removeChild(this._liveElement);
1567
+ this._liveElement = (/** @type {?} */ (null));
1466
1568
  }
1467
1569
  }
1468
1570
  /**
1571
+ * @private
1469
1572
  * @return {?}
1470
1573
  */
1471
1574
  _createLiveElement() {
@@ -1477,7 +1580,7 @@ class LiveAnnouncer {
1477
1580
  const liveEl = this._document.createElement('div');
1478
1581
  // Remove any old containers. This can happen when coming in from a server-side-rendered page.
1479
1582
  for (let i = 0; i < previousElements.length; i++) {
1480
- /** @type {?} */ ((previousElements[i].parentNode)).removeChild(previousElements[i]);
1583
+ (/** @type {?} */ (previousElements[i].parentNode)).removeChild(previousElements[i]);
1481
1584
  }
1482
1585
  liveEl.classList.add(elementClass);
1483
1586
  liveEl.classList.add('cdk-visually-hidden');
@@ -1537,9 +1640,15 @@ class CdkAriaLive {
1537
1640
  return this._contentObserver
1538
1641
  .observe(this._elementRef)
1539
1642
  .subscribe(() => {
1643
+ // Note that we use textContent here, rather than innerText, in order to avoid a reflow.
1540
1644
  /** @type {?} */
1541
- const element = this._elementRef.nativeElement;
1542
- this._liveAnnouncer.announce(element.textContent, this._politeness);
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
+ }
1543
1652
  });
1544
1653
  });
1545
1654
  }
@@ -1571,18 +1680,19 @@ CdkAriaLive.propDecorators = {
1571
1680
  };
1572
1681
  /**
1573
1682
  * \@docs-private \@deprecated \@breaking-change 8.0.0
1574
- * @param {?} parentDispatcher
1683
+ * @param {?} parentAnnouncer
1575
1684
  * @param {?} liveElement
1576
1685
  * @param {?} _document
1577
1686
  * @param {?} ngZone
1578
1687
  * @return {?}
1579
1688
  */
1580
- function LIVE_ANNOUNCER_PROVIDER_FACTORY(parentDispatcher, liveElement, _document, ngZone) {
1581
- return parentDispatcher || new LiveAnnouncer(liveElement, _document, ngZone);
1689
+ function LIVE_ANNOUNCER_PROVIDER_FACTORY(parentAnnouncer, liveElement, _document, ngZone) {
1690
+ return parentAnnouncer || new LiveAnnouncer(liveElement, ngZone, _document);
1582
1691
  }
1583
- /** *
1692
+ /**
1584
1693
  * \@docs-private \@deprecated \@breaking-change 8.0.0
1585
- @type {?} */
1694
+ * @type {?}
1695
+ */
1586
1696
  const LIVE_ANNOUNCER_PROVIDER = {
1587
1697
  // If there is already a LiveAnnouncer available, use that. Otherwise, provide a new one.
1588
1698
  provide: LiveAnnouncer,
@@ -1597,10 +1707,21 @@ const LIVE_ANNOUNCER_PROVIDER = {
1597
1707
 
1598
1708
  /**
1599
1709
  * @fileoverview added by tsickle
1600
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
1710
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1601
1711
  */
1712
+ // This is the value used by AngularJS Material. Through trial and error (on iPhone 6S) they found
1713
+ // that a value of around 650ms seems appropriate.
1602
1714
  /** @type {?} */
1603
1715
  const TOUCH_BUFFER_MS = 650;
1716
+ /**
1717
+ * Event listener options that enable capturing and also
1718
+ * mark the the listener as passive if the browser supports it.
1719
+ * @type {?}
1720
+ */
1721
+ const captureEventListenerOptions = normalizePassiveListenerOptions({
1722
+ passive: true,
1723
+ capture: true
1724
+ });
1604
1725
  /**
1605
1726
  * Monitors mouse and keyboard events to determine the cause of focus events.
1606
1727
  */
@@ -1624,14 +1745,54 @@ class FocusMonitor {
1624
1745
  * Map of elements being monitored to their info.
1625
1746
  */
1626
1747
  this._elementInfo = new Map();
1627
- /**
1628
- * A map of global objects to lists of current listeners.
1629
- */
1630
- this._unregisterGlobalListeners = () => { };
1631
1748
  /**
1632
1749
  * The number of elements currently being monitored.
1633
1750
  */
1634
1751
  this._monitoredElementCount = 0;
1752
+ /**
1753
+ * Event listener for `keydown` events on the document.
1754
+ * Needs to be an arrow function in order to preserve the context when it gets bound.
1755
+ */
1756
+ this._documentKeydownListener = () => {
1757
+ // On keydown record the origin and clear any touch event that may be in progress.
1758
+ this._lastTouchTarget = null;
1759
+ this._setOriginForCurrentEventQueue('keyboard');
1760
+ };
1761
+ /**
1762
+ * Event listener for `mousedown` events on the document.
1763
+ * Needs to be an arrow function in order to preserve the context when it gets bound.
1764
+ */
1765
+ this._documentMousedownListener = () => {
1766
+ // On mousedown record the origin only if there is not touch
1767
+ // target, since a mousedown can happen as a result of a touch event.
1768
+ if (!this._lastTouchTarget) {
1769
+ this._setOriginForCurrentEventQueue('mouse');
1770
+ }
1771
+ };
1772
+ /**
1773
+ * Event listener for `touchstart` events on the document.
1774
+ * Needs to be an arrow function in order to preserve the context when it gets bound.
1775
+ */
1776
+ this._documentTouchstartListener = (event) => {
1777
+ // When the touchstart event fires the focus event is not yet in the event queue. This means
1778
+ // we can't rely on the trick used above (setting timeout of 1ms). Instead we wait 650ms to
1779
+ // see if a focus happens.
1780
+ if (this._touchTimeoutId != null) {
1781
+ clearTimeout(this._touchTimeoutId);
1782
+ }
1783
+ this._lastTouchTarget = event.target;
1784
+ this._touchTimeoutId = setTimeout(() => this._lastTouchTarget = null, TOUCH_BUFFER_MS);
1785
+ };
1786
+ /**
1787
+ * Event listener for `focus` events on the window.
1788
+ * Needs to be an arrow function in order to preserve the context when it gets bound.
1789
+ */
1790
+ this._windowFocusListener = () => {
1791
+ // Make a note of when the window regains focus, so we can
1792
+ // restore the origin info for the focused element.
1793
+ this._windowFocused = true;
1794
+ this._windowFocusTimeoutId = setTimeout(() => this._windowFocused = false);
1795
+ };
1635
1796
  }
1636
1797
  /**
1637
1798
  * @param {?} element
@@ -1648,10 +1809,11 @@ class FocusMonitor {
1648
1809
  // Check if we're already monitoring this element.
1649
1810
  if (this._elementInfo.has(nativeElement)) {
1650
1811
  /** @type {?} */
1651
- let cachedInfo = this._elementInfo.get(nativeElement); /** @type {?} */
1652
- ((cachedInfo)).checkChildren = checkChildren;
1653
- return /** @type {?} */ ((cachedInfo)).subject.asObservable();
1812
+ let cachedInfo = this._elementInfo.get(nativeElement);
1813
+ (/** @type {?} */ (cachedInfo)).checkChildren = checkChildren;
1814
+ return (/** @type {?} */ (cachedInfo)).subject.asObservable();
1654
1815
  }
1816
+ // Create monitored element info.
1655
1817
  /** @type {?} */
1656
1818
  let info = {
1657
1819
  unlisten: () => { },
@@ -1660,6 +1822,7 @@ class FocusMonitor {
1660
1822
  };
1661
1823
  this._elementInfo.set(nativeElement, info);
1662
1824
  this._incrementMonitoredElementCount();
1825
+ // Start listening. We need to listen in capture phase since focus events don't bubble.
1663
1826
  /** @type {?} */
1664
1827
  let focusListener = (event) => this._onFocus(event, nativeElement);
1665
1828
  /** @type {?} */
@@ -1705,7 +1868,7 @@ class FocusMonitor {
1705
1868
  // `focus` isn't available on the server
1706
1869
  if (typeof nativeElement.focus === 'function') {
1707
1870
  // Cast the element to `any`, because the TS typings don't have the `options` parameter yet.
1708
- (/** @type {?} */ (nativeElement)).focus(options);
1871
+ ((/** @type {?} */ (nativeElement))).focus(options);
1709
1872
  }
1710
1873
  }
1711
1874
  /**
@@ -1715,63 +1878,7 @@ class FocusMonitor {
1715
1878
  this._elementInfo.forEach((_info, element) => this.stopMonitoring(element));
1716
1879
  }
1717
1880
  /**
1718
- * Register necessary event listeners on the document and window.
1719
- * @return {?}
1720
- */
1721
- _registerGlobalListeners() {
1722
- // Do nothing if we're not on the browser platform.
1723
- if (!this._platform.isBrowser) {
1724
- return;
1725
- }
1726
- /** @type {?} */
1727
- let documentKeydownListener = () => {
1728
- this._lastTouchTarget = null;
1729
- this._setOriginForCurrentEventQueue('keyboard');
1730
- };
1731
- /** @type {?} */
1732
- let documentMousedownListener = () => {
1733
- if (!this._lastTouchTarget) {
1734
- this._setOriginForCurrentEventQueue('mouse');
1735
- }
1736
- };
1737
- /** @type {?} */
1738
- let documentTouchstartListener = (event) => {
1739
- if (this._touchTimeoutId != null) {
1740
- clearTimeout(this._touchTimeoutId);
1741
- }
1742
- this._lastTouchTarget = event.target;
1743
- this._touchTimeoutId = setTimeout(() => this._lastTouchTarget = null, TOUCH_BUFFER_MS);
1744
- };
1745
- /** @type {?} */
1746
- let windowFocusListener = () => {
1747
- this._windowFocused = true;
1748
- this._windowFocusTimeoutId = setTimeout(() => this._windowFocused = false);
1749
- };
1750
- /** @type {?} */
1751
- const captureEventListenerOptions = normalizePassiveListenerOptions({
1752
- passive: true,
1753
- capture: true
1754
- });
1755
- // Note: we listen to events in the capture phase so we can detect them even if the user stops
1756
- // propagation.
1757
- this._ngZone.runOutsideAngular(() => {
1758
- document.addEventListener('keydown', documentKeydownListener, captureEventListenerOptions);
1759
- document.addEventListener('mousedown', documentMousedownListener, captureEventListenerOptions);
1760
- document.addEventListener('touchstart', documentTouchstartListener, captureEventListenerOptions);
1761
- window.addEventListener('focus', windowFocusListener);
1762
- });
1763
- this._unregisterGlobalListeners = () => {
1764
- document.removeEventListener('keydown', documentKeydownListener, captureEventListenerOptions);
1765
- document.removeEventListener('mousedown', documentMousedownListener, captureEventListenerOptions);
1766
- document.removeEventListener('touchstart', documentTouchstartListener, captureEventListenerOptions);
1767
- window.removeEventListener('focus', windowFocusListener);
1768
- // Clear timeouts for all potentially pending timeouts to prevent the leaks.
1769
- clearTimeout(this._windowFocusTimeoutId);
1770
- clearTimeout(this._touchTimeoutId);
1771
- clearTimeout(this._originTimeoutId);
1772
- };
1773
- }
1774
- /**
1881
+ * @private
1775
1882
  * @param {?} element
1776
1883
  * @param {?} className
1777
1884
  * @param {?} shouldSet
@@ -1787,6 +1894,7 @@ class FocusMonitor {
1787
1894
  }
1788
1895
  /**
1789
1896
  * Sets the focus classes on the element based on the given focus origin.
1897
+ * @private
1790
1898
  * @param {?} element The element to update the classes on.
1791
1899
  * @param {?=} origin The focus origin.
1792
1900
  * @return {?}
@@ -1804,6 +1912,7 @@ class FocusMonitor {
1804
1912
  }
1805
1913
  /**
1806
1914
  * Sets the origin and schedules an async function to clear it at the end of the event queue.
1915
+ * @private
1807
1916
  * @param {?} origin The origin to set.
1808
1917
  * @return {?}
1809
1918
  */
@@ -1818,10 +1927,28 @@ class FocusMonitor {
1818
1927
  }
1819
1928
  /**
1820
1929
  * Checks whether the given focus event was caused by a touchstart event.
1930
+ * @private
1821
1931
  * @param {?} event The focus event to check.
1822
1932
  * @return {?} Whether the event was caused by a touch.
1823
1933
  */
1824
1934
  _wasCausedByTouch(event) {
1935
+ // Note(mmalerba): This implementation is not quite perfect, there is a small edge case.
1936
+ // Consider the following dom structure:
1937
+ //
1938
+ // <div #parent tabindex="0" cdkFocusClasses>
1939
+ // <div #child (click)="#parent.focus()"></div>
1940
+ // </div>
1941
+ //
1942
+ // If the user touches the #child element and the #parent is programmatically focused as a
1943
+ // result, this code will still consider it to have been caused by the touch event and will
1944
+ // apply the cdk-touch-focused class rather than the cdk-program-focused class. This is a
1945
+ // relatively small edge-case that can be worked around by using
1946
+ // focusVia(parentEl, 'program') to focus the parent element.
1947
+ //
1948
+ // If we decide that we absolutely must handle this case correctly, we can do so by listening
1949
+ // for the first focus event after the touchstart, and then the first blur event after that
1950
+ // focus event. When that blur event fires we know that whatever follows is not a result of the
1951
+ // touchstart.
1825
1952
  /** @type {?} */
1826
1953
  let focusTarget = event.target;
1827
1954
  return this._lastTouchTarget instanceof Node && focusTarget instanceof Node &&
@@ -1829,16 +1956,33 @@ class FocusMonitor {
1829
1956
  }
1830
1957
  /**
1831
1958
  * Handles focus events on a registered element.
1959
+ * @private
1832
1960
  * @param {?} event The focus event.
1833
1961
  * @param {?} element The monitored element.
1834
1962
  * @return {?}
1835
1963
  */
1836
1964
  _onFocus(event, element) {
1965
+ // NOTE(mmalerba): We currently set the classes based on the focus origin of the most recent
1966
+ // focus event affecting the monitored element. If we want to use the origin of the first event
1967
+ // instead we should check for the cdk-focused class here and return if the element already has
1968
+ // it. (This only matters for elements that have includesChildren = true).
1969
+ // NOTE(mmalerba): We currently set the classes based on the focus origin of the most recent
1970
+ // focus event affecting the monitored element. If we want to use the origin of the first event
1971
+ // instead we should check for the cdk-focused class here and return if the element already has
1972
+ // it. (This only matters for elements that have includesChildren = true).
1973
+ // If we are not counting child-element-focus as focused, make sure that the event target is the
1974
+ // monitored element itself.
1837
1975
  /** @type {?} */
1838
1976
  const elementInfo = this._elementInfo.get(element);
1839
1977
  if (!elementInfo || (!elementInfo.checkChildren && element !== event.target)) {
1840
1978
  return;
1841
1979
  }
1980
+ // If we couldn't detect a cause for the focus event, it's due to one of three reasons:
1981
+ // 1) The window has just regained focus, in which case we want to restore the focused state of
1982
+ // the element from before the window blurred.
1983
+ // 2) It was caused by a touch event, in which case we mark the origin as 'touch'.
1984
+ // 3) The element was programmatically focused, in which case we should mark the origin as
1985
+ // 'program'.
1842
1986
  /** @type {?} */
1843
1987
  let origin = this._origin;
1844
1988
  if (!origin) {
@@ -1863,6 +2007,8 @@ class FocusMonitor {
1863
2007
  * @return {?}
1864
2008
  */
1865
2009
  _onBlur(event, element) {
2010
+ // If we are counting child-element-focus as focused, make sure that we aren't just blurring in
2011
+ // order to focus another child of the monitored element.
1866
2012
  /** @type {?} */
1867
2013
  const elementInfo = this._elementInfo.get(element);
1868
2014
  if (!elementInfo || (elementInfo.checkChildren && event.relatedTarget instanceof Node &&
@@ -1873,6 +2019,7 @@ class FocusMonitor {
1873
2019
  this._emitOrigin(elementInfo.subject, null);
1874
2020
  }
1875
2021
  /**
2022
+ * @private
1876
2023
  * @param {?} subject
1877
2024
  * @param {?} origin
1878
2025
  * @return {?}
@@ -1881,25 +2028,41 @@ class FocusMonitor {
1881
2028
  this._ngZone.run(() => subject.next(origin));
1882
2029
  }
1883
2030
  /**
2031
+ * @private
1884
2032
  * @return {?}
1885
2033
  */
1886
2034
  _incrementMonitoredElementCount() {
1887
2035
  // Register global listeners when first element is monitored.
1888
- if (++this._monitoredElementCount == 1) {
1889
- this._registerGlobalListeners();
2036
+ if (++this._monitoredElementCount == 1 && this._platform.isBrowser) {
2037
+ // Note: we listen to events in the capture phase so we
2038
+ // can detect them even if the user stops propagation.
2039
+ this._ngZone.runOutsideAngular(() => {
2040
+ document.addEventListener('keydown', this._documentKeydownListener, captureEventListenerOptions);
2041
+ document.addEventListener('mousedown', this._documentMousedownListener, captureEventListenerOptions);
2042
+ document.addEventListener('touchstart', this._documentTouchstartListener, captureEventListenerOptions);
2043
+ window.addEventListener('focus', this._windowFocusListener);
2044
+ });
1890
2045
  }
1891
2046
  }
1892
2047
  /**
2048
+ * @private
1893
2049
  * @return {?}
1894
2050
  */
1895
2051
  _decrementMonitoredElementCount() {
1896
2052
  // Unregister global listeners when last element is unmonitored.
1897
2053
  if (!--this._monitoredElementCount) {
1898
- this._unregisterGlobalListeners();
1899
- this._unregisterGlobalListeners = () => { };
2054
+ document.removeEventListener('keydown', this._documentKeydownListener, captureEventListenerOptions);
2055
+ document.removeEventListener('mousedown', this._documentMousedownListener, captureEventListenerOptions);
2056
+ document.removeEventListener('touchstart', this._documentTouchstartListener, captureEventListenerOptions);
2057
+ window.removeEventListener('focus', this._windowFocusListener);
2058
+ // Clear timeouts for all potentially pending timeouts to prevent the leaks.
2059
+ clearTimeout(this._windowFocusTimeoutId);
2060
+ clearTimeout(this._touchTimeoutId);
2061
+ clearTimeout(this._originTimeoutId);
1900
2062
  }
1901
2063
  }
1902
2064
  /**
2065
+ * @private
1903
2066
  * @param {?} element
1904
2067
  * @return {?}
1905
2068
  */
@@ -1968,9 +2131,10 @@ CdkMonitorFocus.propDecorators = {
1968
2131
  function FOCUS_MONITOR_PROVIDER_FACTORY(parentDispatcher, ngZone, platform) {
1969
2132
  return parentDispatcher || new FocusMonitor(ngZone, platform);
1970
2133
  }
1971
- /** *
2134
+ /**
1972
2135
  * \@docs-private \@deprecated \@breaking-change 8.0.0
1973
- @type {?} */
2136
+ * @type {?}
2137
+ */
1974
2138
  const FOCUS_MONITOR_PROVIDER = {
1975
2139
  // If there is already a FocusMonitor available, use that. Otherwise, provide a new one.
1976
2140
  provide: FocusMonitor,
@@ -1980,7 +2144,7 @@ const FOCUS_MONITOR_PROVIDER = {
1980
2144
 
1981
2145
  /**
1982
2146
  * @fileoverview added by tsickle
1983
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
2147
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1984
2148
  */
1985
2149
 
1986
2150
  /**
@@ -1998,7 +2162,7 @@ function isFakeMousedownFromScreenReader(event) {
1998
2162
 
1999
2163
  /**
2000
2164
  * @fileoverview added by tsickle
2001
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
2165
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
2002
2166
  */
2003
2167
  class A11yModule {
2004
2168
  }
@@ -2012,12 +2176,12 @@ A11yModule.decorators = [
2012
2176
 
2013
2177
  /**
2014
2178
  * @fileoverview added by tsickle
2015
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
2179
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
2016
2180
  */
2017
2181
 
2018
2182
  /**
2019
2183
  * @fileoverview added by tsickle
2020
- * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
2184
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
2021
2185
  */
2022
2186
 
2023
2187
  export { ARIA_DESCRIBER_PROVIDER_FACTORY, MESSAGES_CONTAINER_ID, CDK_DESCRIBEDBY_ID_PREFIX, CDK_DESCRIBEDBY_HOST_ATTRIBUTE, AriaDescriber, ARIA_DESCRIBER_PROVIDER, ActiveDescendantKeyManager, FocusKeyManager, ListKeyManager, FocusTrap, FocusTrapFactory, CdkTrapFocus, InteractivityChecker, LIVE_ANNOUNCER_PROVIDER_FACTORY, LiveAnnouncer, CdkAriaLive, LIVE_ANNOUNCER_PROVIDER, LIVE_ANNOUNCER_ELEMENT_TOKEN_FACTORY, LIVE_ANNOUNCER_ELEMENT_TOKEN, FOCUS_MONITOR_PROVIDER_FACTORY, TOUCH_BUFFER_MS, FocusMonitor, CdkMonitorFocus, FOCUS_MONITOR_PROVIDER, isFakeMousedownFromScreenReader, A11yModule };