@angular/cdk 10.0.2 → 10.1.3

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 (216) hide show
  1. package/a11y/aria-describer/aria-describer.d.ts +10 -1
  2. package/a11y/index.metadata.json +1 -1
  3. package/a11y/interactivity-checker/interactivity-checker.d.ts +11 -1
  4. package/a11y/key-manager/list-key-manager.d.ts +6 -0
  5. package/accordion/accordion.d.ts +7 -1
  6. package/accordion/index.d.ts +1 -0
  7. package/accordion/index.metadata.json +1 -1
  8. package/bundles/cdk-a11y.umd.js +514 -410
  9. package/bundles/cdk-a11y.umd.js.map +1 -1
  10. package/bundles/cdk-a11y.umd.min.js +35 -11
  11. package/bundles/cdk-a11y.umd.min.js.map +1 -1
  12. package/bundles/cdk-accordion.umd.js +47 -39
  13. package/bundles/cdk-accordion.umd.js.map +1 -1
  14. package/bundles/cdk-accordion.umd.min.js +10 -2
  15. package/bundles/cdk-accordion.umd.min.js.map +1 -1
  16. package/bundles/cdk-bidi.umd.js +25 -25
  17. package/bundles/cdk-bidi.umd.js.map +1 -1
  18. package/bundles/cdk-bidi.umd.min.js +5 -4
  19. package/bundles/cdk-bidi.umd.min.js.map +1 -1
  20. package/bundles/cdk-clipboard.umd.js +37 -36
  21. package/bundles/cdk-clipboard.umd.js.map +1 -1
  22. package/bundles/cdk-clipboard.umd.min.js +10 -2
  23. package/bundles/cdk-clipboard.umd.min.js.map +1 -1
  24. package/bundles/cdk-coercion.umd.js.map +1 -1
  25. package/bundles/cdk-collections.umd.js +303 -237
  26. package/bundles/cdk-collections.umd.js.map +1 -1
  27. package/bundles/cdk-collections.umd.min.js +3 -9
  28. package/bundles/cdk-collections.umd.min.js.map +1 -1
  29. package/bundles/cdk-drag-drop.umd.js +1059 -927
  30. package/bundles/cdk-drag-drop.umd.js.map +1 -1
  31. package/bundles/cdk-drag-drop.umd.min.js +72 -10
  32. package/bundles/cdk-drag-drop.umd.min.js.map +1 -1
  33. package/bundles/cdk-keycodes.umd.js.map +1 -1
  34. package/bundles/cdk-layout.umd.js +18 -18
  35. package/bundles/cdk-layout.umd.js.map +1 -1
  36. package/bundles/cdk-layout.umd.min.js +6 -5
  37. package/bundles/cdk-layout.umd.min.js.map +1 -1
  38. package/bundles/cdk-observers.umd.js +34 -34
  39. package/bundles/cdk-observers.umd.js.map +1 -1
  40. package/bundles/cdk-observers.umd.min.js +2 -2
  41. package/bundles/cdk-observers.umd.min.js.map +1 -1
  42. package/bundles/cdk-overlay.umd.js +638 -416
  43. package/bundles/cdk-overlay.umd.js.map +1 -1
  44. package/bundles/cdk-overlay.umd.min.js +51 -12
  45. package/bundles/cdk-overlay.umd.min.js.map +1 -1
  46. package/bundles/cdk-platform.umd.js +10 -10
  47. package/bundles/cdk-platform.umd.js.map +1 -1
  48. package/bundles/cdk-platform.umd.min.js +4 -11
  49. package/bundles/cdk-platform.umd.min.js.map +1 -1
  50. package/bundles/cdk-portal.umd.js +355 -300
  51. package/bundles/cdk-portal.umd.js.map +1 -1
  52. package/bundles/cdk-portal.umd.min.js +4 -5
  53. package/bundles/cdk-portal.umd.min.js.map +1 -1
  54. package/bundles/cdk-scrolling.umd.js +482 -392
  55. package/bundles/cdk-scrolling.umd.js.map +1 -1
  56. package/bundles/cdk-scrolling.umd.min.js +20 -12
  57. package/bundles/cdk-scrolling.umd.min.js.map +1 -1
  58. package/bundles/cdk-stepper.umd.js +117 -117
  59. package/bundles/cdk-stepper.umd.js.map +1 -1
  60. package/bundles/cdk-stepper.umd.min.js +11 -2
  61. package/bundles/cdk-stepper.umd.min.js.map +1 -1
  62. package/bundles/cdk-table.umd.js +862 -607
  63. package/bundles/cdk-table.umd.js.map +1 -1
  64. package/bundles/cdk-table.umd.min.js +8 -15
  65. package/bundles/cdk-table.umd.min.js.map +1 -1
  66. package/bundles/cdk-testing-protractor.umd.js +300 -241
  67. package/bundles/cdk-testing-protractor.umd.js.map +1 -1
  68. package/bundles/cdk-testing-protractor.umd.min.js +2 -9
  69. package/bundles/cdk-testing-protractor.umd.min.js.map +1 -1
  70. package/bundles/cdk-testing-testbed.umd.js +337 -276
  71. package/bundles/cdk-testing-testbed.umd.js.map +1 -1
  72. package/bundles/cdk-testing-testbed.umd.min.js +7 -30
  73. package/bundles/cdk-testing-testbed.umd.min.js.map +1 -1
  74. package/bundles/cdk-testing.umd.js +358 -270
  75. package/bundles/cdk-testing.umd.js.map +1 -1
  76. package/bundles/cdk-testing.umd.min.js +3 -18
  77. package/bundles/cdk-testing.umd.min.js.map +1 -1
  78. package/bundles/cdk-text-field.umd.js +51 -51
  79. package/bundles/cdk-text-field.umd.js.map +1 -1
  80. package/bundles/cdk-text-field.umd.min.js +10 -2
  81. package/bundles/cdk-text-field.umd.min.js.map +1 -1
  82. package/bundles/cdk-tree.umd.js +449 -396
  83. package/bundles/cdk-tree.umd.js.map +1 -1
  84. package/bundles/cdk-tree.umd.min.js +28 -3
  85. package/bundles/cdk-tree.umd.min.js.map +1 -1
  86. package/bundles/cdk.umd.js +1 -1
  87. package/bundles/cdk.umd.js.map +1 -1
  88. package/bundles/cdk.umd.min.js +1 -1
  89. package/bundles/cdk.umd.min.js.map +1 -1
  90. package/drag-drop/clone-node.d.ts +9 -0
  91. package/drag-drop/directives/drag-handle.d.ts +8 -2
  92. package/drag-drop/directives/drag-placeholder.d.ts +7 -1
  93. package/drag-drop/directives/drag-preview.d.ts +7 -1
  94. package/drag-drop/directives/drag.d.ts +3 -7
  95. package/drag-drop/directives/drop-list-group.d.ts +7 -1
  96. package/drag-drop/directives/drop-list.d.ts +7 -1
  97. package/drag-drop/index.d.ts +2 -2
  98. package/drag-drop/index.metadata.json +1 -1
  99. package/drag-drop/parent-position-tracker.d.ts +1 -1
  100. package/esm2015/a11y/aria-describer/aria-describer.js +21 -7
  101. package/esm2015/a11y/focus-trap/configurable-focus-trap-factory.js +3 -3
  102. package/esm2015/a11y/focus-trap/focus-trap.js +1 -1
  103. package/esm2015/a11y/interactivity-checker/interactivity-checker.js +43 -30
  104. package/esm2015/a11y/key-manager/list-key-manager.js +27 -2
  105. package/esm2015/a11y/live-announcer/live-announcer.js +1 -1
  106. package/esm2015/accordion/accordion-item.js +7 -7
  107. package/esm2015/accordion/accordion.js +9 -2
  108. package/esm2015/accordion/index.js +2 -1
  109. package/esm2015/clipboard/pending-copy.js +7 -6
  110. package/esm2015/drag-drop/clone-node.js +54 -0
  111. package/esm2015/drag-drop/directives/drag-handle.js +12 -5
  112. package/esm2015/drag-drop/directives/drag-placeholder.js +10 -3
  113. package/esm2015/drag-drop/directives/drag-preview.js +10 -3
  114. package/esm2015/drag-drop/directives/drag.js +19 -15
  115. package/esm2015/drag-drop/directives/drop-list-group.js +9 -2
  116. package/esm2015/drag-drop/directives/drop-list.js +19 -8
  117. package/esm2015/drag-drop/drag-ref.js +2 -29
  118. package/esm2015/drag-drop/index.js +3 -2
  119. package/esm2015/layout/breakpoints-observer.js +1 -1
  120. package/esm2015/overlay/dispatchers/base-overlay-dispatcher.js +51 -0
  121. package/esm2015/overlay/dispatchers/index.js +10 -0
  122. package/esm2015/overlay/dispatchers/overlay-keyboard-dispatcher.js +79 -0
  123. package/esm2015/overlay/dispatchers/overlay-outside-click-dispatcher.js +94 -0
  124. package/esm2015/overlay/index.js +5 -4
  125. package/esm2015/overlay/overlay-config.js +5 -1
  126. package/esm2015/overlay/overlay-directives.js +34 -8
  127. package/esm2015/overlay/overlay-module.js +2 -2
  128. package/esm2015/overlay/overlay-ref.js +24 -2
  129. package/esm2015/overlay/overlay-reference.js +1 -1
  130. package/esm2015/overlay/overlay.js +10 -5
  131. package/esm2015/overlay/position/connected-position-strategy.js +1 -5
  132. package/esm2015/overlay/position/flexible-connected-position-strategy.js +3 -3
  133. package/esm2015/overlay/position/overlay-position-builder.js +1 -1
  134. package/esm2015/overlay/public-api.js +2 -2
  135. package/esm2015/portal/dom-portal-outlet.js +5 -2
  136. package/esm2015/scrolling/public-api.js +2 -1
  137. package/esm2015/scrolling/scrolling-module.js +4 -1
  138. package/esm2015/scrolling/viewport-ruler.js +24 -10
  139. package/esm2015/scrolling/virtual-for-of.js +26 -12
  140. package/esm2015/scrolling/virtual-scroll-repeater.js +8 -0
  141. package/esm2015/scrolling/virtual-scroll-viewport.js +2 -2
  142. package/esm2015/table/cell.js +18 -3
  143. package/esm2015/table/coalesced-style-scheduler.js +87 -0
  144. package/esm2015/table/public-api.js +2 -1
  145. package/esm2015/table/sticky-styler.js +79 -45
  146. package/esm2015/table/table.js +33 -12
  147. package/esm2015/testing/component-harness.js +19 -1
  148. package/esm2015/testing/harness-environment.js +7 -1
  149. package/esm2015/testing/testbed/fake-events/dispatch-events.js +5 -4
  150. package/esm2015/testing/testbed/fake-events/event-objects.js +10 -7
  151. package/esm2015/testing/testbed/fake-events/type-in-element.js +4 -4
  152. package/esm2015/testing/testbed/unit-test-element.js +20 -12
  153. package/esm2015/tree/control/nested-tree-control.js +7 -3
  154. package/esm2015/tree/tree.js +9 -23
  155. package/esm2015/version.js +1 -1
  156. package/fesm2015/a11y.js +88 -38
  157. package/fesm2015/a11y.js.map +1 -1
  158. package/fesm2015/accordion.js +13 -6
  159. package/fesm2015/accordion.js.map +1 -1
  160. package/fesm2015/cdk.js +1 -1
  161. package/fesm2015/cdk.js.map +1 -1
  162. package/fesm2015/clipboard.js +6 -5
  163. package/fesm2015/clipboard.js.map +1 -1
  164. package/fesm2015/drag-drop.js +669 -600
  165. package/fesm2015/drag-drop.js.map +1 -1
  166. package/fesm2015/overlay.js +215 -40
  167. package/fesm2015/overlay.js.map +1 -1
  168. package/fesm2015/portal.js +4 -1
  169. package/fesm2015/portal.js.map +1 -1
  170. package/fesm2015/scrolling.js +60 -21
  171. package/fesm2015/scrolling.js.map +1 -1
  172. package/fesm2015/table.js +214 -61
  173. package/fesm2015/table.js.map +1 -1
  174. package/fesm2015/testing/testbed.js +35 -23
  175. package/fesm2015/testing/testbed.js.map +1 -1
  176. package/fesm2015/testing.js +25 -1
  177. package/fesm2015/testing.js.map +1 -1
  178. package/fesm2015/tree.js +13 -23
  179. package/fesm2015/tree.js.map +1 -1
  180. package/overlay/dispatchers/base-overlay-dispatcher.d.ts +28 -0
  181. package/overlay/dispatchers/index.d.ts +9 -0
  182. package/overlay/{keyboard → dispatchers}/overlay-keyboard-dispatcher.d.ts +4 -10
  183. package/overlay/dispatchers/overlay-outside-click-dispatcher.d.ts +27 -0
  184. package/overlay/index.d.ts +4 -3
  185. package/overlay/index.metadata.json +1 -1
  186. package/overlay/overlay-config.d.ts +4 -0
  187. package/overlay/overlay-directives.d.ts +5 -0
  188. package/overlay/overlay-ref.d.ts +8 -2
  189. package/overlay/overlay-reference.d.ts +1 -0
  190. package/overlay/overlay.d.ts +4 -2
  191. package/overlay/position/connected-position-strategy.d.ts +0 -2
  192. package/overlay/public-api.d.ts +1 -1
  193. package/package.json +1 -1
  194. package/schematics/ng-add/index.js +1 -1
  195. package/scrolling/index.metadata.json +1 -1
  196. package/scrolling/public-api.d.ts +1 -0
  197. package/scrolling/scrolling-module.d.ts +3 -0
  198. package/scrolling/viewport-ruler.d.ts +2 -2
  199. package/scrolling/virtual-for-of.d.ts +2 -1
  200. package/scrolling/virtual-scroll-repeater.d.ts +16 -0
  201. package/scrolling/virtual-scroll-viewport.d.ts +4 -4
  202. package/table/cell.d.ts +13 -0
  203. package/table/coalesced-style-scheduler.d.ts +41 -0
  204. package/table/index.metadata.json +1 -1
  205. package/table/public-api.d.ts +1 -0
  206. package/table/sticky-styler.d.ts +7 -1
  207. package/table/table.d.ts +9 -1
  208. package/testing/component-harness.d.ts +12 -0
  209. package/testing/harness-environment.d.ts +1 -0
  210. package/testing/testbed/fake-events/dispatch-events.d.ts +3 -2
  211. package/testing/testbed/fake-events/event-objects.d.ts +2 -2
  212. package/testing/testbed/unit-test-element.d.ts +7 -0
  213. package/tree/control/nested-tree-control.d.ts +7 -2
  214. package/tree/index.metadata.json +1 -1
  215. package/tree/tree.d.ts +2 -4
  216. package/esm2015/overlay/keyboard/overlay-keyboard-dispatcher.js +0 -96
package/fesm2015/table.js CHANGED
@@ -4,9 +4,9 @@ import { isDataSource } from '@angular/cdk/collections';
4
4
  export { DataSource } from '@angular/cdk/collections';
5
5
  import { Platform } from '@angular/cdk/platform';
6
6
  import { DOCUMENT } from '@angular/common';
7
- import { InjectionToken, Directive, TemplateRef, Inject, Optional, Input, ContentChild, ElementRef, IterableDiffers, ViewContainerRef, Component, ChangeDetectionStrategy, ViewEncapsulation, EmbeddedViewRef, isDevMode, ChangeDetectorRef, Attribute, ViewChild, ContentChildren, NgModule } from '@angular/core';
8
- import { Subject, BehaviorSubject, isObservable, of } from 'rxjs';
9
- import { takeUntil } from 'rxjs/operators';
7
+ import { InjectionToken, Directive, TemplateRef, Inject, Optional, Input, ContentChild, ElementRef, Injectable, NgZone, IterableDiffers, ViewContainerRef, Component, ChangeDetectionStrategy, ViewEncapsulation, EmbeddedViewRef, isDevMode, ChangeDetectorRef, Attribute, ViewChild, ContentChildren, NgModule } from '@angular/core';
8
+ import { Subject, from, BehaviorSubject, isObservable, of } from 'rxjs';
9
+ import { takeUntil, take } from 'rxjs/operators';
10
10
 
11
11
  /**
12
12
  * @license
@@ -141,6 +141,7 @@ class CdkColumnDef extends _CdkColumnDefBase {
141
141
  if (name) {
142
142
  this._name = name;
143
143
  this.cssClassFriendlyName = name.replace(/[^a-z0-9_-]/ig, '-');
144
+ this._updateColumnCssClassName();
144
145
  }
145
146
  }
146
147
  /**
@@ -156,6 +157,16 @@ class CdkColumnDef extends _CdkColumnDefBase {
156
157
  this._stickyEnd = coerceBooleanProperty(v);
157
158
  this._hasStickyChanged = prevValue !== this._stickyEnd;
158
159
  }
160
+ /**
161
+ * Overridable method that sets the css classes that will be added to every cell in this
162
+ * column.
163
+ * In the future, columnCssClassName will change from type string[] to string and this
164
+ * will set a single string value.
165
+ * @docs-private
166
+ */
167
+ _updateColumnCssClassName() {
168
+ this._columnCssClassName = [`cdk-column-${this.cssClassFriendlyName}`];
169
+ }
159
170
  }
160
171
  CdkColumnDef.decorators = [
161
172
  { type: Directive, args: [{
@@ -177,8 +188,12 @@ CdkColumnDef.propDecorators = {
177
188
  /** Base class for the cells. Adds a CSS classname that identifies the column it renders in. */
178
189
  class BaseCdkCell {
179
190
  constructor(columnDef, elementRef) {
180
- const columnClassName = `cdk-column-${columnDef.cssClassFriendlyName}`;
181
- elementRef.nativeElement.classList.add(columnClassName);
191
+ // If IE 11 is dropped before we switch to setting a single class name, change to multi param
192
+ // with destructuring.
193
+ const classList = elementRef.nativeElement.classList;
194
+ for (const className of columnDef._columnCssClassName) {
195
+ classList.add(className);
196
+ }
182
197
  }
183
198
  }
184
199
  /** Header cell template container that adds the right classes and role. */
@@ -239,6 +254,90 @@ CdkCell.ctorParameters = () => [
239
254
  { type: ElementRef }
240
255
  ];
241
256
 
257
+ /**
258
+ * @license
259
+ * Copyright Google LLC All Rights Reserved.
260
+ *
261
+ * Use of this source code is governed by an MIT-style license that can be
262
+ * found in the LICENSE file at https://angular.io/license
263
+ */
264
+ /**
265
+ * @docs-private
266
+ */
267
+ class _Schedule {
268
+ constructor() {
269
+ this.tasks = [];
270
+ this.endTasks = [];
271
+ }
272
+ }
273
+ /**
274
+ * Allows grouping up CSSDom mutations after the current execution context.
275
+ * This can significantly improve performance when separate consecutive functions are
276
+ * reading from the CSSDom and then mutating it.
277
+ *
278
+ * @docs-private
279
+ */
280
+ class _CoalescedStyleScheduler {
281
+ constructor(_ngZone) {
282
+ this._ngZone = _ngZone;
283
+ this._currentSchedule = null;
284
+ this._destroyed = new Subject();
285
+ }
286
+ /**
287
+ * Schedules the specified task to run at the end of the current VM turn.
288
+ */
289
+ schedule(task) {
290
+ this._createScheduleIfNeeded();
291
+ this._currentSchedule.tasks.push(task);
292
+ }
293
+ /**
294
+ * Schedules the specified task to run after other scheduled tasks at the end of the current
295
+ * VM turn.
296
+ */
297
+ scheduleEnd(task) {
298
+ this._createScheduleIfNeeded();
299
+ this._currentSchedule.endTasks.push(task);
300
+ }
301
+ /** Prevent any further tasks from running. */
302
+ ngOnDestroy() {
303
+ this._destroyed.next();
304
+ this._destroyed.complete();
305
+ }
306
+ _createScheduleIfNeeded() {
307
+ if (this._currentSchedule) {
308
+ return;
309
+ }
310
+ this._currentSchedule = new _Schedule();
311
+ this._getScheduleObservable().pipe(takeUntil(this._destroyed)).subscribe(() => {
312
+ while (this._currentSchedule.tasks.length || this._currentSchedule.endTasks.length) {
313
+ const schedule = this._currentSchedule;
314
+ // Capture new tasks scheduled by the current set of tasks.
315
+ this._currentSchedule = new _Schedule();
316
+ for (const task of schedule.tasks) {
317
+ task();
318
+ }
319
+ for (const task of schedule.endTasks) {
320
+ task();
321
+ }
322
+ }
323
+ this._currentSchedule = null;
324
+ });
325
+ }
326
+ _getScheduleObservable() {
327
+ // Use onStable when in the context of an ongoing change detection cycle so that we
328
+ // do not accidentally trigger additional cycles.
329
+ return this._ngZone.isStable ?
330
+ from(Promise.resolve(undefined)) :
331
+ this._ngZone.onStable.pipe(take(1));
332
+ }
333
+ }
334
+ _CoalescedStyleScheduler.decorators = [
335
+ { type: Injectable }
336
+ ];
337
+ _CoalescedStyleScheduler.ctorParameters = () => [
338
+ { type: NgZone }
339
+ ];
340
+
242
341
  /**
243
342
  * @license
244
343
  * Copyright Google LLC All Rights Reserved.
@@ -505,12 +604,17 @@ class StickyStyler {
505
604
  * @param direction The directionality context of the table (ltr/rtl); affects column positioning
506
605
  * by reversing left/right positions.
507
606
  * @param _isBrowser Whether the table is currently being rendered on the server or the client.
607
+ * @param _needsPositionStickyOnElement Whether we need to specify position: sticky on cells
608
+ * using inline styles. If false, it is assumed that position: sticky is included in
609
+ * the component stylesheet for _stickCellCss.
508
610
  */
509
- constructor(_isNativeHtmlTable, _stickCellCss, direction, _isBrowser = true) {
611
+ constructor(_isNativeHtmlTable, _stickCellCss, direction, _coalescedStyleScheduler, _isBrowser = true, _needsPositionStickyOnElement = true) {
510
612
  this._isNativeHtmlTable = _isNativeHtmlTable;
511
613
  this._stickCellCss = _stickCellCss;
512
614
  this.direction = direction;
615
+ this._coalescedStyleScheduler = _coalescedStyleScheduler;
513
616
  this._isBrowser = _isBrowser;
617
+ this._needsPositionStickyOnElement = _needsPositionStickyOnElement;
514
618
  }
515
619
  /**
516
620
  * Clears the sticky positioning styles from the row and its cells by resetting the `position`
@@ -519,18 +623,24 @@ class StickyStyler {
519
623
  * @param stickyDirections The directions that should no longer be set as sticky on the rows.
520
624
  */
521
625
  clearStickyPositioning(rows, stickyDirections) {
626
+ const elementsToClear = [];
522
627
  for (const row of rows) {
523
628
  // If the row isn't an element (e.g. if it's an `ng-container`),
524
629
  // it won't have inline styles or `children` so we skip it.
525
630
  if (row.nodeType !== row.ELEMENT_NODE) {
526
631
  continue;
527
632
  }
528
- this._removeStickyStyle(row, stickyDirections);
633
+ elementsToClear.push(row);
529
634
  for (let i = 0; i < row.children.length; i++) {
530
- const cell = row.children[i];
531
- this._removeStickyStyle(cell, stickyDirections);
635
+ elementsToClear.push(row.children[i]);
532
636
  }
533
637
  }
638
+ // Coalesce with sticky row/column updates (and potentially other changes like column resize).
639
+ this._coalescedStyleScheduler.schedule(() => {
640
+ for (const element of elementsToClear) {
641
+ this._removeStickyStyle(element, stickyDirections);
642
+ }
643
+ });
534
644
  }
535
645
  /**
536
646
  * Applies sticky left and right positions to the cells of each row according to the sticky
@@ -542,8 +652,8 @@ class StickyStyler {
542
652
  * in this index position should be stuck to the end of the row.
543
653
  */
544
654
  updateStickyColumns(rows, stickyStartStates, stickyEndStates) {
545
- const hasStickyColumns = stickyStartStates.some(state => state) || stickyEndStates.some(state => state);
546
- if (!rows.length || !hasStickyColumns || !this._isBrowser) {
655
+ if (!rows.length || !this._isBrowser || !(stickyStartStates.some(state => state) ||
656
+ stickyEndStates.some(state => state))) {
547
657
  return;
548
658
  }
549
659
  const firstRow = rows[0];
@@ -551,18 +661,23 @@ class StickyStyler {
551
661
  const cellWidths = this._getCellWidths(firstRow);
552
662
  const startPositions = this._getStickyStartColumnPositions(cellWidths, stickyStartStates);
553
663
  const endPositions = this._getStickyEndColumnPositions(cellWidths, stickyEndStates);
554
- const isRtl = this.direction === 'rtl';
555
- for (const row of rows) {
556
- for (let i = 0; i < numCells; i++) {
557
- const cell = row.children[i];
558
- if (stickyStartStates[i]) {
559
- this._addStickyStyle(cell, isRtl ? 'right' : 'left', startPositions[i]);
560
- }
561
- if (stickyEndStates[i]) {
562
- this._addStickyStyle(cell, isRtl ? 'left' : 'right', endPositions[i]);
664
+ // Coalesce with sticky row updates (and potentially other changes like column resize).
665
+ this._coalescedStyleScheduler.schedule(() => {
666
+ const isRtl = this.direction === 'rtl';
667
+ const start = isRtl ? 'right' : 'left';
668
+ const end = isRtl ? 'left' : 'right';
669
+ for (const row of rows) {
670
+ for (let i = 0; i < numCells; i++) {
671
+ const cell = row.children[i];
672
+ if (stickyStartStates[i]) {
673
+ this._addStickyStyle(cell, start, startPositions[i]);
674
+ }
675
+ if (stickyEndStates[i]) {
676
+ this._addStickyStyle(cell, end, endPositions[i]);
677
+ }
563
678
  }
564
679
  }
565
- }
680
+ });
566
681
  }
567
682
  /**
568
683
  * Applies sticky positioning to the row's cells if using the native table layout, and to the
@@ -585,29 +700,34 @@ class StickyStyler {
585
700
  // sticky states need to be reversed as well.
586
701
  const rows = position === 'bottom' ? rowsToStick.slice().reverse() : rowsToStick;
587
702
  const states = position === 'bottom' ? stickyStates.slice().reverse() : stickyStates;
588
- let stickyHeight = 0;
589
- for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
703
+ // Measure row heights all at once before adding sticky styles to reduce layout thrashing.
704
+ const stickyHeights = [];
705
+ const elementsToStick = [];
706
+ for (let rowIndex = 0, stickyHeight = 0; rowIndex < rows.length; rowIndex++) {
707
+ stickyHeights[rowIndex] = stickyHeight;
590
708
  if (!states[rowIndex]) {
591
709
  continue;
592
710
  }
593
711
  const row = rows[rowIndex];
594
- if (this._isNativeHtmlTable) {
595
- for (let j = 0; j < row.children.length; j++) {
596
- const cell = row.children[j];
597
- this._addStickyStyle(cell, position, stickyHeight);
598
- }
712
+ elementsToStick[rowIndex] = this._isNativeHtmlTable ?
713
+ Array.from(row.children) : [row];
714
+ if (rowIndex !== rows.length - 1) {
715
+ stickyHeight += row.getBoundingClientRect().height;
599
716
  }
600
- else {
601
- // Flex does not respect the stick positioning on the cells, needs to be applied to the row.
602
- // If this is applied on a native table, Safari causes the header to fly in wrong direction.
603
- this._addStickyStyle(row, position, stickyHeight);
604
- }
605
- if (rowIndex === rows.length - 1) {
606
- // prevent unnecessary reflow from getBoundingClientRect()
607
- return;
608
- }
609
- stickyHeight += row.getBoundingClientRect().height;
610
717
  }
718
+ // Coalesce with other sticky row updates (top/bottom), sticky columns updates
719
+ // (and potentially other changes like column resize).
720
+ this._coalescedStyleScheduler.schedule(() => {
721
+ for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
722
+ if (!states[rowIndex]) {
723
+ continue;
724
+ }
725
+ const height = stickyHeights[rowIndex];
726
+ for (const element of elementsToStick[rowIndex]) {
727
+ this._addStickyStyle(element, position, height);
728
+ }
729
+ }
730
+ });
611
731
  }
612
732
  /**
613
733
  * When using the native table in Safari, sticky footer cells do not stick. The only way to stick
@@ -620,12 +740,15 @@ class StickyStyler {
620
740
  return;
621
741
  }
622
742
  const tfoot = tableElement.querySelector('tfoot');
623
- if (stickyStates.some(state => !state)) {
624
- this._removeStickyStyle(tfoot, ['bottom']);
625
- }
626
- else {
627
- this._addStickyStyle(tfoot, 'bottom', 0);
628
- }
743
+ // Coalesce with other sticky updates (and potentially other changes like column resize).
744
+ this._coalescedStyleScheduler.schedule(() => {
745
+ if (stickyStates.some(state => !state)) {
746
+ this._removeStickyStyle(tfoot, ['bottom']);
747
+ }
748
+ else {
749
+ this._addStickyStyle(tfoot, 'bottom', 0);
750
+ }
751
+ });
629
752
  }
630
753
  /**
631
754
  * Removes the sticky style on the element by removing the sticky cell CSS class, re-evaluating
@@ -636,12 +759,20 @@ class StickyStyler {
636
759
  for (const dir of stickyDirections) {
637
760
  element.style[dir] = '';
638
761
  }
639
- element.style.zIndex = this._getCalculatedZIndex(element);
640
762
  // If the element no longer has any more sticky directions, remove sticky positioning and
641
763
  // the sticky CSS class.
642
- const hasDirection = STICKY_DIRECTIONS.some(dir => !!element.style[dir]);
643
- if (!hasDirection) {
644
- element.style.position = '';
764
+ // Short-circuit checking element.style[dir] for stickyDirections as they
765
+ // were already removed above.
766
+ const hasDirection = STICKY_DIRECTIONS.some(dir => stickyDirections.indexOf(dir) === -1 && element.style[dir]);
767
+ if (hasDirection) {
768
+ element.style.zIndex = this._getCalculatedZIndex(element);
769
+ }
770
+ else {
771
+ // When not hasDirection, _getCalculatedZIndex will always return ''.
772
+ element.style.zIndex = '';
773
+ if (this._needsPositionStickyOnElement) {
774
+ element.style.position = '';
775
+ }
645
776
  element.classList.remove(this._stickCellCss);
646
777
  }
647
778
  }
@@ -653,8 +784,10 @@ class StickyStyler {
653
784
  _addStickyStyle(element, dir, dirValue) {
654
785
  element.classList.add(this._stickCellCss);
655
786
  element.style[dir] = `${dirValue}px`;
656
- element.style.cssText += 'position: -webkit-sticky; position: sticky; ';
657
787
  element.style.zIndex = this._getCalculatedZIndex(element);
788
+ if (this._needsPositionStickyOnElement) {
789
+ element.style.cssText += 'position: -webkit-sticky; position: sticky; ';
790
+ }
658
791
  }
659
792
  /**
660
793
  * Calculate what the z-index should be for the element, depending on what directions (top,
@@ -901,9 +1034,10 @@ class RowViewRef extends EmbeddedViewRef {
901
1034
  * connect function that will return an Observable stream that emits the data array to render.
902
1035
  */
903
1036
  class CdkTable {
904
- constructor(_differs, _changeDetectorRef, _elementRef, role, _dir, _document, _platform) {
1037
+ constructor(_differs, _changeDetectorRef, _coalescedStyleScheduler, _elementRef, role, _dir, _document, _platform) {
905
1038
  this._differs = _differs;
906
1039
  this._changeDetectorRef = _changeDetectorRef;
1040
+ this._coalescedStyleScheduler = _coalescedStyleScheduler;
907
1041
  this._elementRef = _elementRef;
908
1042
  this._dir = _dir;
909
1043
  this._platform = _platform;
@@ -968,6 +1102,12 @@ class CdkTable {
968
1102
  * table subclasses.
969
1103
  */
970
1104
  this.stickyCssClass = 'cdk-table-sticky';
1105
+ /**
1106
+ * Whether to manually add positon: sticky to all sticky cell elements. Not needed if
1107
+ * the position is set in a selector associated with the value of stickyCssClass. May be
1108
+ * overridden by table subclasses
1109
+ */
1110
+ this.needsPositionStickyOnElement = true;
971
1111
  /** Whether the no data row is currently showing anything. */
972
1112
  this._isShowingNoDataRow = false;
973
1113
  this._multiTemplateDataRows = false;
@@ -1045,6 +1185,7 @@ class CdkTable {
1045
1185
  // this setter will be invoked before the row outlet has been defined hence the null check.
1046
1186
  if (this._rowOutlet && this._rowOutlet.viewContainer.length) {
1047
1187
  this._forceRenderDataRows();
1188
+ this.updateStickyColumnStyles();
1048
1189
  }
1049
1190
  }
1050
1191
  ngOnInit() {
@@ -1068,7 +1209,8 @@ class CdkTable {
1068
1209
  throw getTableMissingRowDefsError();
1069
1210
  }
1070
1211
  // Render updates if the list of columns have been changed for the header, row, or footer defs.
1071
- this._renderUpdatedColumns();
1212
+ const columnsChanged = this._renderUpdatedColumns();
1213
+ const stickyColumnStyleUpdateNeeded = columnsChanged || this._headerRowDefChanged || this._footerRowDefChanged;
1072
1214
  // If the header row definition has been changed, trigger a render to the header row.
1073
1215
  if (this._headerRowDefChanged) {
1074
1216
  this._forceRenderHeaderRows();
@@ -1084,6 +1226,11 @@ class CdkTable {
1084
1226
  if (this.dataSource && this._rowDefs.length > 0 && !this._renderChangeSubscription) {
1085
1227
  this._observeRenderChanges();
1086
1228
  }
1229
+ else if (stickyColumnStyleUpdateNeeded) {
1230
+ // In the above case, _observeRenderChanges will result in updateStickyColumnStyles being
1231
+ // called when it row data arrives. Otherwise, we need to call it proactively.
1232
+ this.updateStickyColumnStyles();
1233
+ }
1087
1234
  this._checkStickyStates();
1088
1235
  }
1089
1236
  ngOnDestroy() {
@@ -1112,6 +1259,7 @@ class CdkTable {
1112
1259
  this._renderRows = this._getAllRenderRows();
1113
1260
  const changes = this._dataDiffer.diff(this._renderRows);
1114
1261
  if (!changes) {
1262
+ this._updateNoDataRow();
1115
1263
  return;
1116
1264
  }
1117
1265
  const viewContainer = this._rowOutlet.viewContainer;
@@ -1340,16 +1488,20 @@ class CdkTable {
1340
1488
  _renderUpdatedColumns() {
1341
1489
  const columnsDiffReducer = (acc, def) => acc || !!def.getColumnsDiff();
1342
1490
  // Force re-render data rows if the list of column definitions have changed.
1343
- if (this._rowDefs.reduce(columnsDiffReducer, false)) {
1491
+ const dataColumnsChanged = this._rowDefs.reduce(columnsDiffReducer, false);
1492
+ if (dataColumnsChanged) {
1344
1493
  this._forceRenderDataRows();
1345
1494
  }
1346
- // Force re-render header/footer rows if the list of column definitions have changed..
1347
- if (this._headerRowDefs.reduce(columnsDiffReducer, false)) {
1495
+ // Force re-render header/footer rows if the list of column definitions have changed.
1496
+ const headerColumnsChanged = this._headerRowDefs.reduce(columnsDiffReducer, false);
1497
+ if (headerColumnsChanged) {
1348
1498
  this._forceRenderHeaderRows();
1349
1499
  }
1350
- if (this._footerRowDefs.reduce(columnsDiffReducer, false)) {
1500
+ const footerColumnsChanged = this._footerRowDefs.reduce(columnsDiffReducer, false);
1501
+ if (footerColumnsChanged) {
1351
1502
  this._forceRenderFooterRows();
1352
1503
  }
1504
+ return dataColumnsChanged || headerColumnsChanged || footerColumnsChanged;
1353
1505
  }
1354
1506
  /**
1355
1507
  * Switch to the provided data source by resetting the data and unsubscribing from the current
@@ -1409,7 +1561,6 @@ class CdkTable {
1409
1561
  }
1410
1562
  this._headerRowDefs.forEach((def, i) => this._renderRow(this._headerRowOutlet, def, i));
1411
1563
  this.updateStickyHeaderRowStyles();
1412
- this.updateStickyColumnStyles();
1413
1564
  }
1414
1565
  /**
1415
1566
  * Clears any existing content in the footer row outlet and creates a new embedded view
@@ -1422,7 +1573,6 @@ class CdkTable {
1422
1573
  }
1423
1574
  this._footerRowDefs.forEach((def, i) => this._renderRow(this._footerRowOutlet, def, i));
1424
1575
  this.updateStickyFooterRowStyles();
1425
- this.updateStickyColumnStyles();
1426
1576
  }
1427
1577
  /** Adds the sticky column styles for the rows according to the columns' stick states. */
1428
1578
  _addStickyColumnStyles(rows, rowDef) {
@@ -1559,7 +1709,6 @@ class CdkTable {
1559
1709
  this._dataDiffer.diff([]);
1560
1710
  this._rowOutlet.viewContainer.clear();
1561
1711
  this.renderRows();
1562
- this.updateStickyColumnStyles();
1563
1712
  }
1564
1713
  /**
1565
1714
  * Checks if there has been a change in sticky states since last check and applies the correct
@@ -1590,7 +1739,7 @@ class CdkTable {
1590
1739
  */
1591
1740
  _setupStickyStyler() {
1592
1741
  const direction = this._dir ? this._dir.value : 'ltr';
1593
- this._stickyStyler = new StickyStyler(this._isNativeHtmlTable, this.stickyCssClass, direction, this._platform.isBrowser);
1742
+ this._stickyStyler = new StickyStyler(this._isNativeHtmlTable, this.stickyCssClass, direction, this._coalescedStyleScheduler, this._platform.isBrowser, this.needsPositionStickyOnElement);
1594
1743
  (this._dir ? this._dir.change : of())
1595
1744
  .pipe(takeUntil(this._onDestroy))
1596
1745
  .subscribe(value => {
@@ -1628,12 +1777,16 @@ CdkTable.decorators = [
1628
1777
  // declared elsewhere, they are checked when their declaration points are checked.
1629
1778
  // tslint:disable-next-line:validate-decorators
1630
1779
  changeDetection: ChangeDetectionStrategy.Default,
1631
- providers: [{ provide: CDK_TABLE, useExisting: CdkTable }]
1780
+ providers: [
1781
+ { provide: CDK_TABLE, useExisting: CdkTable },
1782
+ _CoalescedStyleScheduler,
1783
+ ]
1632
1784
  },] }
1633
1785
  ];
1634
1786
  CdkTable.ctorParameters = () => [
1635
1787
  { type: IterableDiffers },
1636
1788
  { type: ChangeDetectorRef },
1789
+ { type: _CoalescedStyleScheduler },
1637
1790
  { type: ElementRef },
1638
1791
  { type: String, decorators: [{ type: Attribute, args: ['role',] }] },
1639
1792
  { type: Directionality, decorators: [{ type: Optional }] },
@@ -1832,5 +1985,5 @@ CdkTableModule.decorators = [
1832
1985
  * Generated bundle index. Do not edit.
1833
1986
  */
1834
1987
 
1835
- export { BaseCdkCell, BaseRowDef, CDK_ROW_TEMPLATE, CDK_TABLE, CDK_TABLE_TEMPLATE, CdkCell, CdkCellDef, CdkCellOutlet, CdkColumnDef, CdkFooterCell, CdkFooterCellDef, CdkFooterRow, CdkFooterRowDef, CdkHeaderCell, CdkHeaderCellDef, CdkHeaderRow, CdkHeaderRowDef, CdkNoDataRow, CdkRow, CdkRowDef, CdkTable, CdkTableModule, CdkTextColumn, DataRowOutlet, FooterRowOutlet, HeaderRowOutlet, NoDataRowOutlet, STICKY_DIRECTIONS, StickyStyler, TEXT_COLUMN_OPTIONS, mixinHasStickyInput };
1988
+ export { BaseCdkCell, BaseRowDef, CDK_ROW_TEMPLATE, CDK_TABLE, CDK_TABLE_TEMPLATE, CdkCell, CdkCellDef, CdkCellOutlet, CdkColumnDef, CdkFooterCell, CdkFooterCellDef, CdkFooterRow, CdkFooterRowDef, CdkHeaderCell, CdkHeaderCellDef, CdkHeaderRow, CdkHeaderRowDef, CdkNoDataRow, CdkRow, CdkRowDef, CdkTable, CdkTableModule, CdkTextColumn, DataRowOutlet, FooterRowOutlet, HeaderRowOutlet, NoDataRowOutlet, STICKY_DIRECTIONS, StickyStyler, TEXT_COLUMN_OPTIONS, _CoalescedStyleScheduler, _Schedule, mixinHasStickyInput };
1836
1989
  //# sourceMappingURL=table.js.map