@vaadin/grid 24.0.0-alpha4 → 24.0.0-alpha5

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.
@@ -3,6 +3,7 @@
3
3
  * Copyright (c) 2016 - 2022 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
+ import { iterateChildren, updatePart } from './vaadin-grid-helpers.js';
6
7
 
7
8
  /**
8
9
  * @polymerMixin
@@ -28,34 +29,83 @@ export const StylingMixin = (superClass) =>
28
29
  * - `model.selected` Selected state.
29
30
  *
30
31
  * @type {GridCellClassNameGenerator | null | undefined}
32
+ * @deprecated Use `cellPartNameGenerator` instead.
31
33
  */
32
34
  cellClassNameGenerator: Function,
35
+
36
+ /**
37
+ * A function that allows generating CSS `part` names for grid cells in Shadow DOM based
38
+ * on their row and column, for styling from outside using the `::part()` selector.
39
+ *
40
+ * The return value should be the generated part name as a string, or multiple part names
41
+ * separated by whitespace characters.
42
+ *
43
+ * Receives two arguments:
44
+ * - `column` The `<vaadin-grid-column>` element (`undefined` for details-cell).
45
+ * - `model` The object with the properties related with
46
+ * the rendered item, contains:
47
+ * - `model.index` The index of the item.
48
+ * - `model.item` The item.
49
+ * - `model.expanded` Sublevel toggle state.
50
+ * - `model.level` Level of the tree represented with a horizontal offset of the toggle button.
51
+ * - `model.selected` Selected state.
52
+ *
53
+ * @type {GridCellPartNameGenerator | null | undefined}
54
+ */
55
+ cellPartNameGenerator: Function,
33
56
  };
34
57
  }
35
58
 
36
59
  static get observers() {
37
- return ['__cellClassNameGeneratorChanged(cellClassNameGenerator)'];
60
+ return [
61
+ '__cellClassNameGeneratorChanged(cellClassNameGenerator)',
62
+ '__cellPartNameGeneratorChanged(cellPartNameGenerator)',
63
+ ];
38
64
  }
39
65
 
66
+ /** @private */
40
67
  __cellClassNameGeneratorChanged() {
41
68
  this.generateCellClassNames();
42
69
  }
43
70
 
71
+ /** @private */
72
+ __cellPartNameGeneratorChanged() {
73
+ this.generateCellPartNames();
74
+ }
75
+
44
76
  /**
45
77
  * Runs the `cellClassNameGenerator` for the visible cells.
46
78
  * If the generator depends on varying conditions, you need to
47
79
  * call this function manually in order to update the styles when
48
80
  * the conditions change.
81
+ *
82
+ * @deprecated Use `cellPartNameGenerator` and `generateCellPartNames()` instead.
49
83
  */
50
84
  generateCellClassNames() {
51
- Array.from(this.$.items.children)
52
- .filter((row) => !row.hidden && !row.hasAttribute('loading'))
53
- .forEach((row) => this._generateCellClassNames(row, this.__getRowModel(row)));
85
+ iterateChildren(this.$.items, (row) => {
86
+ if (!row.hidden && !row.hasAttribute('loading')) {
87
+ this._generateCellClassNames(row, this.__getRowModel(row));
88
+ }
89
+ });
90
+ }
91
+
92
+ /**
93
+ * Runs the `cellPartNameGenerator` for the visible cells.
94
+ * If the generator depends on varying conditions, you need to
95
+ * call this function manually in order to update the styles when
96
+ * the conditions change.
97
+ */
98
+ generateCellPartNames() {
99
+ iterateChildren(this.$.items, (row) => {
100
+ if (!row.hidden && !row.hasAttribute('loading')) {
101
+ this._generateCellPartNames(row, this.__getRowModel(row));
102
+ }
103
+ });
54
104
  }
55
105
 
56
106
  /** @private */
57
107
  _generateCellClassNames(row, model) {
58
- Array.from(row.children).forEach((cell) => {
108
+ iterateChildren(row, (cell) => {
59
109
  if (cell.__generatedClasses) {
60
110
  cell.__generatedClasses.forEach((className) => cell.classList.remove(className));
61
111
  }
@@ -68,4 +118,26 @@ export const StylingMixin = (superClass) =>
68
118
  }
69
119
  });
70
120
  }
121
+
122
+ /** @private */
123
+ _generateCellPartNames(row, model) {
124
+ iterateChildren(row, (cell) => {
125
+ if (cell.__generatedParts) {
126
+ cell.__generatedParts.forEach((partName) => {
127
+ // Remove previously generated part names
128
+ updatePart(cell, null, partName);
129
+ });
130
+ }
131
+ if (this.cellPartNameGenerator) {
132
+ const result = this.cellPartNameGenerator(cell._column, model);
133
+ cell.__generatedParts = result && result.split(' ').filter((partName) => partName.length > 0);
134
+ if (cell.__generatedParts) {
135
+ cell.__generatedParts.forEach((partName) => {
136
+ // Add the newly generated names to part
137
+ updatePart(cell, true, partName);
138
+ });
139
+ }
140
+ }
141
+ });
142
+ }
71
143
  };
@@ -30,12 +30,16 @@ import { GridRowDetailsRenderer } from './vaadin-grid-row-details-mixin.js';
30
30
  import type { ScrollMixinClass } from './vaadin-grid-scroll-mixin.js';
31
31
  import type { SelectionMixinClass } from './vaadin-grid-selection-mixin.js';
32
32
  import type { SortMixinClass } from './vaadin-grid-sort-mixin.js';
33
- import type { StylingMixinClass } from './vaadin-grid-styling-mixin.js';
34
- import { GridCellClassNameGenerator } from './vaadin-grid-styling-mixin.js';
33
+ import type {
34
+ GridCellClassNameGenerator,
35
+ GridCellPartNameGenerator,
36
+ StylingMixinClass,
37
+ } from './vaadin-grid-styling-mixin.js';
35
38
 
36
39
  export {
37
40
  GridBodyRenderer,
38
41
  GridCellClassNameGenerator,
42
+ GridCellPartNameGenerator,
39
43
  GridDataProvider,
40
44
  GridDataProviderCallback,
41
45
  GridDataProviderParams,
@@ -299,57 +303,86 @@ export interface GridEventMap<TItem> extends HTMLElementEventMap, GridCustomEven
299
303
  *
300
304
  * The following shadow DOM parts are available for styling:
301
305
  *
302
- * Part name | Description
303
- * -----------------------|----------------
304
- * `row` | Row in the internal table
305
- * `expanded-row` | Expanded row
306
- * `selected-row` | Selected row
307
- * `details-opened-row` | Row with details open
308
- * `odd-row` | Odd row
309
- * `first-row` | The first body row
310
- * `last-row` | The last body row
311
- * `dragstart-row` | Set on the row for one frame when drag is starting. The value is a number when multiple rows are dragged
312
- * `dragover-above-row` | Set on the row when the a row is dragged over above
313
- * `dragover-below-row` | Set on the row when the a row is dragged over below
314
- * `dragover-on-top-row` | Set on the row when the a row is dragged over on top
315
- * `drag-disabled-row` | Set to a row that isn't available for dragging
316
- * `drop-disabled-row` | Set to a row that can't be dropped on top of
317
- * `cell` | Cell in the internal table
318
- * `header-cell` | Header cell in the internal table
319
- * `body-cell` | Body cell in the internal table
320
- * `footer-cell` | Footer cell in the internal table
321
- * `details-cell` | Row details cell in the internal table
322
- * `focused-cell` | Focused cell in the internal table
323
- * `resize-handle` | Handle for resizing the columns
324
- * `reorder-ghost` | Ghost element of the header cell being dragged
306
+ * Part name | Description
307
+ * ---------------------------|----------------
308
+ * `row` | Row in the internal table
309
+ * `expanded-row` | Expanded row
310
+ * `selected-row` | Selected row
311
+ * `details-opened-row` | Row with details open
312
+ * `odd-row` | Odd row
313
+ * `even-row` | Even row
314
+ * `first-row` | The first body row
315
+ * `last-row` | The last body row
316
+ * `dragstart-row` | Set on the row for one frame when drag is starting.
317
+ * `dragover-above-row` | Set on the row when the a row is dragged over above
318
+ * `dragover-below-row` | Set on the row when the a row is dragged over below
319
+ * `dragover-on-top-row` | Set on the row when the a row is dragged over on top
320
+ * `drag-disabled-row` | Set to a row that isn't available for dragging
321
+ * `drop-disabled-row` | Set to a row that can't be dropped on top of
322
+ * `cell` | Cell in the internal table
323
+ * `header-cell` | Header cell in the internal table
324
+ * `body-cell` | Body cell in the internal table
325
+ * `footer-cell` | Footer cell in the internal table
326
+ * `details-cell` | Row details cell in the internal table
327
+ * `focused-cell` | Focused cell in the internal table
328
+ * `odd-row-cell` | Cell in an odd row
329
+ * `even-row-cell` | Cell in an even row
330
+ * `first-row-cell` | Cell in the first body row
331
+ * `last-row-cell` | Cell in the last body row
332
+ * `first-header-row-cell` | Cell in the first header row
333
+ * `first-footer-row-cell` | Cell in the first footer row
334
+ * `last-header-row-cell` | Cell in the last header row
335
+ * `last-footer-row-cell` | Cell in the last footer row
336
+ * `loading-row-cell` | Cell in a row that is waiting for data from data provider
337
+ * `selected-row-cell` | Cell in a selected row
338
+ * `expanded-row-cell` | Cell in an expanded row
339
+ * `details-opened-row-cell` | Cell in an row with details open
340
+ * `dragstart-row-cell` | Cell in a row that user started to drag (set for one frame)
341
+ * `dragover-above-row-cell` | Cell in a row that has another row dragged over above
342
+ * `dragover-below-row-cell` | Cell in a row that has another row dragged over below
343
+ * `dragover-on-top-row-cell` | Cell in a row that has another row dragged over on top
344
+ * `drag-disabled-row-cell` | Cell in a row that isn't available for dragging
345
+ * `drop-disabled-row-cell` | Cell in a row that can't be dropped on top of
346
+ * `frozen-cell` | Frozen cell in the internal table
347
+ * `frozen-to-end-cell` | Frozen to end cell in the internal table
348
+ * `last-frozen-cell` | Last frozen cell
349
+ * `first-frozen-to-end-cell` | First cell frozen to end
350
+ * `first-column-cell` | First visible cell on a row
351
+ * `last-column-cell` | Last visible cell on a row
352
+ * `reorder-allowed-cell` | Cell in a column where another column can be reordered
353
+ * `reorder-dragging-cell` | Cell in a column currently being reordered
354
+ * `resize-handle` | Handle for resizing the columns
355
+ * `reorder-ghost` | Ghost element of the header cell being dragged
325
356
  *
326
357
  * The following state attributes are available for styling:
327
358
  *
328
- * Attribute | Description | Part name
329
- * -------------|-------------|------------
330
- * `loading` | Set when the grid is loading data from data provider | :host
331
- * `interacting` | Keyboard navigation in interaction mode | :host
332
- * `navigating` | Keyboard navigation in navigation mode | :host
333
- * `overflow` | Set when rows are overflowing the grid viewport. Possible values: `top`, `bottom`, `start`, `end` | :host
334
- * `reordering` | Set when the grid's columns are being reordered | :host
335
- * `dragover` | Set when the grid (not a specific row) is dragged over | :host
336
- * `dragging-rows` | Set when grid rows are dragged | :host
337
- * `reorder-status` | Reflects the status of a cell while columns are being reordered | cell
338
- * `frozen` | Frozen cell | cell
339
- * `last-frozen` | Last frozen cell | cell
340
- * `first-column` | First visible cell on a row | cell
341
- * `last-column` | Last visible cell on a row | cell
342
- * `selected` | Selected row | row
343
- * `expanded` | Expanded row | row
344
- * `details-opened` | Row with details open | row
345
- * `loading` | Row that is waiting for data from data provider | row
346
- * `odd` | Odd row | row
347
- * `first` | The first body row | row
348
- * `last` | The last body row | row
349
- * `dragstart` | Set for one frame when drag of a row is starting. The value is a number when multiple rows are dragged | row
350
- * `dragover` | Set when the row is dragged over | row
351
- * `drag-disabled` | Set to a row that isn't available for dragging | row
352
- * `drop-disabled` | Set to a row that can't be dropped on top of | row
359
+ * Attribute | Description | Part name
360
+ * -----------------------|---------------------------------------------------------------------------------------------------|-----------
361
+ * `loading` | Set when the grid is loading data from data provider | :host
362
+ * `interacting` | Keyboard navigation in interaction mode | :host
363
+ * `navigating` | Keyboard navigation in navigation mode | :host
364
+ * `overflow` | Set when rows are overflowing the grid viewport. Possible values: `top`, `bottom`, `start`, `end` | :host
365
+ * `reordering` | Set when the grid's columns are being reordered | :host
366
+ * `dragover` | Set when the grid (not a specific row) is dragged over | :host
367
+ * `dragging-rows` | Set when grid rows are dragged | :host
368
+ * `reorder-status` | Reflects the status of a cell while columns are being reordered | cell
369
+ * `frozen` | Frozen cell | cell
370
+ * `frozen-to-end` | Cell frozen to end | cell
371
+ * `last-frozen` | Last frozen cell | cell
372
+ * `first-frozen-to-end` | First cell frozen to end | cell
373
+ * `first-column` | First visible cell on a row | cell
374
+ * `last-column` | Last visible cell on a row | cell
375
+ * `selected` | Selected row | row
376
+ * `expanded` | Expanded row | row
377
+ * `details-opened` | Row with details open | row
378
+ * `loading` | Row that is waiting for data from data provider | row
379
+ * `odd` | Odd row | row
380
+ * `first` | The first body row | row
381
+ * `last` | The last body row | row
382
+ * `dragstart` | Set for one frame when starting to drag a row. The value is a number when dragging multiple rows | row
383
+ * `dragover` | Set when the row is dragged over | row
384
+ * `drag-disabled` | Set to a row that isn't available for dragging | row
385
+ * `drop-disabled` | Set to a row that can't be dropped on top of | row
353
386
  *
354
387
  * See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
355
388
  *
@@ -9,7 +9,6 @@ import { beforeNextRender } from '@polymer/polymer/lib/utils/render-status.js';
9
9
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
10
10
  import { isAndroid, isChrome, isFirefox, isIOS, isSafari, isTouch } from '@vaadin/component-base/src/browser-utils.js';
11
11
  import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
12
- import { addValueToAttribute, removeValueFromAttribute } from '@vaadin/component-base/src/dom-utils.js';
13
12
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
14
13
  import { TabindexMixin } from '@vaadin/component-base/src/tabindex-mixin.js';
15
14
  import { processTemplates } from '@vaadin/component-base/src/templates.js';
@@ -26,6 +25,7 @@ import { DragAndDropMixin } from './vaadin-grid-drag-and-drop-mixin.js';
26
25
  import { DynamicColumnsMixin } from './vaadin-grid-dynamic-columns-mixin.js';
27
26
  import { EventContextMixin } from './vaadin-grid-event-context-mixin.js';
28
27
  import { FilterMixin } from './vaadin-grid-filter-mixin.js';
28
+ import { getBodyRowCells, iterateChildren, updateCellsPart, updateRowStates } from './vaadin-grid-helpers.js';
29
29
  import { KeyboardNavigationMixin } from './vaadin-grid-keyboard-navigation-mixin.js';
30
30
  import { RowDetailsMixin } from './vaadin-grid-row-details-mixin.js';
31
31
  import { ScrollMixin } from './vaadin-grid-scroll-mixin.js';
@@ -173,57 +173,86 @@ import { StylingMixin } from './vaadin-grid-styling-mixin.js';
173
173
  *
174
174
  * The following shadow DOM parts are available for styling:
175
175
  *
176
- * Part name | Description
177
- * -----------------------|----------------
178
- * `row` | Row in the internal table
179
- * `expanded-row` | Expanded row
180
- * `selected-row` | Selected row
181
- * `details-opened-row` | Row with details open
182
- * `odd-row` | Odd row
183
- * `first-row` | The first body row
184
- * `last-row` | The last body row
185
- * `dragstart-row` | Set on the row for one frame when drag is starting. The value is a number when multiple rows are dragged
186
- * `dragover-above-row` | Set on the row when the a row is dragged over above
187
- * `dragover-below-row` | Set on the row when the a row is dragged over below
188
- * `dragover-on-top-row` | Set on the row when the a row is dragged over on top
189
- * `drag-disabled-row` | Set to a row that isn't available for dragging
190
- * `drop-disabled-row` | Set to a row that can't be dropped on top of
191
- * `cell` | Cell in the internal table
192
- * `header-cell` | Header cell in the internal table
193
- * `body-cell` | Body cell in the internal table
194
- * `footer-cell` | Footer cell in the internal table
195
- * `details-cell` | Row details cell in the internal table
196
- * `focused-cell` | Focused cell in the internal table
197
- * `resize-handle` | Handle for resizing the columns
198
- * `reorder-ghost` | Ghost element of the header cell being dragged
176
+ * Part name | Description
177
+ * ---------------------------|----------------
178
+ * `row` | Row in the internal table
179
+ * `expanded-row` | Expanded row
180
+ * `selected-row` | Selected row
181
+ * `details-opened-row` | Row with details open
182
+ * `odd-row` | Odd row
183
+ * `even-row` | Even row
184
+ * `first-row` | The first body row
185
+ * `last-row` | The last body row
186
+ * `dragstart-row` | Set on the row for one frame when drag is starting.
187
+ * `dragover-above-row` | Set on the row when the a row is dragged over above
188
+ * `dragover-below-row` | Set on the row when the a row is dragged over below
189
+ * `dragover-on-top-row` | Set on the row when the a row is dragged over on top
190
+ * `drag-disabled-row` | Set to a row that isn't available for dragging
191
+ * `drop-disabled-row` | Set to a row that can't be dropped on top of
192
+ * `cell` | Cell in the internal table
193
+ * `header-cell` | Header cell in the internal table
194
+ * `body-cell` | Body cell in the internal table
195
+ * `footer-cell` | Footer cell in the internal table
196
+ * `details-cell` | Row details cell in the internal table
197
+ * `focused-cell` | Focused cell in the internal table
198
+ * `odd-row-cell` | Cell in an odd row
199
+ * `even-row-cell` | Cell in an even row
200
+ * `first-row-cell` | Cell in the first body row
201
+ * `last-row-cell` | Cell in the last body row
202
+ * `first-header-row-cell` | Cell in the first header row
203
+ * `first-footer-row-cell` | Cell in the first footer row
204
+ * `last-header-row-cell` | Cell in the last header row
205
+ * `last-footer-row-cell` | Cell in the last footer row
206
+ * `loading-row-cell` | Cell in a row that is waiting for data from data provider
207
+ * `selected-row-cell` | Cell in a selected row
208
+ * `expanded-row-cell` | Cell in an expanded row
209
+ * `details-opened-row-cell` | Cell in an row with details open
210
+ * `dragstart-row-cell` | Cell in a row that user started to drag (set for one frame)
211
+ * `dragover-above-row-cell` | Cell in a row that has another row dragged over above
212
+ * `dragover-below-row-cell` | Cell in a row that has another row dragged over below
213
+ * `dragover-on-top-row-cell` | Cell in a row that has another row dragged over on top
214
+ * `drag-disabled-row-cell` | Cell in a row that isn't available for dragging
215
+ * `drop-disabled-row-cell` | Cell in a row that can't be dropped on top of
216
+ * `frozen-cell` | Frozen cell in the internal table
217
+ * `frozen-to-end-cell` | Frozen to end cell in the internal table
218
+ * `last-frozen-cell` | Last frozen cell
219
+ * `first-frozen-to-end-cell` | First cell frozen to end
220
+ * `first-column-cell` | First visible cell on a row
221
+ * `last-column-cell` | Last visible cell on a row
222
+ * `reorder-allowed-cell` | Cell in a column where another column can be reordered
223
+ * `reorder-dragging-cell` | Cell in a column currently being reordered
224
+ * `resize-handle` | Handle for resizing the columns
225
+ * `reorder-ghost` | Ghost element of the header cell being dragged
199
226
  *
200
227
  * The following state attributes are available for styling:
201
228
  *
202
- * Attribute | Description | Part name
203
- * -------------|-------------|------------
204
- * `loading` | Set when the grid is loading data from data provider | :host
205
- * `interacting` | Keyboard navigation in interaction mode | :host
206
- * `navigating` | Keyboard navigation in navigation mode | :host
207
- * `overflow` | Set when rows are overflowing the grid viewport. Possible values: `top`, `bottom`, `start`, `end` | :host
208
- * `reordering` | Set when the grid's columns are being reordered | :host
209
- * `dragover` | Set when the grid (not a specific row) is dragged over | :host
210
- * `dragging-rows` | Set when grid rows are dragged | :host
211
- * `reorder-status` | Reflects the status of a cell while columns are being reordered | cell
212
- * `frozen` | Frozen cell | cell
213
- * `last-frozen` | Last frozen cell | cell
214
- * `first-column` | First visible cell on a row | cell
215
- * `last-column` | Last visible cell on a row | cell
216
- * `selected` | Selected row | row
217
- * `expanded` | Expanded row | row
218
- * `details-opened` | Row with details open | row
219
- * `loading` | Row that is waiting for data from data provider | row
220
- * `odd` | Odd row | row
221
- * `first` | The first body row | row
222
- * `last` | The last body row | row
223
- * `dragstart` | Set for one frame when drag of a row is starting. The value is a number when multiple rows are dragged | row
224
- * `dragover` | Set when the row is dragged over | row
225
- * `drag-disabled` | Set to a row that isn't available for dragging | row
226
- * `drop-disabled` | Set to a row that can't be dropped on top of | row
229
+ * Attribute | Description | Part name
230
+ * ----------------------|---------------------------------------------------------------------------------------------------|-----------
231
+ * `loading` | Set when the grid is loading data from data provider | :host
232
+ * `interacting` | Keyboard navigation in interaction mode | :host
233
+ * `navigating` | Keyboard navigation in navigation mode | :host
234
+ * `overflow` | Set when rows are overflowing the grid viewport. Possible values: `top`, `bottom`, `start`, `end` | :host
235
+ * `reordering` | Set when the grid's columns are being reordered | :host
236
+ * `dragover` | Set when the grid (not a specific row) is dragged over | :host
237
+ * `dragging-rows` | Set when grid rows are dragged | :host
238
+ * `reorder-status` | Reflects the status of a cell while columns are being reordered | cell
239
+ * `frozen` | Frozen cell | cell
240
+ * `frozen-to-end` | Cell frozen to end | cell
241
+ * `last-frozen` | Last frozen cell | cell
242
+ * `first-frozen-to-end` | First cell frozen to end | cell
243
+ * `first-column` | First visible cell on a row | cell
244
+ * `last-column` | Last visible cell on a row | cell
245
+ * `selected` | Selected row | row
246
+ * `expanded` | Expanded row | row
247
+ * `details-opened` | Row with details open | row
248
+ * `loading` | Row that is waiting for data from data provider | row
249
+ * `odd` | Odd row | row
250
+ * `first` | The first body row | row
251
+ * `last` | The last body row | row
252
+ * `dragstart` | Set for one frame when starting to drag a row. The value is a number when dragging multiple rows | row
253
+ * `dragover` | Set when the row is dragged over | row
254
+ * `drag-disabled` | Set to a row that isn't available for dragging | row
255
+ * `drop-disabled` | Set to a row that can't be dropped on top of | row
227
256
  *
228
257
  * See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
229
258
  *
@@ -759,7 +788,7 @@ class Grid extends ElementMixin(
759
788
 
760
789
  const contentsFragment = document.createDocumentFragment();
761
790
 
762
- Array.from(row.children).forEach((cell) => {
791
+ iterateChildren(row, (cell) => {
763
792
  cell._vacant = true;
764
793
  });
765
794
  row.innerHTML = '';
@@ -888,9 +917,8 @@ class Grid extends ElementMixin(
888
917
  return;
889
918
  }
890
919
 
891
- this._updateRowState(row, 'first', index === 0);
892
- this._updateRowState(row, 'last', index === this._effectiveSize - 1);
893
- this._updateRowState(row, 'odd', index % 2);
920
+ this._updateRowOrderParts(row, index);
921
+
894
922
  this._a11yUpdateRowRowindex(row, index);
895
923
  this._getItem(index, row);
896
924
  }
@@ -901,14 +929,38 @@ class Grid extends ElementMixin(
901
929
  this.recalculateColumnWidths();
902
930
  }
903
931
 
932
+ /** @private */
933
+ _updateRowOrderParts(row, index = row.index) {
934
+ updateRowStates(row, {
935
+ first: index === 0,
936
+ last: index === this._effectiveSize - 1,
937
+ odd: index % 2,
938
+ even: index % 2 === 0,
939
+ });
940
+ }
941
+
942
+ /** @private */
943
+ _updateRowStateParts(row, { expanded, selected, detailsOpened }) {
944
+ updateRowStates(row, {
945
+ expanded,
946
+ selected,
947
+ 'details-opened': detailsOpened,
948
+ });
949
+ }
950
+
904
951
  /**
905
952
  * @param {!Array<!GridColumn>} columnTree
906
953
  * @protected
907
954
  */
908
955
  _renderColumnTree(columnTree) {
909
- Array.from(this.$.items.children).forEach((row) =>
910
- this._updateRow(row, columnTree[columnTree.length - 1], null, false, true),
911
- );
956
+ iterateChildren(this.$.items, (row) => {
957
+ this._updateRow(row, columnTree[columnTree.length - 1], null, false, true);
958
+
959
+ const model = this.__getRowModel(row);
960
+ this._updateRowOrderParts(row);
961
+ this._updateRowStateParts(row, model);
962
+ this._filterDragAndDrop(row, model);
963
+ });
912
964
 
913
965
  while (this.$.header.children.length < columnTree.length) {
914
966
  const headerRow = document.createElement('tr');
@@ -928,13 +980,21 @@ class Grid extends ElementMixin(
928
980
  this.$.footer.removeChild(this.$.footer.firstElementChild);
929
981
  }
930
982
 
931
- Array.from(this.$.header.children).forEach((headerRow, index) =>
932
- this._updateRow(headerRow, columnTree[index], 'header', index === columnTree.length - 1),
933
- );
983
+ iterateChildren(this.$.header, (headerRow, index, rows) => {
984
+ this._updateRow(headerRow, columnTree[index], 'header', index === columnTree.length - 1);
934
985
 
935
- Array.from(this.$.footer.children).forEach((footerRow, index) =>
936
- this._updateRow(footerRow, columnTree[columnTree.length - 1 - index], 'footer', index === 0),
937
- );
986
+ const cells = getBodyRowCells(headerRow);
987
+ updateCellsPart(cells, 'first-header-row-cell', index === 0);
988
+ updateCellsPart(cells, 'last-header-row-cell', index === rows.length - 1);
989
+ });
990
+
991
+ iterateChildren(this.$.footer, (footerRow, index, rows) => {
992
+ this._updateRow(footerRow, columnTree[columnTree.length - 1 - index], 'footer', index === 0);
993
+
994
+ const cells = getBodyRowCells(footerRow);
995
+ updateCellsPart(cells, 'first-footer-row-cell', index === 0);
996
+ updateCellsPart(cells, 'last-footer-row-cell', index === rows.length - 1);
997
+ });
938
998
 
939
999
  // Sizer rows
940
1000
  this._updateRow(this.$.sizer, columnTree[columnTree.length - 1]);
@@ -947,8 +1007,10 @@ class Grid extends ElementMixin(
947
1007
  this._a11yUpdateFooterRows();
948
1008
  this.__updateFooterPositioning();
949
1009
  this.generateCellClassNames();
1010
+ this.generateCellPartNames();
950
1011
  }
951
1012
 
1013
+ /** @private */
952
1014
  __updateFooterPositioning() {
953
1015
  // TODO: fixed in Firefox 99, remove when we can drop Firefox ESR 91 support
954
1016
  if (this._firefox && parseFloat(navigator.userAgent.match(/Firefox\/(\d{2,3}.\d)/)[1]) < 99) {
@@ -975,14 +1037,13 @@ class Grid extends ElementMixin(
975
1037
  this._a11yUpdateRowLevel(row, model.level);
976
1038
  this._a11yUpdateRowSelected(row, model.selected);
977
1039
 
978
- this._updateRowState(row, 'expanded', model.expanded);
979
- this._updateRowState(row, 'selected', model.selected);
980
- this._updateRowState(row, 'details-opened', model.detailsOpened);
1040
+ this._updateRowStateParts(row, model);
981
1041
 
982
1042
  this._generateCellClassNames(row, model);
1043
+ this._generateCellPartNames(row, model);
983
1044
  this._filterDragAndDrop(row, model);
984
1045
 
985
- Array.from(row.children).forEach((cell) => {
1046
+ iterateChildren(row, (cell) => {
986
1047
  if (cell._renderer) {
987
1048
  const owner = cell._column || this;
988
1049
  cell._renderer.call(owner, cell._content, owner, model);
@@ -994,35 +1055,6 @@ class Grid extends ElementMixin(
994
1055
  this._a11yUpdateRowExpanded(row, model.expanded);
995
1056
  }
996
1057
 
997
- /**
998
- * @param {!HTMLElement} row
999
- * @param {string} state
1000
- * @param {boolean | string | null | undefined} value
1001
- * @param {boolean} partWithValue
1002
- * @protected
1003
- */
1004
- _updateRowState(row, state, value, partWithValue) {
1005
- switch (typeof value) {
1006
- case 'boolean':
1007
- row.toggleAttribute(state, value);
1008
- break;
1009
- case 'string':
1010
- row.setAttribute(state, value);
1011
- break;
1012
- default:
1013
- // Value set to null / undefined
1014
- row.removeAttribute(state);
1015
- break;
1016
- }
1017
-
1018
- const part = partWithValue ? `${state}-${value}-row` : `${state}-row`;
1019
- if (value || value === '') {
1020
- addValueToAttribute(row, 'part', part);
1021
- } else {
1022
- removeValueFromAttribute(row, 'part', part);
1023
- }
1024
- }
1025
-
1026
1058
  /** @private */
1027
1059
  _resizeHandler() {
1028
1060
  this._updateDetailsCellHeights();