@vaadin/grid 25.3.0-alpha7 → 25.3.0-alpha9
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.
- package/custom-elements.json +189 -161
- package/package.json +12 -12
- package/src/directives/cell-content-directive.js +2 -1
- package/src/vaadin-grid-a11y-mixin.js +6 -23
- package/src/vaadin-grid-column-auto-width-mixin.js +3 -8
- package/src/vaadin-grid-column-group-mixin.js +5 -20
- package/src/vaadin-grid-column-mixin.d.ts +3 -3
- package/src/vaadin-grid-column-mixin.js +35 -73
- package/src/vaadin-grid-column-reordering-mixin.js +4 -1
- package/src/vaadin-grid-column-resizing-mixin.js +4 -0
- package/src/vaadin-grid-data-provider-mixin.js +1 -1
- package/src/vaadin-grid-drag-and-drop-mixin.js +2 -5
- package/src/vaadin-grid-dynamic-columns-mixin.js +0 -5
- package/src/vaadin-grid-filter-column-mixin.js +1 -1
- package/src/vaadin-grid-filter-element-mixin.js +1 -3
- package/src/vaadin-grid-filter.js +1 -0
- package/src/vaadin-grid-header-footer-rendering-mixin.js +296 -0
- package/src/vaadin-grid-keyboard-navigation-mixin.js +3 -7
- package/src/vaadin-grid-mixin.js +5 -31
- package/src/vaadin-grid-row-details-mixin.js +1 -1
- package/src/vaadin-grid-scroll-mixin.js +2 -5
- package/src/vaadin-grid-selection-column-base-mixin.js +3 -3
- package/src/vaadin-grid-sorter-mixin.js +2 -5
- package/src/vaadin-grid-sorter.js +1 -0
- package/src/vaadin-grid-tree-toggle.js +1 -0
- package/src/vaadin-grid.js +1 -0
- package/web-types.json +20 -94
- package/web-types.lit.json +10 -10
- package/src/vaadin-grid-column-rendering-mixin.js +0 -195
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2016 - 2026 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import { html, nothing, render } from 'lit';
|
|
7
|
+
import { cache } from 'lit/directives/cache.js';
|
|
8
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
9
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
10
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
11
|
+
import { styleMap } from 'lit/directives/style-map.js';
|
|
12
|
+
import { microTask } from '@vaadin/component-base/src/async.js';
|
|
13
|
+
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
14
|
+
import { partMap } from '@vaadin/component-base/src/directives/part-map.js';
|
|
15
|
+
import { cellContent } from './directives/cell-content-directive.js';
|
|
16
|
+
|
|
17
|
+
function isContentCell(column, level, columnTree) {
|
|
18
|
+
const isLastRow = level === columnTree.length - 1;
|
|
19
|
+
return isLastRow || column.localName === 'vaadin-grid-column-group';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isHeaderRowVisible(columns, level, columnTree) {
|
|
23
|
+
return columns.some((column) => {
|
|
24
|
+
if (column.hidden || !isContentCell(column, level, columnTree)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (column.headerRenderer) {
|
|
29
|
+
// The column has a header renderer -> row should be visible
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (column.header === null) {
|
|
34
|
+
// The column header is explicitly set to null -> doesn't block hiding the row
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return column.path || column.header !== undefined;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isFooterRowVisible(columns, level, columnTree) {
|
|
43
|
+
return columns.some((column) => {
|
|
44
|
+
if (column.hidden || !isContentCell(column, level, columnTree)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return column.footerRenderer;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Converts a whitespace separated list of custom part names
|
|
54
|
+
* into an object accepted by the `partMap` directive.
|
|
55
|
+
*/
|
|
56
|
+
function getCustomParts(partName) {
|
|
57
|
+
return Object.fromEntries(
|
|
58
|
+
(partName ?? '')
|
|
59
|
+
.split(' ')
|
|
60
|
+
.filter((name) => name !== '')
|
|
61
|
+
.map((name) => [name, true]),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* A mixin providing rendering of header and footer rows based on the column tree.
|
|
67
|
+
*/
|
|
68
|
+
export const HeaderFooterRenderingMixin = (superClass) =>
|
|
69
|
+
class HeaderFooterRenderingMixin extends superClass {
|
|
70
|
+
/** @private */
|
|
71
|
+
__scheduleRenderHeaderFooter() {
|
|
72
|
+
this.__renderHeaderFooterDebouncer = Debouncer.debounce(this.__renderHeaderFooterDebouncer, microTask, () => {
|
|
73
|
+
this.__renderHeaderFooter();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** @private */
|
|
78
|
+
__renderHeaderFooter() {
|
|
79
|
+
this.__renderHeaderFooterDebouncer?.cancel();
|
|
80
|
+
|
|
81
|
+
const sortedColumnTree = (this._columnTree ?? []).map((columns) => {
|
|
82
|
+
return columns.toSorted((a, b) => a._order - b._order);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
sortedColumnTree.flat().forEach((column) => {
|
|
86
|
+
column._emptyCells = [];
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
this.#renderHeader(sortedColumnTree);
|
|
90
|
+
this.#renderFooter(sortedColumnTree);
|
|
91
|
+
|
|
92
|
+
this._resetKeyboardNavigation();
|
|
93
|
+
this.__a11yUpdateGridSize(this.size, this._columnTree, this.__emptyState);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
#renderHeader(columnTree) {
|
|
97
|
+
const rows = this.#getRows(columnTree, 'header');
|
|
98
|
+
render(rows.map(this.#renderHeaderRow), this.$.header, { host: this });
|
|
99
|
+
|
|
100
|
+
this.$.table.toggleAttribute('has-header', !!this.$.header.querySelector('tr:not([hidden])'));
|
|
101
|
+
|
|
102
|
+
this.$.header.querySelectorAll('.header-cell').forEach((cell) => {
|
|
103
|
+
const column = cell._column;
|
|
104
|
+
const isColumnRow = cell.parentElement === this.$.header.lastElementChild;
|
|
105
|
+
if (isColumnRow || column.localName === 'vaadin-grid-column-group') {
|
|
106
|
+
column._headerCell = cell;
|
|
107
|
+
} else {
|
|
108
|
+
column._emptyCells.push(cell);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
#renderHeaderRow = ({ level, cells, isLastRow, isFirstRow, isRowVisible }) => {
|
|
114
|
+
const rowParts = {
|
|
115
|
+
'first-header-row': isFirstRow,
|
|
116
|
+
'last-header-row': isLastRow,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
return html`
|
|
120
|
+
<tr
|
|
121
|
+
role="row"
|
|
122
|
+
part="row header-row${partMap(rowParts)}"
|
|
123
|
+
class="row header-row${classMap(rowParts)}"
|
|
124
|
+
tabindex="-1"
|
|
125
|
+
?hidden=${!isRowVisible}
|
|
126
|
+
>
|
|
127
|
+
${repeat(
|
|
128
|
+
cells,
|
|
129
|
+
({ column }) => column._id,
|
|
130
|
+
({ column, isFirstCell, isLastCell, isContentCell }) => {
|
|
131
|
+
// `cache` keeps the cell and its rendered content when the
|
|
132
|
+
// column gets hidden, so it can be restored as-is when the
|
|
133
|
+
// column is shown again.
|
|
134
|
+
if (column.hidden) {
|
|
135
|
+
return cache(nothing);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const cellParts = {
|
|
139
|
+
'first-header-row-cell': isFirstRow,
|
|
140
|
+
'last-header-row-cell': isLastRow,
|
|
141
|
+
'first-column-cell': isFirstCell,
|
|
142
|
+
'last-column-cell': isLastCell,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const customCellParts = isContentCell ? getCustomParts(column.headerPartName) : {};
|
|
146
|
+
|
|
147
|
+
return cache(html`
|
|
148
|
+
<th
|
|
149
|
+
role="columnheader"
|
|
150
|
+
part="cell header-cell${partMap({ ...cellParts, ...customCellParts })}"
|
|
151
|
+
class="cell header-cell${classMap(cellParts)}"
|
|
152
|
+
style="${styleMap({
|
|
153
|
+
width: column.width,
|
|
154
|
+
'flex-grow': column.flexGrow,
|
|
155
|
+
})}"
|
|
156
|
+
?first-column="${isFirstCell}"
|
|
157
|
+
?last-column="${isLastCell}"
|
|
158
|
+
@keydown="${this.__onCellKeyDown}"
|
|
159
|
+
@mousedown=${this.__onCellMouseDown}
|
|
160
|
+
@mouseenter=${this.__onCellMouseEnter}
|
|
161
|
+
@mouseleave=${this.__onCellMouseLeave}
|
|
162
|
+
colspan="${ifDefined(column._colSpan)}"
|
|
163
|
+
aria-colspan="${ifDefined(column._colSpan)}"
|
|
164
|
+
tabindex="-1"
|
|
165
|
+
._column=${column}
|
|
166
|
+
>
|
|
167
|
+
${cellContent(this, `vaadin-grid-header-cell-content-${level}-${column._id}`, {
|
|
168
|
+
textAlign: column.textAlign,
|
|
169
|
+
})}
|
|
170
|
+
${column.resizable ? html`<div part="resize-handle" class="resize-handle"></div>` : nothing}
|
|
171
|
+
</th>
|
|
172
|
+
`);
|
|
173
|
+
},
|
|
174
|
+
)}
|
|
175
|
+
</tr>
|
|
176
|
+
`;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
#renderFooter(columnTree) {
|
|
180
|
+
const rows = this.#getRows(columnTree, 'footer');
|
|
181
|
+
render(rows.map(this.#renderFooterRow), this.$.footer, { host: this });
|
|
182
|
+
|
|
183
|
+
this.$.table.toggleAttribute('has-footer', !!this.$.footer.querySelector('tr:not([hidden])'));
|
|
184
|
+
|
|
185
|
+
this.$.footer.querySelectorAll('.footer-cell').forEach((cell) => {
|
|
186
|
+
const column = cell._column;
|
|
187
|
+
const isColumnRow = cell.parentElement === this.$.footer.firstElementChild;
|
|
188
|
+
if (isColumnRow || column.localName === 'vaadin-grid-column-group') {
|
|
189
|
+
column._footerCell = cell;
|
|
190
|
+
} else {
|
|
191
|
+
column._emptyCells.push(cell);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
#renderFooterRow = ({ level, cells, isLastRow, isFirstRow, isRowVisible }) => {
|
|
197
|
+
const rowParts = {
|
|
198
|
+
'first-footer-row': isFirstRow,
|
|
199
|
+
'last-footer-row': isLastRow,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
return html`
|
|
203
|
+
<tr
|
|
204
|
+
role="row"
|
|
205
|
+
part="row footer-row${partMap(rowParts)}"
|
|
206
|
+
class="row footer-row${classMap(rowParts)}"
|
|
207
|
+
tabindex="-1"
|
|
208
|
+
?hidden=${!isRowVisible}
|
|
209
|
+
>
|
|
210
|
+
${repeat(
|
|
211
|
+
cells,
|
|
212
|
+
({ column }) => column._id,
|
|
213
|
+
({ column, isFirstCell, isLastCell, isContentCell }) => {
|
|
214
|
+
// `cache` keeps the cell and its rendered content when the
|
|
215
|
+
// column gets hidden, so it can be restored as-is when the
|
|
216
|
+
// column is shown again.
|
|
217
|
+
if (column.hidden) {
|
|
218
|
+
return cache(nothing);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const cellParts = {
|
|
222
|
+
'first-footer-row-cell': isFirstRow,
|
|
223
|
+
'last-footer-row-cell': isLastRow,
|
|
224
|
+
'first-column-cell': isFirstCell,
|
|
225
|
+
'last-column-cell': isLastCell,
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const customCellParts = isContentCell ? getCustomParts(column.footerPartName) : {};
|
|
229
|
+
|
|
230
|
+
return cache(html`
|
|
231
|
+
<td
|
|
232
|
+
role="gridcell"
|
|
233
|
+
part="cell footer-cell${partMap({ ...cellParts, ...customCellParts })}"
|
|
234
|
+
class="cell footer-cell${classMap(cellParts)}"
|
|
235
|
+
style="${styleMap({
|
|
236
|
+
width: column.width,
|
|
237
|
+
'flex-grow': column.flexGrow,
|
|
238
|
+
})}"
|
|
239
|
+
?first-column="${isFirstCell}"
|
|
240
|
+
?last-column="${isLastCell}"
|
|
241
|
+
@keydown="${this.__onCellKeyDown}"
|
|
242
|
+
@mousedown=${this.__onCellMouseDown}
|
|
243
|
+
@mouseenter=${this.__onCellMouseEnter}
|
|
244
|
+
@mouseleave=${this.__onCellMouseLeave}
|
|
245
|
+
colspan="${ifDefined(column._colSpan)}"
|
|
246
|
+
aria-colspan="${ifDefined(column._colSpan)}"
|
|
247
|
+
tabindex="-1"
|
|
248
|
+
._column=${column}
|
|
249
|
+
>
|
|
250
|
+
${cellContent(this, `vaadin-grid-footer-cell-content-${level}-${column._id}`, {
|
|
251
|
+
textAlign: column.textAlign,
|
|
252
|
+
})}
|
|
253
|
+
</td>
|
|
254
|
+
`);
|
|
255
|
+
},
|
|
256
|
+
)}
|
|
257
|
+
</tr>
|
|
258
|
+
`;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
#getRows(columnTree, section) {
|
|
262
|
+
let rows = columnTree.map((columns, level) => {
|
|
263
|
+
const visibleColumns = columns.filter((column) => !column.hidden);
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
level,
|
|
267
|
+
cells: columns.map((column) => {
|
|
268
|
+
return {
|
|
269
|
+
column,
|
|
270
|
+
isFirstCell: column === visibleColumns.at(0),
|
|
271
|
+
isLastCell: column === visibleColumns.at(-1),
|
|
272
|
+
isContentCell: isContentCell(column, level, columnTree),
|
|
273
|
+
};
|
|
274
|
+
}),
|
|
275
|
+
isRowVisible:
|
|
276
|
+
section === 'header'
|
|
277
|
+
? isHeaderRowVisible(columns, level, columnTree)
|
|
278
|
+
: isFooterRowVisible(columns, level, columnTree),
|
|
279
|
+
};
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
if (section === 'footer') {
|
|
283
|
+
rows = rows.toReversed();
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const visibleRows = rows.filter((row) => row.isRowVisible);
|
|
287
|
+
|
|
288
|
+
return rows.map((row) => {
|
|
289
|
+
return {
|
|
290
|
+
...row,
|
|
291
|
+
isFirstRow: row === visibleRows.at(0),
|
|
292
|
+
isLastRow: row === visibleRows.at(-1),
|
|
293
|
+
};
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
};
|
|
@@ -154,9 +154,7 @@ export const KeyboardNavigationMixin = (superClass) =>
|
|
|
154
154
|
|
|
155
155
|
/** @private */
|
|
156
156
|
_focusableChanged(focusable, oldFocusable) {
|
|
157
|
-
|
|
158
|
-
oldFocusable.setAttribute('tabindex', '-1');
|
|
159
|
-
}
|
|
157
|
+
oldFocusable?.setAttribute('tabindex', '-1');
|
|
160
158
|
if (focusable) {
|
|
161
159
|
this._updateGridSectionFocusTarget(focusable);
|
|
162
160
|
}
|
|
@@ -415,9 +413,7 @@ export const KeyboardNavigationMixin = (superClass) =>
|
|
|
415
413
|
_onRowNavigation(activeRow, dy) {
|
|
416
414
|
const { dstRow } = this.__navigateRows(dy, activeRow);
|
|
417
415
|
|
|
418
|
-
|
|
419
|
-
dstRow.focus();
|
|
420
|
-
}
|
|
416
|
+
dstRow?.focus();
|
|
421
417
|
}
|
|
422
418
|
|
|
423
419
|
/** @private */
|
|
@@ -765,7 +761,7 @@ export const KeyboardNavigationMixin = (superClass) =>
|
|
|
765
761
|
// When clicking a cell with only text nodes, skip activating the cell
|
|
766
762
|
// on click, since that is already handled on keydown.
|
|
767
763
|
const cell = e.composedPath()[0];
|
|
768
|
-
const target =
|
|
764
|
+
const target = cell._content?.firstElementChild || cell;
|
|
769
765
|
const wasNavigating = this.hasAttribute('navigating');
|
|
770
766
|
const clickEvent = new MouseEvent('click', {
|
|
771
767
|
shiftKey: e.shiftKey,
|
package/src/vaadin-grid-mixin.js
CHANGED
|
@@ -13,7 +13,6 @@ import { A11yMixin } from './vaadin-grid-a11y-mixin.js';
|
|
|
13
13
|
import { ActiveItemMixin } from './vaadin-grid-active-item-mixin.js';
|
|
14
14
|
import { ArrayDataProviderMixin } from './vaadin-grid-array-data-provider-mixin.js';
|
|
15
15
|
import { ColumnAutoWidthMixin } from './vaadin-grid-column-auto-width-mixin.js';
|
|
16
|
-
import { ColumnRenderingMixin } from './vaadin-grid-column-rendering-mixin.js';
|
|
17
16
|
import { ColumnReorderingMixin } from './vaadin-grid-column-reordering-mixin.js';
|
|
18
17
|
import { ColumnResizingMixin } from './vaadin-grid-column-resizing-mixin.js';
|
|
19
18
|
import { DataProviderMixin } from './vaadin-grid-data-provider-mixin.js';
|
|
@@ -21,6 +20,7 @@ import { DragAndDropMixin } from './vaadin-grid-drag-and-drop-mixin.js';
|
|
|
21
20
|
import { DynamicColumnsMixin } from './vaadin-grid-dynamic-columns-mixin.js';
|
|
22
21
|
import { EventContextMixin } from './vaadin-grid-event-context-mixin.js';
|
|
23
22
|
import { FilterMixin } from './vaadin-grid-filter-mixin.js';
|
|
23
|
+
import { HeaderFooterRenderingMixin } from './vaadin-grid-header-footer-rendering-mixin.js';
|
|
24
24
|
import {
|
|
25
25
|
getBodyRowCells,
|
|
26
26
|
getClosestCell,
|
|
@@ -47,7 +47,7 @@ export const GridMixin = (superClass) =>
|
|
|
47
47
|
ArrayDataProviderMixin(
|
|
48
48
|
DataProviderMixin(
|
|
49
49
|
DynamicColumnsMixin(
|
|
50
|
-
|
|
50
|
+
HeaderFooterRenderingMixin(
|
|
51
51
|
ActiveItemMixin(
|
|
52
52
|
ScrollMixin(
|
|
53
53
|
SelectionMixin(
|
|
@@ -152,13 +152,13 @@ export const GridMixin = (superClass) =>
|
|
|
152
152
|
/** @private */
|
|
153
153
|
get _firstVisibleIndex() {
|
|
154
154
|
const firstVisibleItem = this.__getFirstVisibleItem();
|
|
155
|
-
return firstVisibleItem
|
|
155
|
+
return firstVisibleItem?.index;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
/** @private */
|
|
159
159
|
get _lastVisibleIndex() {
|
|
160
160
|
const lastVisibleItem = this.__getLastVisibleItem();
|
|
161
|
-
return lastVisibleItem
|
|
161
|
+
return lastVisibleItem?.index;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
constructor() {
|
|
@@ -247,13 +247,6 @@ export const GridMixin = (superClass) =>
|
|
|
247
247
|
// otherwise be triggered by this logic because it reads the row height
|
|
248
248
|
// right after updating the rows' content.
|
|
249
249
|
__disableHeightPlaceholder: true,
|
|
250
|
-
// The virtualizer amortizes scroller height updates to avoid reflows while
|
|
251
|
-
// scrolling. In `allRowsVisible` mode the grid has no scrolling and its
|
|
252
|
-
// height must track the content exactly, so tell the virtualizer to always
|
|
253
|
-
// apply the scroller height. Otherwise the items container can be left at a
|
|
254
|
-
// stale, too-small height and clip rows when the grid grows (e.g. when
|
|
255
|
-
// expanding a tree grid from a small size).
|
|
256
|
-
__alwaysUpdateScrollerSize: () => this.allRowsVisible,
|
|
257
250
|
});
|
|
258
251
|
|
|
259
252
|
this._tooltipController = new TooltipController(this);
|
|
@@ -305,9 +298,7 @@ export const GridMixin = (superClass) =>
|
|
|
305
298
|
__focusBodyCell({ item, column }) {
|
|
306
299
|
const row = this._getRenderedRows().find((row) => row._item === item);
|
|
307
300
|
const cell = row && [...row.children].find((cell) => cell._column === column);
|
|
308
|
-
|
|
309
|
-
cell.focus();
|
|
310
|
-
}
|
|
301
|
+
cell?.focus();
|
|
311
302
|
}
|
|
312
303
|
|
|
313
304
|
/** @protected */
|
|
@@ -597,7 +588,6 @@ export const GridMixin = (superClass) =>
|
|
|
597
588
|
|
|
598
589
|
this._resizeHandler();
|
|
599
590
|
this._frozenCellsChanged();
|
|
600
|
-
this._updateFirstAndLastColumn();
|
|
601
591
|
this._resetKeyboardNavigation();
|
|
602
592
|
this.__a11yUpdateHeaderRows();
|
|
603
593
|
this.__a11yUpdateFooterRows();
|
|
@@ -605,22 +595,6 @@ export const GridMixin = (superClass) =>
|
|
|
605
595
|
this.__updateHeaderAndFooter();
|
|
606
596
|
}
|
|
607
597
|
|
|
608
|
-
/** @private */
|
|
609
|
-
__updateHeaderFooterRowParts(section) {
|
|
610
|
-
const visibleRows = [...this.$[section].querySelectorAll('tr:not([hidden])')];
|
|
611
|
-
[...this.$[section].children].forEach((row) => {
|
|
612
|
-
updatePart(row, `first-${section}-row`, row === visibleRows.at(0));
|
|
613
|
-
updatePart(row, `last-${section}-row`, row === visibleRows.at(-1));
|
|
614
|
-
|
|
615
|
-
getBodyRowCells(row).forEach((cell) => {
|
|
616
|
-
updatePart(cell, `first-${section}-row-cell`, row === visibleRows.at(0));
|
|
617
|
-
updatePart(cell, `last-${section}-row-cell`, row === visibleRows.at(-1));
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
this._updateFirstAndLastColumnForRow(row);
|
|
621
|
-
});
|
|
622
|
-
}
|
|
623
|
-
|
|
624
598
|
/**
|
|
625
599
|
* @param {!HTMLElement} row
|
|
626
600
|
* @param {boolean} loading
|
|
@@ -180,7 +180,7 @@ export const RowDetailsMixin = (superClass) =>
|
|
|
180
180
|
* @protected
|
|
181
181
|
*/
|
|
182
182
|
_isDetailsOpened(item) {
|
|
183
|
-
return this.__detailsOpenedKeys
|
|
183
|
+
return this.__detailsOpenedKeys?.has(this.getItemId(item));
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
/** @private */
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { microTask, timeOut } from '@vaadin/component-base/src/async.js';
|
|
7
7
|
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
8
8
|
import { getNormalizedScrollLeft } from '@vaadin/component-base/src/dir-utils.js';
|
|
9
|
+
import { setOrRemoveAttribute } from '@vaadin/component-base/src/dom-utils.js';
|
|
9
10
|
import { OverflowController } from '@vaadin/component-base/src/overflow-controller.js';
|
|
10
11
|
|
|
11
12
|
const timeouts = {
|
|
@@ -377,11 +378,7 @@ export const ScrollMixin = (superClass) =>
|
|
|
377
378
|
|
|
378
379
|
/** @private */
|
|
379
380
|
__columnRenderingChanged(_columnTree, columnRendering) {
|
|
380
|
-
|
|
381
|
-
this.$.scroller.removeAttribute('column-rendering');
|
|
382
|
-
} else {
|
|
383
|
-
this.$.scroller.setAttribute('column-rendering', columnRendering);
|
|
384
|
-
}
|
|
381
|
+
setOrRemoveAttribute(this.$.scroller, 'column-rendering', columnRendering !== 'eager' && columnRendering);
|
|
385
382
|
|
|
386
383
|
this.__updateColumnsBodyContentHidden();
|
|
387
384
|
}
|
|
@@ -174,8 +174,8 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
|
|
|
174
174
|
this._headerCell.appendChild(label);
|
|
175
175
|
}
|
|
176
176
|
label.textContent = selectAllUnavailable;
|
|
177
|
-
} else
|
|
178
|
-
label
|
|
177
|
+
} else {
|
|
178
|
+
label?.remove();
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
@@ -383,7 +383,7 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
|
|
|
383
383
|
|
|
384
384
|
// Get the index of the row being hovered over or the first/last
|
|
385
385
|
// visible row if hovering outside the grid
|
|
386
|
-
let hoveredIndex = hoveredRow
|
|
386
|
+
let hoveredIndex = hoveredRow?.index;
|
|
387
387
|
const scrollableArea = this.__getScrollableArea();
|
|
388
388
|
if (this.__dragCurrentY < scrollableArea.top) {
|
|
389
389
|
hoveredIndex = this._grid._firstVisibleIndex;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Copyright (c) 2016 - 2026 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
+
import { setOrRemoveAttribute } from '@vaadin/component-base/src/dom-utils.js';
|
|
6
7
|
import { getClosestCell } from './vaadin-grid-helpers.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -97,11 +98,7 @@ export const GridSorterMixin = (superClass) =>
|
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
const ariaLabel = grid.__effectiveI18n.sorter?.replace('{column}', this.textContent.trim());
|
|
100
|
-
|
|
101
|
-
this.setAttribute('aria-label', ariaLabel);
|
|
102
|
-
} else {
|
|
103
|
-
this.removeAttribute('aria-label');
|
|
104
|
-
}
|
|
101
|
+
setOrRemoveAttribute(this, 'aria-label', ariaLabel);
|
|
105
102
|
}
|
|
106
103
|
|
|
107
104
|
/** @private */
|
|
@@ -51,6 +51,7 @@ import { GridSorterMixin } from './vaadin-grid-sorter-mixin.js';
|
|
|
51
51
|
* @fires {CustomEvent} direction-changed - Fired when the `direction` property changes.
|
|
52
52
|
* @fires {CustomEvent} sorter-changed - Fired when the `path` or `direction` property changes.
|
|
53
53
|
*
|
|
54
|
+
* @attr {string} theme - The theme variants to apply to the component.
|
|
54
55
|
* @customElement vaadin-grid-sorter
|
|
55
56
|
* @extends HTMLElement
|
|
56
57
|
*/
|
|
@@ -59,6 +59,7 @@ import { GridTreeToggleMixin } from './vaadin-grid-tree-toggle-mixin.js';
|
|
|
59
59
|
*
|
|
60
60
|
* @fires {CustomEvent} expanded-changed - Fired when the `expanded` property changes.
|
|
61
61
|
*
|
|
62
|
+
* @attr {string} theme - The theme variants to apply to the component.
|
|
62
63
|
* @customElement vaadin-grid-tree-toggle
|
|
63
64
|
* @extends HTMLElement
|
|
64
65
|
*/
|
package/src/vaadin-grid.js
CHANGED
|
@@ -274,6 +274,7 @@ const DEFAULT_I18N = {
|
|
|
274
274
|
* @fires {CustomEvent} size-changed - Fired when the `size` property changes.
|
|
275
275
|
* @fires {CustomEvent} item-toggle - Fired when the user selects or deselects an item through the selection column.
|
|
276
276
|
*
|
|
277
|
+
* @attr {string} theme - The theme variants to apply to the component.
|
|
277
278
|
* @customElement vaadin-grid
|
|
278
279
|
* @extends HTMLElement
|
|
279
280
|
*/
|