@vaadin/grid 24.0.0-alpha1 → 24.0.0-alpha11

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 (63) hide show
  1. package/all-imports.d.ts +10 -0
  2. package/all-imports.js +11 -0
  3. package/package.json +11 -10
  4. package/src/all-imports.js +1 -1
  5. package/src/array-data-provider.js +1 -1
  6. package/src/lit/column-renderer-directives.d.ts +1 -1
  7. package/src/lit/column-renderer-directives.js +1 -1
  8. package/src/lit/renderer-directives.d.ts +1 -1
  9. package/src/lit/renderer-directives.js +1 -1
  10. package/src/vaadin-grid-a11y-mixin.js +12 -9
  11. package/src/vaadin-grid-active-item-mixin.d.ts +1 -1
  12. package/src/vaadin-grid-active-item-mixin.js +10 -5
  13. package/src/vaadin-grid-array-data-provider-mixin.d.ts +1 -1
  14. package/src/vaadin-grid-array-data-provider-mixin.js +1 -1
  15. package/src/vaadin-grid-column-group.d.ts +1 -1
  16. package/src/vaadin-grid-column-group.js +17 -17
  17. package/src/vaadin-grid-column-reordering-mixin.d.ts +1 -1
  18. package/src/vaadin-grid-column-reordering-mixin.js +8 -10
  19. package/src/vaadin-grid-column-resizing-mixin.js +6 -5
  20. package/src/vaadin-grid-column.d.ts +1 -1
  21. package/src/vaadin-grid-column.js +54 -40
  22. package/src/vaadin-grid-data-provider-mixin.d.ts +1 -1
  23. package/src/vaadin-grid-data-provider-mixin.js +34 -7
  24. package/src/vaadin-grid-drag-and-drop-mixin.d.ts +1 -1
  25. package/src/vaadin-grid-drag-and-drop-mixin.js +23 -18
  26. package/src/vaadin-grid-dynamic-columns-mixin.js +5 -4
  27. package/src/vaadin-grid-event-context-mixin.d.ts +1 -1
  28. package/src/vaadin-grid-event-context-mixin.js +1 -1
  29. package/src/vaadin-grid-filter-column.d.ts +1 -1
  30. package/src/vaadin-grid-filter-column.js +1 -2
  31. package/src/vaadin-grid-filter-mixin.js +1 -1
  32. package/src/vaadin-grid-filter.d.ts +3 -2
  33. package/src/vaadin-grid-filter.js +27 -22
  34. package/src/vaadin-grid-helpers.js +104 -1
  35. package/src/vaadin-grid-keyboard-navigation-mixin.js +48 -35
  36. package/src/vaadin-grid-row-details-mixin.d.ts +2 -6
  37. package/src/vaadin-grid-row-details-mixin.js +5 -4
  38. package/src/vaadin-grid-scroll-mixin.d.ts +1 -1
  39. package/src/vaadin-grid-scroll-mixin.js +18 -10
  40. package/src/vaadin-grid-selection-column.d.ts +1 -1
  41. package/src/vaadin-grid-selection-column.js +1 -1
  42. package/src/vaadin-grid-selection-mixin.d.ts +1 -1
  43. package/src/vaadin-grid-selection-mixin.js +1 -1
  44. package/src/vaadin-grid-sort-column.d.ts +1 -1
  45. package/src/vaadin-grid-sort-column.js +1 -1
  46. package/src/vaadin-grid-sort-mixin.d.ts +10 -1
  47. package/src/vaadin-grid-sort-mixin.js +22 -6
  48. package/src/vaadin-grid-sorter.d.ts +7 -2
  49. package/src/vaadin-grid-sorter.js +18 -2
  50. package/src/vaadin-grid-styles.js +5 -1
  51. package/src/vaadin-grid-styling-mixin.d.ts +38 -2
  52. package/src/vaadin-grid-styling-mixin.js +78 -6
  53. package/src/vaadin-grid-tree-column.d.ts +1 -8
  54. package/src/vaadin-grid-tree-column.js +2 -25
  55. package/src/vaadin-grid-tree-toggle.d.ts +1 -1
  56. package/src/vaadin-grid-tree-toggle.js +2 -2
  57. package/src/vaadin-grid.d.ts +100 -50
  58. package/src/vaadin-grid.js +198 -105
  59. package/theme/lumo/vaadin-grid-styles.js +14 -14
  60. package/theme/lumo/vaadin-grid.js +0 -7
  61. package/theme/material/vaadin-grid-styles.js +1 -1
  62. package/web-types.json +33 -26
  63. package/web-types.lit.json +18 -11
@@ -1,14 +1,16 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import './vaadin-grid-column.js';
7
7
  import './vaadin-grid-styles.js';
8
8
  import { beforeNextRender } from '@polymer/polymer/lib/utils/render-status.js';
9
9
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
10
+ import { microTask } from '@vaadin/component-base/src/async.js';
10
11
  import { isAndroid, isChrome, isFirefox, isIOS, isSafari, isTouch } from '@vaadin/component-base/src/browser-utils.js';
11
12
  import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
13
+ import { Debouncer } from '@vaadin/component-base/src/debounce.js';
12
14
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
13
15
  import { TabindexMixin } from '@vaadin/component-base/src/tabindex-mixin.js';
14
16
  import { processTemplates } from '@vaadin/component-base/src/templates.js';
@@ -25,6 +27,7 @@ import { DragAndDropMixin } from './vaadin-grid-drag-and-drop-mixin.js';
25
27
  import { DynamicColumnsMixin } from './vaadin-grid-dynamic-columns-mixin.js';
26
28
  import { EventContextMixin } from './vaadin-grid-event-context-mixin.js';
27
29
  import { FilterMixin } from './vaadin-grid-filter-mixin.js';
30
+ import { getBodyRowCells, iterateChildren, updateCellsPart, updateRowStates } from './vaadin-grid-helpers.js';
28
31
  import { KeyboardNavigationMixin } from './vaadin-grid-keyboard-navigation-mixin.js';
29
32
  import { RowDetailsMixin } from './vaadin-grid-row-details-mixin.js';
30
33
  import { ScrollMixin } from './vaadin-grid-scroll-mixin.js';
@@ -172,45 +175,86 @@ import { StylingMixin } from './vaadin-grid-styling-mixin.js';
172
175
  *
173
176
  * The following shadow DOM parts are available for styling:
174
177
  *
175
- * Part name | Description
176
- * ----------------|----------------
177
- * `row` | Row in the internal table
178
- * `cell` | Cell in the internal table
179
- * `header-cell` | Header cell in the internal table
180
- * `body-cell` | Body cell in the internal table
181
- * `footer-cell` | Footer cell in the internal table
182
- * `details-cell` | Row details cell in the internal table
183
- * `focused-cell` | Focused cell in the internal table
184
- * `resize-handle` | Handle for resizing the columns
185
- * `reorder-ghost` | Ghost element of the header cell being dragged
178
+ * Part name | Description
179
+ * ---------------------------|----------------
180
+ * `row` | Row in the internal table
181
+ * `expanded-row` | Expanded row
182
+ * `selected-row` | Selected row
183
+ * `details-opened-row` | Row with details open
184
+ * `odd-row` | Odd row
185
+ * `even-row` | Even row
186
+ * `first-row` | The first body row
187
+ * `last-row` | The last body row
188
+ * `dragstart-row` | Set on the row for one frame when drag is starting.
189
+ * `dragover-above-row` | Set on the row when the a row is dragged over above
190
+ * `dragover-below-row` | Set on the row when the a row is dragged over below
191
+ * `dragover-on-top-row` | Set on the row when the a row is dragged over on top
192
+ * `drag-disabled-row` | Set to a row that isn't available for dragging
193
+ * `drop-disabled-row` | Set to a row that can't be dropped on top of
194
+ * `cell` | Cell in the internal table
195
+ * `header-cell` | Header cell in the internal table
196
+ * `body-cell` | Body cell in the internal table
197
+ * `footer-cell` | Footer cell in the internal table
198
+ * `details-cell` | Row details cell in the internal table
199
+ * `focused-cell` | Focused cell in the internal table
200
+ * `odd-row-cell` | Cell in an odd row
201
+ * `even-row-cell` | Cell in an even row
202
+ * `first-row-cell` | Cell in the first body row
203
+ * `last-row-cell` | Cell in the last body row
204
+ * `first-header-row-cell` | Cell in the first header row
205
+ * `first-footer-row-cell` | Cell in the first footer row
206
+ * `last-header-row-cell` | Cell in the last header row
207
+ * `last-footer-row-cell` | Cell in the last footer row
208
+ * `loading-row-cell` | Cell in a row that is waiting for data from data provider
209
+ * `selected-row-cell` | Cell in a selected row
210
+ * `expanded-row-cell` | Cell in an expanded row
211
+ * `details-opened-row-cell` | Cell in an row with details open
212
+ * `dragstart-row-cell` | Cell in a row that user started to drag (set for one frame)
213
+ * `dragover-above-row-cell` | Cell in a row that has another row dragged over above
214
+ * `dragover-below-row-cell` | Cell in a row that has another row dragged over below
215
+ * `dragover-on-top-row-cell` | Cell in a row that has another row dragged over on top
216
+ * `drag-disabled-row-cell` | Cell in a row that isn't available for dragging
217
+ * `drop-disabled-row-cell` | Cell in a row that can't be dropped on top of
218
+ * `frozen-cell` | Frozen cell in the internal table
219
+ * `frozen-to-end-cell` | Frozen to end cell in the internal table
220
+ * `last-frozen-cell` | Last frozen cell
221
+ * `first-frozen-to-end-cell` | First cell frozen to end
222
+ * `first-column-cell` | First visible cell on a row
223
+ * `last-column-cell` | Last visible cell on a row
224
+ * `reorder-allowed-cell` | Cell in a column where another column can be reordered
225
+ * `reorder-dragging-cell` | Cell in a column currently being reordered
226
+ * `resize-handle` | Handle for resizing the columns
227
+ * `reorder-ghost` | Ghost element of the header cell being dragged
186
228
  *
187
229
  * The following state attributes are available for styling:
188
230
  *
189
- * Attribute | Description | Part name
190
- * -------------|-------------|------------
191
- * `loading` | Set when the grid is loading data from data provider | :host
192
- * `interacting` | Keyboard navigation in interaction mode | :host
193
- * `navigating` | Keyboard navigation in navigation mode | :host
194
- * `overflow` | Set when rows are overflowing the grid viewport. Possible values: `top`, `bottom`, `start`, `end` | :host
195
- * `reordering` | Set when the grid's columns are being reordered | :host
196
- * `dragover` | Set when the grid (not a specific row) is dragged over | :host
197
- * `dragging-rows` | Set when grid rows are dragged | :host
198
- * `reorder-status` | Reflects the status of a cell while columns are being reordered | cell
199
- * `frozen` | Frozen cell | cell
200
- * `last-frozen` | Last frozen cell | cell
201
- * `first-column` | First visible cell on a row | cell
202
- * `last-column` | Last visible cell on a row | cell
203
- * `selected` | Selected row | row
204
- * `expanded` | Expanded row | row
205
- * `details-opened` | Row with details open | row
206
- * `loading` | Row that is waiting for data from data provider | row
207
- * `odd` | Odd row | row
208
- * `first` | The first body row | row
209
- * `last` | The last body row | row
210
- * `dragstart` | Set for one frame when drag of a row is starting. The value is a number when multiple rows are dragged | row
211
- * `dragover` | Set when the row is dragged over | row
212
- * `drag-disabled` | Set to a row that isn't available for dragging | row
213
- * `drop-disabled` | Set to a row that can't be dropped on top of | row
231
+ * Attribute | Description | Part name
232
+ * ----------------------|---------------------------------------------------------------------------------------------------|-----------
233
+ * `loading` | Set when the grid is loading data from data provider | :host
234
+ * `interacting` | Keyboard navigation in interaction mode | :host
235
+ * `navigating` | Keyboard navigation in navigation mode | :host
236
+ * `overflow` | Set when rows are overflowing the grid viewport. Possible values: `top`, `bottom`, `start`, `end` | :host
237
+ * `reordering` | Set when the grid's columns are being reordered | :host
238
+ * `dragover` | Set when the grid (not a specific row) is dragged over | :host
239
+ * `dragging-rows` | Set when grid rows are dragged | :host
240
+ * `reorder-status` | Reflects the status of a cell while columns are being reordered | cell
241
+ * `frozen` | Frozen cell | cell
242
+ * `frozen-to-end` | Cell frozen to end | cell
243
+ * `last-frozen` | Last frozen cell | cell
244
+ * `first-frozen-to-end` | First cell frozen to end | cell
245
+ * `first-column` | First visible cell on a row | cell
246
+ * `last-column` | Last visible cell on a row | cell
247
+ * `selected` | Selected row | row
248
+ * `expanded` | Expanded row | row
249
+ * `details-opened` | Row with details open | row
250
+ * `loading` | Row that is waiting for data from data provider | row
251
+ * `odd` | Odd row | row
252
+ * `first` | The first body row | row
253
+ * `last` | The last body row | row
254
+ * `dragstart` | Set for one frame when starting to drag a row. The value is a number when dragging multiple rows | row
255
+ * `dragover` | Set when the row is dragged over | row
256
+ * `drag-disabled` | Set to a row that isn't available for dragging | row
257
+ * `drop-disabled` | Set to a row that can't be dropped on top of | row
214
258
  *
215
259
  * See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
216
260
  *
@@ -219,12 +263,14 @@ import { StylingMixin } from './vaadin-grid-styling-mixin.js';
219
263
  * @fires {CustomEvent} cell-focus - Fired when a cell is focused with click or keyboard navigation.
220
264
  * @fires {CustomEvent} column-reorder - Fired when the columns in the grid are reordered.
221
265
  * @fires {CustomEvent} column-resize - Fired when the grid column resize is finished.
266
+ * @fires {CustomEvent} data-provider-changed - Fired when the `dataProvider` property changes.
222
267
  * @fires {CustomEvent} expanded-items-changed - Fired when the `expandedItems` property changes.
223
268
  * @fires {CustomEvent} grid-dragstart - Fired when starting to drag grid rows.
224
269
  * @fires {CustomEvent} grid-dragend - Fired when the dragging of the rows ends.
225
270
  * @fires {CustomEvent} grid-drop - Fired when a drop occurs on top of the grid.
226
271
  * @fires {CustomEvent} loading-changed - Fired when the `loading` property changes.
227
272
  * @fires {CustomEvent} selected-items-changed - Fired when the `selectedItems` property changes.
273
+ * @fires {CustomEvent} size-changed - Fired when the `size` property changes.
228
274
  *
229
275
  * @extends HTMLElement
230
276
  * @mixes ElementMixin
@@ -390,6 +436,18 @@ class Grid extends ElementMixin(
390
436
  this.addEventListener('animationend', this._onAnimationEnd);
391
437
  }
392
438
 
439
+ /** @private */
440
+ get _firstVisibleIndex() {
441
+ const firstVisibleItem = this.__getFirstVisibleItem();
442
+ return firstVisibleItem ? firstVisibleItem.index : undefined;
443
+ }
444
+
445
+ /** @private */
446
+ get _lastVisibleIndex() {
447
+ const lastVisibleItem = this.__getLastVisibleItem();
448
+ return lastVisibleItem ? lastVisibleItem.index : undefined;
449
+ }
450
+
393
451
  /** @protected */
394
452
  connectedCallback() {
395
453
  super.connectedCallback();
@@ -409,12 +467,6 @@ class Grid extends ElementMixin(
409
467
  return this._getVisibleRows().find((row) => this._isInViewport(row));
410
468
  }
411
469
 
412
- /** @private */
413
- get _firstVisibleIndex() {
414
- const firstVisibleItem = this.__getFirstVisibleItem();
415
- return firstVisibleItem ? firstVisibleItem.index : undefined;
416
- }
417
-
418
470
  /** @private */
419
471
  __getLastVisibleItem() {
420
472
  return this._getVisibleRows()
@@ -422,12 +474,6 @@ class Grid extends ElementMixin(
422
474
  .find((row) => this._isInViewport(row));
423
475
  }
424
476
 
425
- /** @private */
426
- get _lastVisibleIndex() {
427
- const lastVisibleItem = this.__getLastVisibleItem();
428
- return lastVisibleItem ? lastVisibleItem.index : undefined;
429
- }
430
-
431
477
  /** @private */
432
478
  _isInViewport(item) {
433
479
  const scrollTargetRect = this.$.table.getBoundingClientRect();
@@ -467,19 +513,6 @@ class Grid extends ElementMixin(
467
513
  this._tooltipController.setManual(true);
468
514
  }
469
515
 
470
- /**
471
- * @param {string} name
472
- * @param {?string} oldValue
473
- * @param {?string} newValue
474
- * @protected
475
- */
476
- attributeChangedCallback(name, oldValue, newValue) {
477
- super.attributeChangedCallback(name, oldValue, newValue);
478
- if (name === 'dir') {
479
- this.__isRTL = newValue === 'rtl';
480
- }
481
- }
482
-
483
516
  /** @private */
484
517
  __getBodyCellCoordinates(cell) {
485
518
  if (this.$.items.contains(cell) && cell.localName === 'td') {
@@ -506,9 +539,15 @@ class Grid extends ElementMixin(
506
539
  const cell = this.shadowRoot.activeElement;
507
540
  const cellCoordinates = this.__getBodyCellCoordinates(cell);
508
541
 
542
+ const previousSize = virtualizer.size || 0;
509
543
  virtualizer.size = effectiveSize;
510
- virtualizer.update();
511
- virtualizer.flush();
544
+
545
+ // Request an update for the previous last row to have the "last" state removed
546
+ virtualizer.update(previousSize - 1, previousSize - 1);
547
+ if (effectiveSize < previousSize) {
548
+ // Size was decreased, so the new last row requires an explicit update
549
+ virtualizer.update(effectiveSize - 1, effectiveSize - 1);
550
+ }
512
551
 
513
552
  // If the focused cell's parent row got hidden by the size change, focus the corresponding new cell
514
553
  if (cellCoordinates && cell.parentElement.hidden) {
@@ -539,6 +578,18 @@ class Grid extends ElementMixin(
539
578
 
540
579
  /** @private */
541
580
  __getIntrinsicWidth(col) {
581
+ if (this.__intrinsicWidthCache.has(col)) {
582
+ return this.__intrinsicWidthCache.get(col);
583
+ }
584
+
585
+ const width = this.__calculateIntrinsicWidth(col);
586
+ this.__intrinsicWidthCache.set(col, width);
587
+
588
+ return width;
589
+ }
590
+
591
+ /** @private */
592
+ __calculateIntrinsicWidth(col) {
542
593
  const initialWidth = col.width;
543
594
  const initialFlexGrow = col.flexGrow;
544
595
 
@@ -605,12 +656,19 @@ class Grid extends ElementMixin(
605
656
  _recalculateColumnWidths(cols) {
606
657
  // Flush to make sure DOM is up-to-date when measuring the column widths
607
658
  this.__virtualizer.flush();
659
+ [...this.$.header.children, ...this.$.footer.children].forEach((row) => {
660
+ if (row.__debounceUpdateHeaderFooterRowVisibility) {
661
+ row.__debounceUpdateHeaderFooterRowVisibility.flush();
662
+ }
663
+ });
608
664
 
609
665
  // Flush to account for any changes to the visibility of the columns
610
666
  if (this._debouncerHiddenChanged) {
611
667
  this._debouncerHiddenChanged.flush();
612
668
  }
613
669
 
670
+ this.__intrinsicWidthCache = new Map();
671
+
614
672
  cols.forEach((col) => {
615
673
  col.width = `${this.__getDistributedWidth(col)}px`;
616
674
  });
@@ -751,13 +809,10 @@ class Grid extends ElementMixin(
751
809
  * @param {boolean} noNotify
752
810
  * @protected
753
811
  */
754
- // eslint-disable-next-line max-params
755
- _updateRow(row, columns, section, isColumnRow, noNotify) {
756
- section = section || 'body';
757
-
812
+ _updateRow(row, columns, section = 'body', isColumnRow = false, noNotify = false) {
758
813
  const contentsFragment = document.createDocumentFragment();
759
814
 
760
- Array.from(row.children).forEach((cell) => {
815
+ iterateChildren(row, (cell) => {
761
816
  cell._vacant = true;
762
817
  });
763
818
  row.innerHTML = '';
@@ -769,7 +824,9 @@ class Grid extends ElementMixin(
769
824
 
770
825
  if (section === 'body') {
771
826
  // Body
772
- column._cells = column._cells || [];
827
+ if (!column._cells) {
828
+ column._cells = [];
829
+ }
773
830
  cell = column._cells.find((cell) => cell._vacant);
774
831
  if (!cell) {
775
832
  cell = this._createCell('td', column);
@@ -780,7 +837,9 @@ class Grid extends ElementMixin(
780
837
 
781
838
  if (index === cols.length - 1 && this.rowDetailsRenderer) {
782
839
  // Add details cell as last cell to body rows
783
- this._detailsCells = this._detailsCells || [];
840
+ if (!this._detailsCells) {
841
+ this._detailsCells = [];
842
+ }
784
843
  const detailsCell = this._detailsCells.find((cell) => cell._vacant) || this._createCell('td');
785
844
  if (this._detailsCells.indexOf(detailsCell) === -1) {
786
845
  this._detailsCells.push(detailsCell);
@@ -806,7 +865,9 @@ class Grid extends ElementMixin(
806
865
  row.appendChild(cell);
807
866
  column[`_${section}Cell`] = cell;
808
867
  } else {
809
- column._emptyCells = column._emptyCells || [];
868
+ if (!column._emptyCells) {
869
+ column._emptyCells = [];
870
+ }
810
871
  cell = column._emptyCells.find((cell) => cell._vacant) || this._createCell(tagName);
811
872
  cell._column = column;
812
873
  row.appendChild(cell);
@@ -815,7 +876,6 @@ class Grid extends ElementMixin(
815
876
  }
816
877
  }
817
878
  cell.setAttribute('part', `cell ${section}-cell`);
818
- this.__updateHeaderFooterRowVisibility(row);
819
879
  }
820
880
 
821
881
  if (!cell._content.parentElement) {
@@ -825,6 +885,10 @@ class Grid extends ElementMixin(
825
885
  cell._column = column;
826
886
  });
827
887
 
888
+ if (section !== 'body') {
889
+ this.__debounceUpdateHeaderFooterRowVisibility(row);
890
+ }
891
+
828
892
  // Might be empty if only cache was used
829
893
  this.appendChild(contentsFragment);
830
894
 
@@ -832,6 +896,18 @@ class Grid extends ElementMixin(
832
896
  this._updateFirstAndLastColumnForRow(row);
833
897
  }
834
898
 
899
+ /**
900
+ * @param {HTMLTableRowElement} row
901
+ * @protected
902
+ */
903
+ __debounceUpdateHeaderFooterRowVisibility(row) {
904
+ row.__debounceUpdateHeaderFooterRowVisibility = Debouncer.debounce(
905
+ row.__debounceUpdateHeaderFooterRowVisibility,
906
+ microTask,
907
+ () => this.__updateHeaderFooterRowVisibility(row),
908
+ );
909
+ }
910
+
835
911
  /**
836
912
  * @param {HTMLTableRowElement} row
837
913
  * @protected
@@ -886,9 +962,8 @@ class Grid extends ElementMixin(
886
962
  return;
887
963
  }
888
964
 
889
- row.toggleAttribute('first', index === 0);
890
- row.toggleAttribute('last', index === this._effectiveSize - 1);
891
- row.toggleAttribute('odd', index % 2);
965
+ this._updateRowOrderParts(row, index);
966
+
892
967
  this._a11yUpdateRowRowindex(row, index);
893
968
  this._getItem(index, row);
894
969
  }
@@ -899,14 +974,38 @@ class Grid extends ElementMixin(
899
974
  this.recalculateColumnWidths();
900
975
  }
901
976
 
977
+ /** @private */
978
+ _updateRowOrderParts(row, index = row.index) {
979
+ updateRowStates(row, {
980
+ first: index === 0,
981
+ last: index === this._effectiveSize - 1,
982
+ odd: index % 2 !== 0,
983
+ even: index % 2 === 0,
984
+ });
985
+ }
986
+
987
+ /** @private */
988
+ _updateRowStateParts(row, { expanded, selected, detailsOpened }) {
989
+ updateRowStates(row, {
990
+ expanded,
991
+ selected,
992
+ 'details-opened': detailsOpened,
993
+ });
994
+ }
995
+
902
996
  /**
903
997
  * @param {!Array<!GridColumn>} columnTree
904
998
  * @protected
905
999
  */
906
1000
  _renderColumnTree(columnTree) {
907
- Array.from(this.$.items.children).forEach((row) =>
908
- this._updateRow(row, columnTree[columnTree.length - 1], null, false, true),
909
- );
1001
+ iterateChildren(this.$.items, (row) => {
1002
+ this._updateRow(row, columnTree[columnTree.length - 1], 'body', false, true);
1003
+
1004
+ const model = this.__getRowModel(row);
1005
+ this._updateRowOrderParts(row);
1006
+ this._updateRowStateParts(row, model);
1007
+ this._filterDragAndDrop(row, model);
1008
+ });
910
1009
 
911
1010
  while (this.$.header.children.length < columnTree.length) {
912
1011
  const headerRow = document.createElement('tr');
@@ -926,13 +1025,21 @@ class Grid extends ElementMixin(
926
1025
  this.$.footer.removeChild(this.$.footer.firstElementChild);
927
1026
  }
928
1027
 
929
- Array.from(this.$.header.children).forEach((headerRow, index) =>
930
- this._updateRow(headerRow, columnTree[index], 'header', index === columnTree.length - 1),
931
- );
1028
+ iterateChildren(this.$.header, (headerRow, index, rows) => {
1029
+ this._updateRow(headerRow, columnTree[index], 'header', index === columnTree.length - 1);
932
1030
 
933
- Array.from(this.$.footer.children).forEach((footerRow, index) =>
934
- this._updateRow(footerRow, columnTree[columnTree.length - 1 - index], 'footer', index === 0),
935
- );
1031
+ const cells = getBodyRowCells(headerRow);
1032
+ updateCellsPart(cells, 'first-header-row-cell', index === 0);
1033
+ updateCellsPart(cells, 'last-header-row-cell', index === rows.length - 1);
1034
+ });
1035
+
1036
+ iterateChildren(this.$.footer, (footerRow, index, rows) => {
1037
+ this._updateRow(footerRow, columnTree[columnTree.length - 1 - index], 'footer', index === 0);
1038
+
1039
+ const cells = getBodyRowCells(footerRow);
1040
+ updateCellsPart(cells, 'first-footer-row-cell', index === 0);
1041
+ updateCellsPart(cells, 'last-footer-row-cell', index === rows.length - 1);
1042
+ });
936
1043
 
937
1044
  // Sizer rows
938
1045
  this._updateRow(this.$.sizer, columnTree[columnTree.length - 1]);
@@ -945,11 +1052,13 @@ class Grid extends ElementMixin(
945
1052
  this._a11yUpdateFooterRows();
946
1053
  this.__updateFooterPositioning();
947
1054
  this.generateCellClassNames();
1055
+ this.generateCellPartNames();
948
1056
  }
949
1057
 
1058
+ /** @private */
950
1059
  __updateFooterPositioning() {
951
1060
  // TODO: fixed in Firefox 99, remove when we can drop Firefox ESR 91 support
952
- if (this._firefox && parseFloat(navigator.userAgent.match(/Firefox\/(\d{2,3}.\d)/)[1]) < 99) {
1061
+ if (this._firefox && parseFloat(navigator.userAgent.match(/Firefox\/(\d{2,3}.\d)/u)[1]) < 99) {
953
1062
  // Sticky (or translated) footer in a flexbox host doesn't get included in
954
1063
  // the scroll height calculation on FF. This is a workaround for the issue.
955
1064
  this.$.items.style.paddingBottom = 0;
@@ -973,14 +1082,13 @@ class Grid extends ElementMixin(
973
1082
  this._a11yUpdateRowLevel(row, model.level);
974
1083
  this._a11yUpdateRowSelected(row, model.selected);
975
1084
 
976
- row.toggleAttribute('expanded', model.expanded);
977
- row.toggleAttribute('selected', model.selected);
978
- row.toggleAttribute('details-opened', model.detailsOpened);
1085
+ this._updateRowStateParts(row, model);
979
1086
 
980
1087
  this._generateCellClassNames(row, model);
1088
+ this._generateCellPartNames(row, model);
981
1089
  this._filterDragAndDrop(row, model);
982
1090
 
983
- Array.from(row.children).forEach((cell) => {
1091
+ iterateChildren(row, (cell) => {
984
1092
  if (cell._renderer) {
985
1093
  const owner = cell._column || this;
986
1094
  cell._renderer.call(owner, cell._content, owner, model);
@@ -1088,21 +1196,6 @@ class Grid extends ElementMixin(
1088
1196
  this.__virtualizer.update(start, end);
1089
1197
  }
1090
1198
  }
1091
-
1092
- /**
1093
- * Updates the computed metrics and positioning of internal grid parts
1094
- * (row/details cell positioning etc). Needs to be invoked whenever the sizing of grid
1095
- * content changes asynchronously to ensure consistent appearance (e.g. when a
1096
- * contained image whose bounds aren't known beforehand finishes loading).
1097
- *
1098
- * @deprecated Since Vaadin 22, `notifyResize()` is deprecated. The component uses a
1099
- * ResizeObserver internally and doesn't need to be explicitly notified of resizes.
1100
- */
1101
- notifyResize() {
1102
- console.warn(
1103
- `WARNING: Since Vaadin 22, notifyResize() is deprecated. The component uses a ResizeObserver internally and doesn't need to be explicitly notified of resizes.`,
1104
- );
1105
- }
1106
1199
  }
1107
1200
 
1108
1201
  customElements.define(Grid.is, Grid);
@@ -57,7 +57,7 @@ registerStyles(
57
57
  }
58
58
 
59
59
  /* Hide first body row top border */
60
- :host(:not([theme~='no-row-borders'])) [part='row'][first] [part~='cell']:not([part~='details-cell']) {
60
+ :host(:not([theme~='no-row-borders'])) [part~='first-row'] [part~='cell']:not([part~='details-cell']) {
61
61
  border-top: 0;
62
62
  min-height: calc(var(--lumo-size-m) - var(--_lumo-grid-border-width));
63
63
  }
@@ -137,7 +137,7 @@ registerStyles(
137
137
  margin-top: -1px;
138
138
  }
139
139
 
140
- :host([all-rows-visible]) [part~='row'][last][dragover='below'] [part~='cell']::after {
140
+ :host([all-rows-visible]) [part~='last-row'][dragover='below'] [part~='cell']::after {
141
141
  height: 1px;
142
142
  }
143
143
 
@@ -207,42 +207,42 @@ registerStyles(
207
207
  font-weight: 400;
208
208
  }
209
209
 
210
- [part='row']:only-child [part~='header-cell'] {
210
+ [part~='row']:only-child [part~='header-cell'] {
211
211
  min-height: var(--lumo-size-xl);
212
212
  }
213
213
 
214
214
  /* Header borders */
215
215
 
216
216
  /* Hide first header row top border */
217
- :host(:not([theme~='no-row-borders'])) [part='row']:first-child [part~='header-cell'] {
217
+ :host(:not([theme~='no-row-borders'])) [part~='row']:first-child [part~='header-cell'] {
218
218
  border-top: 0;
219
219
  }
220
220
 
221
- [part='row']:last-child [part~='header-cell'] {
221
+ [part~='row']:last-child [part~='header-cell'] {
222
222
  border-bottom: var(--_lumo-grid-border-width) solid transparent;
223
223
  }
224
224
 
225
- :host(:not([theme~='no-row-borders'])) [part='row']:last-child [part~='header-cell'] {
225
+ :host(:not([theme~='no-row-borders'])) [part~='row']:last-child [part~='header-cell'] {
226
226
  border-bottom-color: var(--_lumo-grid-secondary-border-color);
227
227
  }
228
228
 
229
229
  /* Overflow uses a stronger border color */
230
- :host([overflow~='top']) [part='row']:last-child [part~='header-cell'] {
230
+ :host([overflow~='top']) [part~='row']:last-child [part~='header-cell'] {
231
231
  border-bottom-color: var(--_lumo-grid-border-color);
232
232
  }
233
233
 
234
234
  /* Footer borders */
235
235
 
236
- [part='row']:first-child [part~='footer-cell'] {
236
+ [part~='row']:first-child [part~='footer-cell'] {
237
237
  border-top: var(--_lumo-grid-border-width) solid transparent;
238
238
  }
239
239
 
240
- :host(:not([theme~='no-row-borders'])) [part='row']:first-child [part~='footer-cell'] {
240
+ :host(:not([theme~='no-row-borders'])) [part~='row']:first-child [part~='footer-cell'] {
241
241
  border-top-color: var(--_lumo-grid-secondary-border-color);
242
242
  }
243
243
 
244
244
  /* Overflow uses a stronger border color */
245
- :host([overflow~='bottom']) [part='row']:first-child [part~='footer-cell'] {
245
+ :host([overflow~='bottom']) [part~='row']:first-child [part~='footer-cell'] {
246
246
  border-top-color: var(--_lumo-grid-border-color);
247
247
  }
248
248
 
@@ -309,8 +309,8 @@ registerStyles(
309
309
 
310
310
  /* Row stripes */
311
311
 
312
- :host([theme~='row-stripes']) [part~='row']:not([odd]) [part~='body-cell'],
313
- :host([theme~='row-stripes']) [part~='row']:not([odd]) [part~='details-cell'] {
312
+ :host([theme~='row-stripes']) [part~='even-row'] [part~='body-cell'],
313
+ :host([theme~='row-stripes']) [part~='even-row'] [part~='details-cell'] {
314
314
  background-image: linear-gradient(var(--lumo-contrast-5pct), var(--lumo-contrast-5pct));
315
315
  background-repeat: repeat-x;
316
316
  }
@@ -334,7 +334,7 @@ registerStyles(
334
334
 
335
335
  /* Compact */
336
336
 
337
- :host([theme~='compact']) [part='row']:only-child [part~='header-cell'] {
337
+ :host([theme~='compact']) [part~='row']:only-child [part~='header-cell'] {
338
338
  min-height: var(--lumo-size-m);
339
339
  }
340
340
 
@@ -342,7 +342,7 @@ registerStyles(
342
342
  min-height: var(--lumo-size-s);
343
343
  }
344
344
 
345
- :host([theme~='compact']) [part='row'][first] [part~='cell']:not([part~='details-cell']) {
345
+ :host([theme~='compact']) [part~='first-row'] [part~='cell']:not([part~='details-cell']) {
346
346
  min-height: calc(var(--lumo-size-s) - var(--_lumo-grid-border-width));
347
347
  }
348
348
 
@@ -1,9 +1,2 @@
1
- import '@vaadin/vaadin-lumo-styles/color.js';
2
- import '@vaadin/vaadin-lumo-styles/font-icons.js';
3
- import '@vaadin/vaadin-lumo-styles/sizing.js';
4
- import '@vaadin/vaadin-lumo-styles/spacing.js';
5
- import '@vaadin/vaadin-lumo-styles/style.js';
6
- import '@vaadin/vaadin-lumo-styles/typography.js';
7
- import '@vaadin/checkbox/theme/lumo/vaadin-checkbox.js';
8
1
  import './vaadin-grid-styles.js';
9
2
  import '../../src/vaadin-grid.js';
@@ -191,7 +191,7 @@ registerStyles(
191
191
  margin-top: -1px;
192
192
  }
193
193
 
194
- :host([all-rows-visible]) [part~='row'][last][dragover='below'] [part~='cell']::after {
194
+ :host([all-rows-visible]) [part~='last-row'][dragover='below'] [part~='cell']::after {
195
195
  height: 1px;
196
196
  }
197
197