@vaadin/grid 24.4.0-dev.b3e1d14600 → 24.5.0-alpha1

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 (151) hide show
  1. package/README.md +4 -5
  2. package/package.json +10 -10
  3. package/src/all-imports.js +1 -1
  4. package/src/lit/column-renderer-directives.d.ts +1 -1
  5. package/src/lit/column-renderer-directives.js +1 -1
  6. package/src/lit/renderer-directives.d.ts +1 -1
  7. package/src/lit/renderer-directives.js +1 -1
  8. package/src/lit-all-imports.js +1 -1
  9. package/src/vaadin-grid-a11y-mixin.js +4 -2
  10. package/src/vaadin-grid-active-item-mixin.d.ts +1 -1
  11. package/src/vaadin-grid-active-item-mixin.js +29 -16
  12. package/src/vaadin-grid-array-data-provider-mixin.d.ts +1 -1
  13. package/src/vaadin-grid-array-data-provider-mixin.js +1 -1
  14. package/src/vaadin-grid-column-group-mixin.d.ts +1 -1
  15. package/src/vaadin-grid-column-group-mixin.js +1 -1
  16. package/src/vaadin-grid-column-group.d.ts +1 -1
  17. package/src/vaadin-grid-column-group.js +1 -1
  18. package/src/vaadin-grid-column-mixin.d.ts +6 -1
  19. package/src/vaadin-grid-column-mixin.js +14 -5
  20. package/src/vaadin-grid-column-reordering-mixin.d.ts +1 -1
  21. package/src/vaadin-grid-column-reordering-mixin.js +18 -5
  22. package/src/vaadin-grid-column-resizing-mixin.js +1 -1
  23. package/src/vaadin-grid-column.d.ts +1 -1
  24. package/src/vaadin-grid-column.js +1 -1
  25. package/src/vaadin-grid-data-provider-mixin.d.ts +1 -1
  26. package/src/vaadin-grid-data-provider-mixin.js +18 -9
  27. package/src/vaadin-grid-drag-and-drop-mixin.d.ts +1 -1
  28. package/src/vaadin-grid-drag-and-drop-mixin.js +1 -1
  29. package/src/vaadin-grid-dynamic-columns-mixin.js +1 -1
  30. package/src/vaadin-grid-event-context-mixin.d.ts +1 -1
  31. package/src/vaadin-grid-event-context-mixin.js +2 -5
  32. package/src/vaadin-grid-filter-column-mixin.d.ts +1 -1
  33. package/src/vaadin-grid-filter-column-mixin.js +2 -27
  34. package/src/vaadin-grid-filter-column.d.ts +1 -1
  35. package/src/vaadin-grid-filter-column.js +1 -1
  36. package/src/vaadin-grid-filter-element-mixin.d.ts +1 -1
  37. package/src/vaadin-grid-filter-element-mixin.js +3 -11
  38. package/src/vaadin-grid-filter-mixin.js +1 -1
  39. package/src/vaadin-grid-filter.d.ts +1 -1
  40. package/src/vaadin-grid-filter.js +1 -1
  41. package/src/vaadin-grid-helpers.js +1 -1
  42. package/src/vaadin-grid-keyboard-navigation-mixin.js +30 -16
  43. package/src/vaadin-grid-mixin.d.ts +1 -1
  44. package/src/vaadin-grid-mixin.js +77 -16
  45. package/src/vaadin-grid-row-details-mixin.d.ts +1 -1
  46. package/src/vaadin-grid-row-details-mixin.js +1 -1
  47. package/src/vaadin-grid-scroll-mixin.d.ts +3 -1
  48. package/src/vaadin-grid-scroll-mixin.js +21 -9
  49. package/src/vaadin-grid-selection-column-base-mixin.d.ts +1 -1
  50. package/src/vaadin-grid-selection-column-base-mixin.js +19 -1
  51. package/src/vaadin-grid-selection-column-mixin.d.ts +1 -1
  52. package/src/vaadin-grid-selection-column-mixin.js +1 -1
  53. package/src/vaadin-grid-selection-column.d.ts +1 -1
  54. package/src/vaadin-grid-selection-column.js +1 -1
  55. package/src/vaadin-grid-selection-mixin.d.ts +1 -1
  56. package/src/vaadin-grid-selection-mixin.js +1 -1
  57. package/src/vaadin-grid-sort-column-mixin.d.ts +1 -1
  58. package/src/vaadin-grid-sort-column-mixin.js +1 -1
  59. package/src/vaadin-grid-sort-column.d.ts +1 -1
  60. package/src/vaadin-grid-sort-column.js +1 -1
  61. package/src/vaadin-grid-sort-mixin.d.ts +1 -1
  62. package/src/vaadin-grid-sort-mixin.js +1 -1
  63. package/src/vaadin-grid-sorter-mixin.d.ts +1 -1
  64. package/src/vaadin-grid-sorter-mixin.js +1 -1
  65. package/src/vaadin-grid-sorter.d.ts +1 -1
  66. package/src/vaadin-grid-sorter.js +1 -1
  67. package/src/vaadin-grid-styles.js +33 -1
  68. package/src/vaadin-grid-styling-mixin.d.ts +1 -1
  69. package/src/vaadin-grid-styling-mixin.js +1 -1
  70. package/src/vaadin-grid-tree-column-mixin.d.ts +1 -1
  71. package/src/vaadin-grid-tree-column-mixin.js +1 -1
  72. package/src/vaadin-grid-tree-column.d.ts +1 -1
  73. package/src/vaadin-grid-tree-column.js +1 -1
  74. package/src/vaadin-grid-tree-toggle-mixin.d.ts +1 -1
  75. package/src/vaadin-grid-tree-toggle-mixin.js +3 -5
  76. package/src/vaadin-grid-tree-toggle.d.ts +1 -1
  77. package/src/vaadin-grid-tree-toggle.js +1 -1
  78. package/src/vaadin-grid.d.ts +2 -1
  79. package/src/vaadin-grid.js +10 -1
  80. package/src/vaadin-lit-grid-column-group.js +2 -2
  81. package/src/vaadin-lit-grid-column.js +2 -2
  82. package/src/vaadin-lit-grid-filter-column.js +2 -2
  83. package/src/vaadin-lit-grid-filter.js +2 -2
  84. package/src/vaadin-lit-grid-selection-column.js +2 -2
  85. package/src/vaadin-lit-grid-sort-column.js +2 -2
  86. package/src/vaadin-lit-grid-sorter.js +2 -2
  87. package/src/vaadin-lit-grid-tree-column.js +2 -2
  88. package/src/vaadin-lit-grid-tree-toggle.js +2 -2
  89. package/src/vaadin-lit-grid.js +10 -2
  90. package/theme/lumo/all-imports.d.ts +11 -0
  91. package/theme/lumo/lit-all-imports.d.ts +11 -0
  92. package/theme/lumo/vaadin-grid-column-group.d.ts +1 -0
  93. package/theme/lumo/vaadin-grid-column.d.ts +1 -0
  94. package/theme/lumo/vaadin-grid-filter-column.d.ts +2 -0
  95. package/theme/lumo/vaadin-grid-filter.d.ts +2 -0
  96. package/theme/lumo/vaadin-grid-selection-column.d.ts +2 -0
  97. package/theme/lumo/vaadin-grid-sort-column.d.ts +2 -0
  98. package/theme/lumo/vaadin-grid-sorter-styles.d.ts +3 -0
  99. package/theme/lumo/vaadin-grid-sorter.d.ts +2 -0
  100. package/theme/lumo/vaadin-grid-styles.d.ts +6 -0
  101. package/theme/lumo/vaadin-grid-styles.js +10 -1
  102. package/theme/lumo/vaadin-grid-tree-column.d.ts +2 -0
  103. package/theme/lumo/vaadin-grid-tree-toggle-styles.d.ts +3 -0
  104. package/theme/lumo/vaadin-grid-tree-toggle.d.ts +2 -0
  105. package/theme/lumo/vaadin-grid.d.ts +2 -0
  106. package/theme/lumo/vaadin-lit-grid-column-group.d.ts +1 -0
  107. package/theme/lumo/vaadin-lit-grid-column.d.ts +1 -0
  108. package/theme/lumo/vaadin-lit-grid-filter-column.d.ts +2 -0
  109. package/theme/lumo/vaadin-lit-grid-filter.d.ts +2 -0
  110. package/theme/lumo/vaadin-lit-grid-filter.js +1 -2
  111. package/theme/lumo/vaadin-lit-grid-selection-column.d.ts +2 -0
  112. package/theme/lumo/vaadin-lit-grid-selection-column.js +1 -1
  113. package/theme/lumo/vaadin-lit-grid-sort-column.d.ts +2 -0
  114. package/theme/lumo/vaadin-lit-grid-sorter.d.ts +2 -0
  115. package/theme/lumo/vaadin-lit-grid-tree-column.d.ts +2 -0
  116. package/theme/lumo/vaadin-lit-grid-tree-toggle.d.ts +2 -0
  117. package/theme/lumo/vaadin-lit-grid.d.ts +2 -0
  118. package/theme/material/all-imports.d.ts +11 -0
  119. package/theme/material/lit-all-imports.d.ts +11 -0
  120. package/theme/material/vaadin-grid-column-group.d.ts +1 -0
  121. package/theme/material/vaadin-grid-column.d.ts +1 -0
  122. package/theme/material/vaadin-grid-filter-column.d.ts +2 -0
  123. package/theme/material/vaadin-grid-filter.d.ts +2 -0
  124. package/theme/material/vaadin-grid-selection-column.d.ts +2 -0
  125. package/theme/material/vaadin-grid-sort-column.d.ts +2 -0
  126. package/theme/material/vaadin-grid-sorter-styles.d.ts +2 -0
  127. package/theme/material/vaadin-grid-sorter.d.ts +2 -0
  128. package/theme/material/vaadin-grid-styles.d.ts +2 -0
  129. package/theme/material/vaadin-grid-styles.js +6 -0
  130. package/theme/material/vaadin-grid-tree-column.d.ts +2 -0
  131. package/theme/material/vaadin-grid-tree-toggle-styles.d.ts +3 -0
  132. package/theme/material/vaadin-grid-tree-toggle.d.ts +2 -0
  133. package/theme/material/vaadin-grid.d.ts +2 -0
  134. package/theme/material/vaadin-lit-grid-column-group.d.ts +1 -0
  135. package/theme/material/vaadin-lit-grid-column.d.ts +1 -0
  136. package/theme/material/vaadin-lit-grid-filter-column.d.ts +2 -0
  137. package/theme/material/vaadin-lit-grid-filter.d.ts +2 -0
  138. package/theme/material/vaadin-lit-grid-filter.js +1 -2
  139. package/theme/material/vaadin-lit-grid-selection-column.d.ts +2 -0
  140. package/theme/material/vaadin-lit-grid-selection-column.js +1 -1
  141. package/theme/material/vaadin-lit-grid-sort-column.d.ts +2 -0
  142. package/theme/material/vaadin-lit-grid-sorter.d.ts +2 -0
  143. package/theme/material/vaadin-lit-grid-tree-column.d.ts +2 -0
  144. package/theme/material/vaadin-lit-grid-tree-toggle.d.ts +2 -0
  145. package/theme/material/vaadin-lit-grid.d.ts +2 -0
  146. package/vaadin-grid.d.ts +0 -1
  147. package/vaadin-grid.js +0 -1
  148. package/vaadin-lit-grid.d.ts +0 -1
  149. package/vaadin-lit-grid.js +0 -1
  150. package/web-types.json +2579 -0
  151. package/web-types.lit.json +1091 -0
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 { timeOut } from '@vaadin/component-base/src/async.js';
@@ -69,12 +69,8 @@ export const GridFilterElementMixin = (superClass) =>
69
69
 
70
70
  this._filterController = new SlotController(this, '', 'vaadin-text-field', {
71
71
  initializer: (field) => {
72
- field.addEventListener('value-changed', (e) => {
73
- if (field.__previousValue === undefined && e.detail.value === '') {
74
- field.__previousValue = e.detail.value;
75
- return;
76
- }
77
- this.value = e.detail.value;
72
+ field.addEventListener('input', (e) => {
73
+ this.value = e.target.value;
78
74
  });
79
75
 
80
76
  this._textField = field;
@@ -88,12 +84,8 @@ export const GridFilterElementMixin = (superClass) =>
88
84
  if (path === undefined || value === undefined || !textField) {
89
85
  return;
90
86
  }
91
- if (this._previousValue === undefined && value === '') {
92
- return;
93
- }
94
87
 
95
88
  textField.value = value;
96
- this._previousValue = value;
97
89
 
98
90
  this._debouncerFilterChanged = Debouncer.debounce(this._debouncerFilterChanged, timeOut.after(200), () => {
99
91
  this.dispatchEvent(new CustomEvent('filter-changed', { bubbles: true }));
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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/text-field/src/vaadin-text-field.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 { microTask } from '@vaadin/component-base/src/async.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 { isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
@@ -109,6 +109,11 @@ export const KeyboardNavigationMixin = (superClass) =>
109
109
  });
110
110
  }
111
111
 
112
+ /** @private */
113
+ get _visibleItemsCount() {
114
+ return this._lastVisibleIndex - this._firstVisibleIndex - 1;
115
+ }
116
+
112
117
  /** @protected */
113
118
  ready() {
114
119
  super.ready();
@@ -304,8 +309,9 @@ export const KeyboardNavigationMixin = (superClass) =>
304
309
  _onNavigationKeyDown(e, key) {
305
310
  e.preventDefault();
306
311
 
307
- const visibleItemsCount = this._lastVisibleIndex - this._firstVisibleIndex - 1;
308
312
  const isRTL = this.__isRTL;
313
+ const activeRow = e.composedPath().find((el) => this.__isRow(el));
314
+ const activeCell = e.composedPath().find((el) => this.__isCell(el));
309
315
 
310
316
  // Handle keyboard interaction as defined in:
311
317
  // https://w3c.github.io/aria-practices/#keyboard-interaction-24
@@ -350,18 +356,22 @@ export const KeyboardNavigationMixin = (superClass) =>
350
356
  dy = -1;
351
357
  break;
352
358
  case 'PageDown':
353
- dy = visibleItemsCount;
359
+ // Check if the active group is body
360
+ if (this.$.items.contains(activeRow)) {
361
+ const currentRowIndex = this.__getIndexInGroup(activeRow, this._focusedItemIndex);
362
+ // Scroll the current row to the top...
363
+ this._scrollToFlatIndex(currentRowIndex);
364
+ }
365
+ // ...only then measure the visible items count
366
+ dy = this._visibleItemsCount;
354
367
  break;
355
368
  case 'PageUp':
356
- dy = -visibleItemsCount;
369
+ dy = -this._visibleItemsCount;
357
370
  break;
358
371
  default:
359
372
  break;
360
373
  }
361
374
 
362
- const activeRow = e.composedPath().find((el) => this.__isRow(el));
363
- const activeCell = e.composedPath().find((el) => this.__isCell(el));
364
-
365
375
  if ((this.__rowFocusMode && !activeRow) || (!this.__rowFocusMode && !activeCell)) {
366
376
  // When using a screen reader, it's possible that neither a cell nor a row is focused.
367
377
  return;
@@ -665,7 +675,7 @@ export const KeyboardNavigationMixin = (superClass) =>
665
675
  const tabOrder = [
666
676
  this.$.table,
667
677
  this._headerFocusable,
668
- this._itemsFocusable,
678
+ this.__emptyState ? this.$.emptystatecell : this._itemsFocusable,
669
679
  this._footerFocusable,
670
680
  this.$.focusexit,
671
681
  ];
@@ -804,10 +814,12 @@ export const KeyboardNavigationMixin = (superClass) =>
804
814
  const rootTarget = e.composedPath()[0];
805
815
 
806
816
  if (rootTarget === this.$.table || rootTarget === this.$.focusexit) {
807
- // The focus enters the top (bottom) of the grid, meaning that user has
808
- // tabbed (shift-tabbed) into the grid. Move the focus to
809
- // the first (the last) focusable.
810
- this._predictFocusStepTarget(rootTarget, rootTarget === this.$.table ? 1 : -1).focus();
817
+ if (!this._isMousedown) {
818
+ // The focus enters the top (bottom) of the grid, meaning that user has
819
+ // tabbed (shift-tabbed) into the grid. Move the focus to
820
+ // the first (the last) focusable.
821
+ this._predictFocusStepTarget(rootTarget, rootTarget === this.$.table ? 1 : -1).focus();
822
+ }
811
823
  this._setInteracting(false);
812
824
  } else {
813
825
  this._detectInteracting(e);
@@ -848,7 +860,7 @@ export const KeyboardNavigationMixin = (superClass) =>
848
860
  if (cell) {
849
861
  const context = this.getEventContext(e);
850
862
  this.__pendingBodyCellFocus = this.loading && context.section === 'body';
851
- if (!this.__pendingBodyCellFocus) {
863
+ if (!this.__pendingBodyCellFocus && cell !== this.$.emptystatecell) {
852
864
  // Fire a cell-focus event for the cell
853
865
  cell.dispatchEvent(new CustomEvent('cell-focus', { bubbles: true, composed: true, detail: { context } }));
854
866
  }
@@ -895,7 +907,7 @@ export const KeyboardNavigationMixin = (superClass) =>
895
907
  * @private
896
908
  */
897
909
  _detectInteracting(e) {
898
- const isInteracting = e.composedPath().some((el) => el.localName === 'vaadin-grid-cell-content');
910
+ const isInteracting = e.composedPath().some((el) => el.localName === 'slot' && this.shadowRoot.contains(el));
899
911
  this._setInteracting(isInteracting);
900
912
  this.__updateHorizontalScrollPosition();
901
913
  }
@@ -1057,10 +1069,12 @@ export const KeyboardNavigationMixin = (superClass) =>
1057
1069
  * The event may either target table section, a row, a cell or contents of a cell.
1058
1070
  * @param {Event} e
1059
1071
  * @returns {GridEventLocation}
1060
- * @private
1072
+ * @protected
1061
1073
  */
1062
1074
  _getGridEventLocation(e) {
1063
- const path = e.composedPath();
1075
+ // Use `composedPath()` stored by vaadin-context-menu gesture
1076
+ // to avoid problem when accessing it after a timeout on iOS
1077
+ const path = e.__composedPath || e.composedPath();
1064
1078
  const tableIndex = path.indexOf(this.$.table);
1065
1079
  // Assuming ascending path to table is: [...,] th|td, tr, thead|tbody, table [,...]
1066
1080
  const section = tableIndex >= 1 ? path[tableIndex - 1] : null;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 { isElementHidden } from '@vaadin/a11y-base/src/focus-utils.js';
@@ -9,6 +9,7 @@ import { animationFrame, microTask } from '@vaadin/component-base/src/async.js';
9
9
  import { isAndroid, isChrome, isFirefox, isIOS, isSafari, isTouch } from '@vaadin/component-base/src/browser-utils.js';
10
10
  import { Debouncer } from '@vaadin/component-base/src/debounce.js';
11
11
  import { getClosestElement } from '@vaadin/component-base/src/dom-utils.js';
12
+ import { SlotObserver } from '@vaadin/component-base/src/slot-observer.js';
12
13
  import { processTemplates } from '@vaadin/component-base/src/templates.js';
13
14
  import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
14
15
  import { Virtualizer } from '@vaadin/component-base/src/virtualizer.js';
@@ -156,6 +157,18 @@ export const GridMixin = (superClass) =>
156
157
  type: Boolean,
157
158
  value: true,
158
159
  },
160
+
161
+ /** @private */
162
+ __hasEmptyStateContent: {
163
+ type: Boolean,
164
+ value: false,
165
+ },
166
+
167
+ /** @private */
168
+ __emptyState: {
169
+ type: Boolean,
170
+ computed: '__computeEmptyState(_flatSize, __hasEmptyStateContent)',
171
+ },
159
172
  };
160
173
  }
161
174
 
@@ -261,6 +274,11 @@ export const GridMixin = (superClass) =>
261
274
  this._tooltipController = new TooltipController(this);
262
275
  this.addController(this._tooltipController);
263
276
  this._tooltipController.setManual(true);
277
+
278
+ this.__emptyStateContentObserver = new SlotObserver(this.$.emptystateslot, ({ currentNodes }) => {
279
+ this.$.emptystatecell._content = currentNodes[0];
280
+ this.__hasEmptyStateContent = !!this.$.emptystatecell._content;
281
+ });
264
282
  }
265
283
 
266
284
  /** @private */
@@ -316,11 +334,6 @@ export const GridMixin = (superClass) =>
316
334
  }
317
335
  }
318
336
 
319
- /** @private */
320
- __hasRowsWithClientHeight() {
321
- return !!Array.from(this.$.items.children).filter((row) => row.clientHeight).length;
322
- }
323
-
324
337
  /** @private */
325
338
  __getIntrinsicWidth(col) {
326
339
  if (!this.__intrinsicWidthCache.has(col)) {
@@ -432,6 +445,12 @@ export const GridMixin = (superClass) =>
432
445
  cell.style.position = '';
433
446
  }
434
447
  });
448
+
449
+ if (autoWidth) {
450
+ this.$.scroller.setAttribute('measuring-auto-width', '');
451
+ } else {
452
+ this.$.scroller.removeAttribute('measuring-auto-width');
453
+ }
435
454
  }
436
455
 
437
456
  /**
@@ -478,17 +497,40 @@ export const GridMixin = (superClass) =>
478
497
  return;
479
498
  }
480
499
  const cols = this._getColumns().filter((col) => !col.hidden && col.autoWidth);
481
- this._recalculateColumnWidths(cols);
500
+
501
+ const undefinedCols = cols.filter((col) => !customElements.get(col.localName));
502
+ if (undefinedCols.length) {
503
+ // Some of the columns are not defined yet, wait for them to be defined before measuring
504
+ Promise.all(undefinedCols.map((col) => customElements.whenDefined(col.localName))).then(() => {
505
+ this._recalculateColumnWidths(cols);
506
+ });
507
+ } else {
508
+ this._recalculateColumnWidths(cols);
509
+ }
482
510
  }
483
511
 
484
512
  /** @private */
485
513
  __tryToRecalculateColumnWidthsIfPending() {
486
- if (
487
- this.__pendingRecalculateColumnWidths &&
488
- !isElementHidden(this) &&
489
- !this._dataProviderController.isLoading() &&
490
- this.__hasRowsWithClientHeight()
491
- ) {
514
+ if (!this.__pendingRecalculateColumnWidths || isElementHidden(this) || this._dataProviderController.isLoading()) {
515
+ return;
516
+ }
517
+
518
+ // Delay recalculation if any rows are missing an index.
519
+ // This can happen during the grid's initialization if the recalculation is triggered
520
+ // as a result of the data provider responding synchronously to a page request created
521
+ // in the middle of the virtualizer update loop. In this case, rows after the one that
522
+ // triggered the page request may not have an index property yet. The lack of index
523
+ // prevents _onDataProviderPageReceived from requesting children for these rows,
524
+ // resulting in loading state being set to false and the recalculation beginning
525
+ // before all the data is loaded. Note, rows without index get updated in later iterations
526
+ // of the virtualizer update loop, ensuring the grid eventually reaches a stable state.
527
+ const hasRowsWithUndefinedIndex = [...this.$.items.children].some((row) => row.index === undefined);
528
+ if (hasRowsWithUndefinedIndex) {
529
+ return;
530
+ }
531
+
532
+ const hasRowsWithClientHeight = [...this.$.items.children].some((row) => row.clientHeight > 0);
533
+ if (hasRowsWithClientHeight) {
492
534
  this.__pendingRecalculateColumnWidths = false;
493
535
  this.recalculateColumnWidths();
494
536
  }
@@ -653,17 +695,22 @@ export const GridMixin = (superClass) =>
653
695
  cell = column._cells.find((cell) => cell._vacant);
654
696
  if (!cell) {
655
697
  cell = this._createCell('td', column);
698
+ if (column._onCellKeyDown) {
699
+ cell.addEventListener('keydown', column._onCellKeyDown.bind(column));
700
+ }
656
701
  column._cells.push(cell);
657
702
  }
658
703
  cell.setAttribute('part', 'cell body-cell');
659
704
  cell.__parentRow = row;
660
705
  // Cache the cell reference
661
706
  row.__cells.push(cell);
662
- if (!column._bodyContentHidden) {
707
+
708
+ const isSizerRow = row === this.$.sizer;
709
+ if (!column._bodyContentHidden || isSizerRow) {
663
710
  row.appendChild(cell);
664
711
  }
665
712
 
666
- if (row === this.$.sizer) {
713
+ if (isSizerRow) {
667
714
  column._sizerCell = cell;
668
715
  }
669
716
 
@@ -694,7 +741,13 @@ export const GridMixin = (superClass) =>
694
741
  // Header & footer
695
742
  const tagName = section === 'header' ? 'th' : 'td';
696
743
  if (isColumnRow || column.localName === 'vaadin-grid-column-group') {
697
- cell = column[`_${section}Cell`] || this._createCell(tagName);
744
+ cell = column[`_${section}Cell`];
745
+ if (!cell) {
746
+ cell = this._createCell(tagName);
747
+ if (column._onCellKeyDown) {
748
+ cell.addEventListener('keydown', column._onCellKeyDown.bind(column));
749
+ }
750
+ }
698
751
  cell._column = column;
699
752
  row.appendChild(cell);
700
753
  column[`_${section}Cell`] = cell;
@@ -829,6 +882,11 @@ export const GridMixin = (superClass) =>
829
882
  });
830
883
  }
831
884
 
885
+ /** @private */
886
+ __computeEmptyState(flatSize, hasEmptyStateContent) {
887
+ return flatSize === 0 && hasEmptyStateContent;
888
+ }
889
+
832
890
  /**
833
891
  * @param {!Array<!GridColumn>} columnTree
834
892
  * @protected
@@ -912,6 +970,9 @@ export const GridMixin = (superClass) =>
912
970
  this._filterDragAndDrop(row, model);
913
971
 
914
972
  iterateChildren(row, (cell) => {
973
+ if (cell._column && !cell._column.isConnected) {
974
+ return;
975
+ }
915
976
  if (cell._renderer) {
916
977
  const owner = cell._column || this;
917
978
  cell._renderer.call(owner, cell._content, owner, model);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 { iterateChildren } from './vaadin-grid-helpers.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';
@@ -43,6 +43,8 @@ export declare class ScrollMixinClass {
43
43
  * - Keyboard Navigation: Tabbing through focusable elements inside the grid body may not work as expected because
44
44
  * some of the columns that would include focusable elements in the body cells may be outside the visible viewport
45
45
  * and thus not rendered.
46
+ *
47
+ * @attr {eager|lazy} column-rendering
46
48
  */
47
49
  columnRendering: ColumnRendering;
48
50
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 { isElementHidden } from '@vaadin/a11y-base';
@@ -123,6 +123,19 @@ export const ScrollMixin = (superClass) =>
123
123
  this.$.items.addEventListener('focusin', (e) => {
124
124
  const itemsIndex = e.composedPath().indexOf(this.$.items);
125
125
  this._rowWithFocusedElement = e.composedPath()[itemsIndex - 1];
126
+
127
+ if (this._rowWithFocusedElement) {
128
+ // Make sure the row with the focused element is fully inside the visible viewport
129
+ this.__scrollIntoViewport(this._rowWithFocusedElement.index);
130
+
131
+ if (!this.$.table.contains(e.relatedTarget)) {
132
+ // Virtualizer can't catch the event because if orginates from the light DOM.
133
+ // Dispatch a virtualizer-element-focused event for virtualizer to catch.
134
+ this.$.table.dispatchEvent(
135
+ new CustomEvent('virtualizer-element-focused', { detail: { element: this._rowWithFocusedElement } }),
136
+ );
137
+ }
138
+ }
126
139
  });
127
140
  this.$.items.addEventListener('focusout', () => {
128
141
  this._rowWithFocusedElement = undefined;
@@ -235,17 +248,11 @@ export const ScrollMixin = (superClass) =>
235
248
 
236
249
  /** @private */
237
250
  __updateColumnsBodyContentHidden() {
238
- if (!this._columnTree) {
251
+ if (!this._columnTree || !this._areSizerCellsAssigned()) {
239
252
  return;
240
253
  }
241
254
 
242
255
  const columnsInOrder = this._getColumnsInOrder();
243
-
244
- // Return if sizer cells are not yet assigned to columns
245
- if (!columnsInOrder[0] || !columnsInOrder[0]._sizerCell) {
246
- return;
247
- }
248
-
249
256
  let bodyContentHiddenChanged = false;
250
257
 
251
258
  // Remove the column cells from the DOM if the column is outside the viewport.
@@ -485,7 +492,7 @@ export const ScrollMixin = (superClass) =>
485
492
 
486
493
  let transformFrozenToEndBody = transformFrozenToEnd;
487
494
 
488
- if (this._lazyColumns) {
495
+ if (this._lazyColumns && this._areSizerCellsAssigned()) {
489
496
  // Lazy column rendering is used, calculate the offset to apply to the frozen to end cells
490
497
  const columnsInOrder = this._getColumnsInOrder();
491
498
 
@@ -515,4 +522,9 @@ export const ScrollMixin = (superClass) =>
515
522
  this.$.table.style.setProperty('--_grid-horizontal-scroll-position', `${-x}px`);
516
523
  }
517
524
  }
525
+
526
+ /** @private */
527
+ _areSizerCellsAssigned() {
528
+ return this._getColumnsInOrder().every((column) => column._sizerCell);
529
+ }
518
530
  };
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 { addListener } from '@vaadin/component-base/src/gestures.js';
@@ -31,6 +31,14 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
31
31
  sync: true,
32
32
  },
33
33
 
34
+ /**
35
+ * Override `autoWidth` to enable auto-width
36
+ */
37
+ autoWidth: {
38
+ type: Boolean,
39
+ value: true,
40
+ },
41
+
34
42
  /**
35
43
  * Flex grow ratio for the cell widths. When set to 0, cell width is fixed.
36
44
  * @attr {number} flex-grow
@@ -233,6 +241,16 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
233
241
  }
234
242
  }
235
243
 
244
+ /** @private */
245
+ _onCellKeyDown(e) {
246
+ const target = e.composedPath()[0];
247
+ // Toggle on Space without having to enter interaction mode first
248
+ if (e.keyCode === 32 && (target === this._headerCell || (this._cells.includes(target) && !this.autoSelect))) {
249
+ const checkbox = target._content.firstElementChild;
250
+ checkbox.checked = !checkbox.checked;
251
+ }
252
+ }
253
+
236
254
  /** @private */
237
255
  __dragAutoScroller() {
238
256
  if (this.__dragStartIndex === undefined) {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 { GridSelectionColumnBaseMixin } from './vaadin-grid-selection-column-base-mixin.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 type { GridDefaultItem } from './vaadin-grid.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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/checkbox/src/vaadin-checkbox.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 type { GridDefaultItem } from './vaadin-grid.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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-sorter.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2016 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2016 - 2024 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 { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';