@vaadin/grid 25.0.0-alpha1 → 25.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.
- package/all-imports.js +1 -1
- package/package.json +12 -13
- package/src/array-data-provider.js +6 -0
- package/src/lit/column-renderer-directives.d.ts +0 -1
- package/src/styles/vaadin-grid-base-styles.d.ts +8 -0
- package/src/styles/vaadin-grid-base-styles.js +510 -0
- package/src/styles/vaadin-grid-filter-base-styles.d.ts +8 -0
- package/src/styles/vaadin-grid-filter-base-styles.js +18 -0
- package/src/styles/vaadin-grid-sorter-base-styles.d.ts +8 -0
- package/src/styles/vaadin-grid-sorter-base-styles.js +63 -0
- package/src/styles/vaadin-grid-tree-toggle-base-styles.d.ts +8 -0
- package/src/styles/vaadin-grid-tree-toggle-base-styles.js +76 -0
- package/src/vaadin-grid-a11y-mixin.js +14 -8
- package/src/vaadin-grid-column-auto-width-mixin.js +8 -2
- package/src/vaadin-grid-data-provider-mixin.js +19 -76
- package/src/vaadin-grid-drag-and-drop-mixin.js +3 -0
- package/src/vaadin-grid-filter-element-mixin.js +0 -17
- package/src/vaadin-grid-filter.js +7 -1
- package/src/vaadin-grid-keyboard-navigation-mixin.js +1 -1
- package/src/vaadin-grid-mixin.js +51 -28
- package/src/vaadin-grid-row-details-mixin.js +4 -4
- package/src/vaadin-grid-scroll-mixin.js +52 -21
- package/src/vaadin-grid-sorter-mixin.js +0 -60
- package/src/vaadin-grid-sorter.js +7 -1
- package/src/vaadin-grid-tree-toggle-mixin.js +0 -77
- package/src/vaadin-grid-tree-toggle.js +9 -1
- package/src/vaadin-grid.d.ts +1 -1
- package/src/vaadin-grid.js +4 -3
- package/vaadin-grid-column-group.js +1 -1
- package/vaadin-grid-column.js +1 -1
- package/vaadin-grid-filter-column.js +1 -1
- package/vaadin-grid-filter.js +1 -1
- package/vaadin-grid-selection-column.js +1 -1
- package/vaadin-grid-sort-column.js +1 -1
- package/vaadin-grid-sorter.js +1 -1
- package/vaadin-grid-tree-column.js +1 -1
- package/vaadin-grid-tree-toggle.js +1 -1
- package/vaadin-grid.js +1 -1
- package/web-types.json +4 -4
- package/web-types.lit.json +4 -4
- package/src/vaadin-grid-styles.js +0 -389
- package/theme/lumo/all-imports.d.ts +0 -11
- package/theme/lumo/all-imports.js +0 -11
- package/theme/lumo/vaadin-grid-column-group.d.ts +0 -1
- package/theme/lumo/vaadin-grid-column-group.js +0 -1
- package/theme/lumo/vaadin-grid-column.d.ts +0 -1
- package/theme/lumo/vaadin-grid-column.js +0 -1
- package/theme/lumo/vaadin-grid-filter-column.d.ts +0 -2
- package/theme/lumo/vaadin-grid-filter-column.js +0 -2
- package/theme/lumo/vaadin-grid-filter.d.ts +0 -2
- package/theme/lumo/vaadin-grid-filter.js +0 -2
- package/theme/lumo/vaadin-grid-selection-column.d.ts +0 -2
- package/theme/lumo/vaadin-grid-selection-column.js +0 -2
- package/theme/lumo/vaadin-grid-sort-column.d.ts +0 -2
- package/theme/lumo/vaadin-grid-sort-column.js +0 -2
- package/theme/lumo/vaadin-grid-sorter-styles.d.ts +0 -3
- package/theme/lumo/vaadin-grid-sorter-styles.js +0 -52
- package/theme/lumo/vaadin-grid-sorter.d.ts +0 -2
- package/theme/lumo/vaadin-grid-sorter.js +0 -2
- package/theme/lumo/vaadin-grid-styles.d.ts +0 -6
- package/theme/lumo/vaadin-grid-styles.js +0 -405
- package/theme/lumo/vaadin-grid-tree-column.d.ts +0 -2
- package/theme/lumo/vaadin-grid-tree-column.js +0 -2
- package/theme/lumo/vaadin-grid-tree-toggle-styles.d.ts +0 -3
- package/theme/lumo/vaadin-grid-tree-toggle-styles.js +0 -81
- package/theme/lumo/vaadin-grid-tree-toggle.d.ts +0 -2
- package/theme/lumo/vaadin-grid-tree-toggle.js +0 -2
- package/theme/lumo/vaadin-grid.d.ts +0 -2
- package/theme/lumo/vaadin-grid.js +0 -2
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2016 - 2025 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import '@vaadin/component-base/src/styles/style-props.js';
|
|
7
|
+
import { css } from 'lit';
|
|
8
|
+
|
|
9
|
+
export const gridTreeToggleStyles = css`
|
|
10
|
+
:host {
|
|
11
|
+
display: flex;
|
|
12
|
+
max-width: 100%;
|
|
13
|
+
pointer-events: none;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Don't expand/collapse when clicking #level-spacer */
|
|
17
|
+
[part] {
|
|
18
|
+
pointer-events: auto;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
:host([hidden]) {
|
|
22
|
+
display: none !important;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:host(:not([leaf])) {
|
|
26
|
+
cursor: var(--vaadin-clickable-cursor);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#level-spacer,
|
|
30
|
+
[part='toggle'] {
|
|
31
|
+
flex: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#level-spacer {
|
|
35
|
+
width: calc(var(--_level, 0) * var(--vaadin-grid-tree-toggle-level-offset, 16px));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
[part='toggle'] {
|
|
39
|
+
margin-inline-end: var(--vaadin-gap-container-inline);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
[part='toggle']::before {
|
|
43
|
+
content: '';
|
|
44
|
+
display: block;
|
|
45
|
+
width: var(--vaadin-icon-size, 1lh);
|
|
46
|
+
height: var(--vaadin-icon-size, 1lh);
|
|
47
|
+
background: currentColor;
|
|
48
|
+
mask-image: var(--_vaadin-icon-chevron-down);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
:host(:not([expanded])) [part='toggle']::before {
|
|
52
|
+
rotate: -90deg;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
56
|
+
[part='toggle']::before {
|
|
57
|
+
transition: rotate 120ms;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
:host([leaf]) [part='toggle'] {
|
|
62
|
+
visibility: hidden;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
slot {
|
|
66
|
+
display: block;
|
|
67
|
+
overflow: hidden;
|
|
68
|
+
text-overflow: ellipsis;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@media (forced-colors: active) {
|
|
72
|
+
[part='toggle']::before {
|
|
73
|
+
background: CanvasText;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
`;
|
|
@@ -22,7 +22,7 @@ export const A11yMixin = (superClass) =>
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
static get observers() {
|
|
25
|
-
return ['_a11yUpdateGridSize(size, _columnTree)'];
|
|
25
|
+
return ['_a11yUpdateGridSize(size, _columnTree, __emptyState)'];
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/** @private */
|
|
@@ -34,21 +34,27 @@ export const A11yMixin = (superClass) =>
|
|
|
34
34
|
|
|
35
35
|
/** @private */
|
|
36
36
|
_a11yGetFooterRowCount(_columnTree) {
|
|
37
|
-
return _columnTree.filter((level) => level.some((col) => col.
|
|
37
|
+
return _columnTree.filter((level) => level.some((col) => col.footerRenderer)).length;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/** @private */
|
|
41
|
-
_a11yUpdateGridSize(size, _columnTree) {
|
|
41
|
+
_a11yUpdateGridSize(size, _columnTree, emptyState) {
|
|
42
42
|
if (size === undefined || _columnTree === undefined) {
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
const headerRowsCount = this._a11yGetHeaderRowCount(_columnTree);
|
|
47
|
+
const footerRowsCount = this._a11yGetFooterRowCount(_columnTree);
|
|
48
|
+
const bodyRowsCount = emptyState ? 1 : size;
|
|
49
|
+
const rowsCount = bodyRowsCount + headerRowsCount + footerRowsCount;
|
|
50
|
+
|
|
51
|
+
this.$.table.setAttribute('aria-rowcount', rowsCount);
|
|
52
|
+
|
|
46
53
|
const bodyColumns = _columnTree[_columnTree.length - 1];
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
);
|
|
51
|
-
this.$.table.setAttribute('aria-colcount', (bodyColumns && bodyColumns.length) || 0);
|
|
54
|
+
// If no header and footer rows while the empty state is active, count as one column
|
|
55
|
+
// Otherwise, use the number of body columns, if present
|
|
56
|
+
const columnsCount = emptyState ? 1 : (rowsCount && bodyColumns && bodyColumns.length) || 0;
|
|
57
|
+
this.$.table.setAttribute('aria-colcount', columnsCount);
|
|
52
58
|
|
|
53
59
|
this._a11yUpdateHeaderRows();
|
|
54
60
|
this._a11yUpdateFooterRows();
|
|
@@ -59,9 +59,15 @@ export const ColumnAutoWidthMixin = (superClass) =>
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/** @private */
|
|
62
|
-
__flatSizeChangedAutoWidth() {
|
|
62
|
+
__flatSizeChangedAutoWidth(flatSize) {
|
|
63
63
|
// Flat size changed, recalculate column widths if pending (asynchronously, to allow grid to render row elements first)
|
|
64
|
-
requestAnimationFrame(() =>
|
|
64
|
+
requestAnimationFrame(() => {
|
|
65
|
+
if (!!flatSize && !this.__hasHadRenderedRowsForColumnWidthCalculation) {
|
|
66
|
+
this.recalculateColumnWidths();
|
|
67
|
+
} else {
|
|
68
|
+
this.__tryToRecalculateColumnWidthsIfPending();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
/**
|
|
@@ -7,7 +7,6 @@ import { microTask, timeOut } from '@vaadin/component-base/src/async.js';
|
|
|
7
7
|
import { DataProviderController } from '@vaadin/component-base/src/data-provider-controller/data-provider-controller.js';
|
|
8
8
|
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
9
9
|
import { get } from '@vaadin/component-base/src/path-utils.js';
|
|
10
|
-
import { getBodyRowCells, updateCellsPart, updateState } from './vaadin-grid-helpers.js';
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* @polymerMixin
|
|
@@ -166,24 +165,6 @@ export const DataProviderMixin = (superClass) =>
|
|
|
166
165
|
this._dataProviderController.addEventListener('page-loaded', this._onDataProviderPageLoaded.bind(this));
|
|
167
166
|
}
|
|
168
167
|
|
|
169
|
-
/**
|
|
170
|
-
* @protected
|
|
171
|
-
* @deprecated since 24.3 and will be removed in Vaadin 25.
|
|
172
|
-
*/
|
|
173
|
-
get _cache() {
|
|
174
|
-
console.warn('<vaadin-grid> The `_cache` property is deprecated and will be removed in Vaadin 25.');
|
|
175
|
-
return this._dataProviderController.rootCache;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* @protected
|
|
180
|
-
* @deprecated since 24.3 and will be removed in Vaadin 25.
|
|
181
|
-
*/
|
|
182
|
-
get _effectiveSize() {
|
|
183
|
-
console.warn('<vaadin-grid> The `_effectiveSize` property is deprecated and will be removed in Vaadin 25.');
|
|
184
|
-
return this._flatSize;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
168
|
/** @private */
|
|
188
169
|
_sizeChanged(size) {
|
|
189
170
|
this._dataProviderController.rootCache.size = size;
|
|
@@ -200,46 +181,20 @@ export const DataProviderMixin = (superClass) =>
|
|
|
200
181
|
this.requestContentUpdate();
|
|
201
182
|
}
|
|
202
183
|
|
|
203
|
-
/**
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
*/
|
|
208
|
-
_getItem(index, el) {
|
|
209
|
-
el.index = index;
|
|
210
|
-
|
|
211
|
-
const { item } = this._dataProviderController.getFlatIndexContext(index);
|
|
212
|
-
if (item) {
|
|
213
|
-
this.__updateLoading(el, false);
|
|
214
|
-
this._updateItem(el, item);
|
|
215
|
-
if (this._isExpanded(item)) {
|
|
216
|
-
this._dataProviderController.ensureFlatIndexHierarchy(index);
|
|
217
|
-
}
|
|
218
|
-
} else {
|
|
219
|
-
this.__updateLoading(el, true);
|
|
220
|
-
this._dataProviderController.ensureFlatIndexLoaded(index);
|
|
221
|
-
}
|
|
184
|
+
/** @private */
|
|
185
|
+
__getRowItem(row) {
|
|
186
|
+
const { item } = this._dataProviderController.getFlatIndexContext(row.index);
|
|
187
|
+
return item;
|
|
222
188
|
}
|
|
223
189
|
|
|
224
|
-
/**
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
*/
|
|
229
|
-
__updateLoading(row, loading) {
|
|
230
|
-
const cells = getBodyRowCells(row);
|
|
231
|
-
|
|
232
|
-
// Row state attribute
|
|
233
|
-
updateState(row, 'loading', loading);
|
|
234
|
-
|
|
235
|
-
// Cells part attribute
|
|
236
|
-
updateCellsPart(cells, 'loading-row-cell', loading);
|
|
190
|
+
/** @private */
|
|
191
|
+
__ensureRowItem(row) {
|
|
192
|
+
this._dataProviderController.ensureFlatIndexLoaded(row.index);
|
|
193
|
+
}
|
|
237
194
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
this._generateCellPartNames(row);
|
|
242
|
-
}
|
|
195
|
+
/** @private */
|
|
196
|
+
__ensureRowHierarchy(row) {
|
|
197
|
+
this._dataProviderController.ensureFlatIndexHierarchy(row.index);
|
|
243
198
|
}
|
|
244
199
|
|
|
245
200
|
/**
|
|
@@ -309,17 +264,6 @@ export const DataProviderMixin = (superClass) =>
|
|
|
309
264
|
return level;
|
|
310
265
|
}
|
|
311
266
|
|
|
312
|
-
/**
|
|
313
|
-
* @param {number} page
|
|
314
|
-
* @param {ItemCache} cache
|
|
315
|
-
* @protected
|
|
316
|
-
* @deprecated since 24.3 and will be removed in Vaadin 25.
|
|
317
|
-
*/
|
|
318
|
-
_loadPage(page, cache) {
|
|
319
|
-
console.warn('<vaadin-grid> The `_loadPage` method is deprecated and will be removed in Vaadin 25.');
|
|
320
|
-
this._dataProviderController.__loadCachePage(cache, page);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
267
|
/** @protected */
|
|
324
268
|
_onDataProviderPageRequested() {
|
|
325
269
|
this._setLoading(true);
|
|
@@ -331,7 +275,7 @@ export const DataProviderMixin = (superClass) =>
|
|
|
331
275
|
if (this._flatSize !== this._dataProviderController.flatSize) {
|
|
332
276
|
// Schedule an update of all rendered rows by _debouncerApplyCachedData,
|
|
333
277
|
// to ensure that all pages associated with the rendered rows are loaded.
|
|
334
|
-
this.
|
|
278
|
+
this._shouldLoadAllRenderedRowsAfterPageLoad = true;
|
|
335
279
|
|
|
336
280
|
// TODO: Updating the flat size property can still result in a synchonous virtualizer update
|
|
337
281
|
// if the size change requires the virtualizer to increase the amount of physical elements
|
|
@@ -341,9 +285,7 @@ export const DataProviderMixin = (superClass) =>
|
|
|
341
285
|
}
|
|
342
286
|
|
|
343
287
|
// After updating the cache, check if some of the expanded items should have sub-caches loaded
|
|
344
|
-
this._getRenderedRows().forEach((row) =>
|
|
345
|
-
this._dataProviderController.ensureFlatIndexHierarchy(row.index);
|
|
346
|
-
});
|
|
288
|
+
this._getRenderedRows().forEach((row) => this.__ensureRowHierarchy(row));
|
|
347
289
|
|
|
348
290
|
this._hasData = true;
|
|
349
291
|
}
|
|
@@ -354,13 +296,14 @@ export const DataProviderMixin = (superClass) =>
|
|
|
354
296
|
this._debouncerApplyCachedData = Debouncer.debounce(this._debouncerApplyCachedData, timeOut.after(0), () => {
|
|
355
297
|
this._setLoading(false);
|
|
356
298
|
|
|
357
|
-
const
|
|
358
|
-
this.
|
|
299
|
+
const shouldLoadAllRenderedRowsAfterPageLoad = this._shouldLoadAllRenderedRowsAfterPageLoad;
|
|
300
|
+
this._shouldLoadAllRenderedRowsAfterPageLoad = false;
|
|
359
301
|
|
|
360
302
|
this._getRenderedRows().forEach((row) => {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
303
|
+
this.__updateRow(row);
|
|
304
|
+
|
|
305
|
+
if (shouldLoadAllRenderedRowsAfterPageLoad) {
|
|
306
|
+
this.__ensureRowItem(row);
|
|
364
307
|
}
|
|
365
308
|
});
|
|
366
309
|
|
|
@@ -247,6 +247,9 @@ export const DragAndDropMixin = (superClass) =>
|
|
|
247
247
|
|
|
248
248
|
let row = e.composedPath().find((node) => node.localName === 'tr');
|
|
249
249
|
|
|
250
|
+
// Update the horizontal scroll position property of the row being dragged over
|
|
251
|
+
this.__updateRowScrollPositionProperty(row);
|
|
252
|
+
|
|
250
253
|
if (!this._flatSize || this.dropMode === DropMode.ON_GRID) {
|
|
251
254
|
// The grid is empty or "on-grid" drop mode was used, always default to "empty"
|
|
252
255
|
this._dropLocation = DropLocation.EMPTY;
|
|
@@ -6,23 +6,6 @@
|
|
|
6
6
|
import { timeOut } from '@vaadin/component-base/src/async.js';
|
|
7
7
|
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
8
8
|
import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
|
|
9
|
-
import { css, registerStyles } from '@vaadin/vaadin-themable-mixin';
|
|
10
|
-
|
|
11
|
-
registerStyles(
|
|
12
|
-
'vaadin-grid-filter',
|
|
13
|
-
css`
|
|
14
|
-
:host {
|
|
15
|
-
display: inline-flex;
|
|
16
|
-
max-width: 100%;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
::slotted(*) {
|
|
20
|
-
width: 100%;
|
|
21
|
-
box-sizing: border-box;
|
|
22
|
-
}
|
|
23
|
-
`,
|
|
24
|
-
{ moduleId: 'vaadin-grid-filter-styles' },
|
|
25
|
-
);
|
|
26
9
|
|
|
27
10
|
/**
|
|
28
11
|
* @polymerMixin
|
|
@@ -8,6 +8,8 @@ import { html, LitElement } from 'lit';
|
|
|
8
8
|
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
|
|
9
9
|
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
|
|
10
10
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin';
|
|
11
|
+
import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
|
|
12
|
+
import { gridFilterStyles } from './styles/vaadin-grid-filter-base-styles.js';
|
|
11
13
|
import { GridFilterElementMixin } from './vaadin-grid-filter-element-mixin.js';
|
|
12
14
|
|
|
13
15
|
/**
|
|
@@ -39,11 +41,15 @@ import { GridFilterElementMixin } from './vaadin-grid-filter-element-mixin.js';
|
|
|
39
41
|
* @extends HTMLElement
|
|
40
42
|
* @mixes GridFilterElementMixin
|
|
41
43
|
*/
|
|
42
|
-
class GridFilter extends GridFilterElementMixin(ThemableMixin(PolylitMixin(LitElement))) {
|
|
44
|
+
class GridFilter extends GridFilterElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))) {
|
|
43
45
|
static get is() {
|
|
44
46
|
return 'vaadin-grid-filter';
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
static get styles() {
|
|
50
|
+
return gridFilterStyles;
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
/** @protected */
|
|
48
54
|
render() {
|
|
49
55
|
return html`<slot></slot>`;
|
package/src/vaadin-grid-mixin.js
CHANGED
|
@@ -5,15 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { TabindexMixin } from '@vaadin/a11y-base/src/tabindex-mixin.js';
|
|
7
7
|
import { animationFrame, microTask } from '@vaadin/component-base/src/async.js';
|
|
8
|
-
import {
|
|
9
|
-
isAndroid,
|
|
10
|
-
isChrome,
|
|
11
|
-
isFirefox,
|
|
12
|
-
isIOS,
|
|
13
|
-
isSafari,
|
|
14
|
-
isTouch,
|
|
15
|
-
supportsAdoptingStyleSheets,
|
|
16
|
-
} from '@vaadin/component-base/src/browser-utils.js';
|
|
8
|
+
import { isAndroid, isChrome, isFirefox, isIOS, isSafari, isTouch } from '@vaadin/component-base/src/browser-utils.js';
|
|
17
9
|
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
18
10
|
import { getClosestElement } from '@vaadin/component-base/src/dom-utils.js';
|
|
19
11
|
import { SlotObserver } from '@vaadin/component-base/src/slot-observer.js';
|
|
@@ -36,6 +28,7 @@ import {
|
|
|
36
28
|
iterateRowCells,
|
|
37
29
|
updateBooleanRowStates,
|
|
38
30
|
updateCellsPart,
|
|
31
|
+
updateState,
|
|
39
32
|
} from './vaadin-grid-helpers.js';
|
|
40
33
|
import { KeyboardNavigationMixin } from './vaadin-grid-keyboard-navigation-mixin.js';
|
|
41
34
|
import { RowDetailsMixin } from './vaadin-grid-row-details-mixin.js';
|
|
@@ -353,7 +346,7 @@ export const GridMixin = (superClass) =>
|
|
|
353
346
|
row.setAttribute('role', 'row');
|
|
354
347
|
row.setAttribute('tabindex', '-1');
|
|
355
348
|
if (this._columnTree) {
|
|
356
|
-
this.
|
|
349
|
+
this.__initRow(row, this._columnTree[this._columnTree.length - 1], 'body', false, true);
|
|
357
350
|
}
|
|
358
351
|
rows.push(row);
|
|
359
352
|
}
|
|
@@ -465,9 +458,9 @@ export const GridMixin = (superClass) =>
|
|
|
465
458
|
* @param {?string} section
|
|
466
459
|
* @param {boolean} isColumnRow
|
|
467
460
|
* @param {boolean} noNotify
|
|
468
|
-
* @
|
|
461
|
+
* @private
|
|
469
462
|
*/
|
|
470
|
-
|
|
463
|
+
__initRow(row, columns, section = 'body', isColumnRow = false, noNotify = false) {
|
|
471
464
|
const contentsFragment = document.createDocumentFragment();
|
|
472
465
|
|
|
473
466
|
iterateRowCells(row, (cell) => {
|
|
@@ -637,6 +630,7 @@ export const GridMixin = (superClass) =>
|
|
|
637
630
|
|
|
638
631
|
// Make sure the section has a tabbable element
|
|
639
632
|
this._resetKeyboardNavigation();
|
|
633
|
+
this._a11yUpdateGridSize(this.size, this._columnTree, this.__emptyState);
|
|
640
634
|
}
|
|
641
635
|
|
|
642
636
|
/** @private */
|
|
@@ -647,10 +641,15 @@ export const GridMixin = (superClass) =>
|
|
|
647
641
|
return;
|
|
648
642
|
}
|
|
649
643
|
|
|
644
|
+
row.index = index;
|
|
645
|
+
|
|
650
646
|
this._updateRowOrderParts(row, index);
|
|
651
647
|
|
|
652
648
|
this._a11yUpdateRowRowindex(row, index);
|
|
653
|
-
|
|
649
|
+
|
|
650
|
+
this.__ensureRowItem(row);
|
|
651
|
+
this.__ensureRowHierarchy(row);
|
|
652
|
+
this.__updateRow(row);
|
|
654
653
|
}
|
|
655
654
|
|
|
656
655
|
/** @private */
|
|
@@ -691,7 +690,7 @@ export const GridMixin = (superClass) =>
|
|
|
691
690
|
*/
|
|
692
691
|
_renderColumnTree(columnTree) {
|
|
693
692
|
iterateChildren(this.$.items, (row) => {
|
|
694
|
-
this.
|
|
693
|
+
this.__initRow(row, columnTree[columnTree.length - 1], 'body', false, true);
|
|
695
694
|
|
|
696
695
|
const model = this.__getRowModel(row);
|
|
697
696
|
this._updateRowOrderParts(row);
|
|
@@ -718,7 +717,7 @@ export const GridMixin = (superClass) =>
|
|
|
718
717
|
}
|
|
719
718
|
|
|
720
719
|
iterateChildren(this.$.header, (headerRow, index, rows) => {
|
|
721
|
-
this.
|
|
720
|
+
this.__initRow(headerRow, columnTree[index], 'header', index === columnTree.length - 1);
|
|
722
721
|
|
|
723
722
|
const cells = getBodyRowCells(headerRow);
|
|
724
723
|
updateCellsPart(cells, 'first-header-row-cell', index === 0);
|
|
@@ -726,7 +725,7 @@ export const GridMixin = (superClass) =>
|
|
|
726
725
|
});
|
|
727
726
|
|
|
728
727
|
iterateChildren(this.$.footer, (footerRow, index, rows) => {
|
|
729
|
-
this.
|
|
728
|
+
this.__initRow(footerRow, columnTree[columnTree.length - 1 - index], 'footer', index === 0);
|
|
730
729
|
|
|
731
730
|
const cells = getBodyRowCells(footerRow);
|
|
732
731
|
updateCellsPart(cells, 'first-footer-row-cell', index === 0);
|
|
@@ -734,7 +733,7 @@ export const GridMixin = (superClass) =>
|
|
|
734
733
|
});
|
|
735
734
|
|
|
736
735
|
// Sizer rows
|
|
737
|
-
this.
|
|
736
|
+
this.__initRow(this.$.sizer, columnTree[columnTree.length - 1]);
|
|
738
737
|
|
|
739
738
|
this._resizeHandler();
|
|
740
739
|
this._frozenCellsChanged();
|
|
@@ -749,10 +748,38 @@ export const GridMixin = (superClass) =>
|
|
|
749
748
|
|
|
750
749
|
/**
|
|
751
750
|
* @param {!HTMLElement} row
|
|
752
|
-
* @param {
|
|
753
|
-
* @
|
|
751
|
+
* @param {boolean} loading
|
|
752
|
+
* @private
|
|
754
753
|
*/
|
|
755
|
-
|
|
754
|
+
__updateRowLoading(row, loading) {
|
|
755
|
+
const cells = getBodyRowCells(row);
|
|
756
|
+
|
|
757
|
+
// Row state attribute
|
|
758
|
+
updateState(row, 'loading', loading);
|
|
759
|
+
|
|
760
|
+
// Cells part attribute
|
|
761
|
+
updateCellsPart(cells, 'loading-row-cell', loading);
|
|
762
|
+
|
|
763
|
+
if (loading) {
|
|
764
|
+
// Run style generators for the loading row to have custom names cleared
|
|
765
|
+
this._generateCellClassNames(row);
|
|
766
|
+
this._generateCellPartNames(row);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* @param {!HTMLElement} row
|
|
772
|
+
* @private
|
|
773
|
+
*/
|
|
774
|
+
__updateRow(row) {
|
|
775
|
+
const item = this.__getRowItem(row);
|
|
776
|
+
if (item) {
|
|
777
|
+
this.__updateRowLoading(row, false);
|
|
778
|
+
} else {
|
|
779
|
+
this.__updateRowLoading(row, true);
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
|
|
756
783
|
row._item = item;
|
|
757
784
|
const model = this.__getRowModel(row);
|
|
758
785
|
|
|
@@ -929,15 +956,11 @@ export const GridMixin = (superClass) =>
|
|
|
929
956
|
|
|
930
957
|
// The style is set to host instead of the scroller so that the value can be overridden by the user with "grid { min-height: 0 }"
|
|
931
958
|
// Prefer setting style in adopted style sheet to avoid the need to add a confusing inline style on the host element
|
|
932
|
-
|
|
933
|
-
if (!this.__minHeightStyleSheet && supportsAdoptingStyleSheets) {
|
|
959
|
+
if (!this.__minHeightStyleSheet) {
|
|
934
960
|
this.__minHeightStyleSheet = new CSSStyleSheet();
|
|
935
|
-
this.shadowRoot.adoptedStyleSheets
|
|
936
|
-
}
|
|
937
|
-
if (this.__minHeightStyleSheet) {
|
|
938
|
-
this.__minHeightStyleSheet.replaceSync(`:host { --_grid-min-height: ${minHeight}px; }`);
|
|
939
|
-
} else {
|
|
940
|
-
this.style.setProperty('--_grid-min-height', `${minHeight}px`);
|
|
961
|
+
this.shadowRoot.adoptedStyleSheets.push(this.__minHeightStyleSheet);
|
|
941
962
|
}
|
|
963
|
+
|
|
964
|
+
this.__minHeightStyleSheet.replaceSync(`:host { --_grid-min-height: ${minHeight}px; }`);
|
|
942
965
|
}
|
|
943
966
|
};
|
|
@@ -85,7 +85,7 @@ export const RowDetailsMixin = (superClass) =>
|
|
|
85
85
|
// Only update the rows if the column tree has already been initialized
|
|
86
86
|
iterateChildren(this.$.items, (row) => {
|
|
87
87
|
if (!row.querySelector('[part~=details-cell]')) {
|
|
88
|
-
this.
|
|
88
|
+
this.__initRow(row, this._columnTree[this._columnTree.length - 1]);
|
|
89
89
|
const isDetailsOpened = this._isDetailsOpened(row._item);
|
|
90
90
|
this._toggleDetailsCell(row, isDetailsOpened);
|
|
91
91
|
}
|
|
@@ -98,13 +98,13 @@ export const RowDetailsMixin = (superClass) =>
|
|
|
98
98
|
iterateChildren(this.$.items, (row) => {
|
|
99
99
|
// Re-renders the row to possibly close the previously opened details.
|
|
100
100
|
if (row.hasAttribute('details-opened')) {
|
|
101
|
-
this.
|
|
101
|
+
this.__updateRow(row);
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
// Re-renders the row to open the details when a row details renderer is provided.
|
|
106
106
|
if (rowDetailsRenderer && this._isDetailsOpened(row._item)) {
|
|
107
|
-
this.
|
|
107
|
+
this.__updateRow(row);
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
110
|
}
|
|
@@ -140,7 +140,7 @@ export const RowDetailsMixin = (superClass) =>
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
// Assigns a renderer when the details cell is opened.
|
|
143
|
-
// The details cell content is rendered later in the `
|
|
143
|
+
// The details cell content is rendered later in the `__updateRow` method.
|
|
144
144
|
if (this.rowDetailsRenderer) {
|
|
145
145
|
cell._renderer = this.rowDetailsRenderer;
|
|
146
146
|
}
|
|
@@ -122,10 +122,23 @@ export const ScrollMixin = (superClass) =>
|
|
|
122
122
|
const row = composedPath[composedPath.indexOf(this.$.items) - 1];
|
|
123
123
|
|
|
124
124
|
if (row) {
|
|
125
|
-
//
|
|
126
|
-
// Don't change scroll position if the user is interacting with the mouse
|
|
125
|
+
// Don't change scroll position if the user is interacting with the mouse.
|
|
127
126
|
if (!this._isMousedown) {
|
|
128
|
-
|
|
127
|
+
// Make sure the focused element (row, cell, or focusable element inside a cell)
|
|
128
|
+
// is inside the viewport. If the whole row fits into the viewport, then scroll
|
|
129
|
+
// the row into view. This ensures that labels, helper texts and other related
|
|
130
|
+
// elements of focusable elements within cells also become visible. When the row
|
|
131
|
+
// is larger than the viewport, scroll the focus event target into the viewport.
|
|
132
|
+
// This works better when focusing elements within cells, which could otherwise
|
|
133
|
+
// still be outside the viewport when scrolling to the top or bottom of the row.
|
|
134
|
+
const tableHeight = this.$.table.clientHeight;
|
|
135
|
+
const headerHeight = this.$.header.clientHeight;
|
|
136
|
+
const footerHeight = this.$.footer.clientHeight;
|
|
137
|
+
const viewportHeight = tableHeight - headerHeight - footerHeight;
|
|
138
|
+
const isRowLargerThanViewport = row.clientHeight > viewportHeight;
|
|
139
|
+
const scrollTarget = isRowLargerThanViewport ? e.target : row;
|
|
140
|
+
|
|
141
|
+
this.__scrollIntoViewport(scrollTarget);
|
|
129
142
|
}
|
|
130
143
|
|
|
131
144
|
if (!this.$.table.contains(e.relatedTarget)) {
|
|
@@ -171,25 +184,27 @@ export const ScrollMixin = (superClass) =>
|
|
|
171
184
|
_scrollToFlatIndex(index) {
|
|
172
185
|
index = Math.min(this._flatSize - 1, Math.max(0, index));
|
|
173
186
|
this.__virtualizer.scrollToIndex(index);
|
|
174
|
-
this.
|
|
187
|
+
const rowElement = [...this.$.items.children].find((child) => child.index === index);
|
|
188
|
+
this.__scrollIntoViewport(rowElement);
|
|
175
189
|
}
|
|
176
190
|
|
|
177
191
|
/**
|
|
178
|
-
* Makes sure the
|
|
179
|
-
*
|
|
192
|
+
* Makes sure the given element is fully inside the visible viewport,
|
|
193
|
+
* taking header/footer into account.
|
|
180
194
|
* @private
|
|
181
195
|
*/
|
|
182
|
-
__scrollIntoViewport(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
196
|
+
__scrollIntoViewport(element) {
|
|
197
|
+
if (!element) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const dstRect = element.getBoundingClientRect();
|
|
202
|
+
const footerTop = this.$.footer.getBoundingClientRect().top;
|
|
203
|
+
const headerBottom = this.$.header.getBoundingClientRect().bottom;
|
|
204
|
+
if (dstRect.bottom > footerTop) {
|
|
205
|
+
this.$.table.scrollTop += dstRect.bottom - footerTop;
|
|
206
|
+
} else if (dstRect.top < headerBottom) {
|
|
207
|
+
this.$.table.scrollTop -= headerBottom - dstRect.top;
|
|
193
208
|
}
|
|
194
209
|
}
|
|
195
210
|
|
|
@@ -476,6 +491,7 @@ export const ScrollMixin = (superClass) =>
|
|
|
476
491
|
|
|
477
492
|
// Position frozen cells
|
|
478
493
|
const x = this.__isRTL ? normalizedScrollLeft + clientWidth - scrollWidth : scrollLeft;
|
|
494
|
+
this.__horizontalScrollPosition = x;
|
|
479
495
|
const transformFrozen = `translate(${x}px, 0)`;
|
|
480
496
|
this._frozenCells.forEach((cell) => {
|
|
481
497
|
cell.style.transform = transformFrozen;
|
|
@@ -511,10 +527,25 @@ export const ScrollMixin = (superClass) =>
|
|
|
511
527
|
}
|
|
512
528
|
});
|
|
513
529
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
this
|
|
530
|
+
const focusedRow = this.shadowRoot.querySelector("[part~='row']:focus");
|
|
531
|
+
if (focusedRow) {
|
|
532
|
+
// Update the horizontal scroll position property of the focused row
|
|
533
|
+
this.__updateRowScrollPositionProperty(focusedRow);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Synchronizes the internal `--_grid-horizontal-scroll-position` CSS property
|
|
539
|
+
* of the given row with the current horizontal scroll position of the grid.
|
|
540
|
+
* @private
|
|
541
|
+
*/
|
|
542
|
+
__updateRowScrollPositionProperty(row) {
|
|
543
|
+
if (row instanceof HTMLTableRowElement === false) {
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
const newValue = `${this.__horizontalScrollPosition}px`;
|
|
547
|
+
if (row.style.getPropertyValue('--_grid-horizontal-scroll-position') !== newValue) {
|
|
548
|
+
row.style.setProperty('--_grid-horizontal-scroll-position', newValue);
|
|
518
549
|
}
|
|
519
550
|
}
|
|
520
551
|
|