@vaadin/grid 25.0.0-alpha2 → 25.0.0-alpha21

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 (84) hide show
  1. package/all-imports.js +1 -1
  2. package/package.json +12 -13
  3. package/src/array-data-provider.js +9 -2
  4. package/src/lit/column-renderer-directives.d.ts +0 -1
  5. package/src/styles/vaadin-grid-base-styles.d.ts +8 -0
  6. package/src/styles/vaadin-grid-base-styles.js +677 -0
  7. package/src/styles/vaadin-grid-filter-base-styles.d.ts +8 -0
  8. package/src/styles/vaadin-grid-filter-base-styles.js +18 -0
  9. package/src/styles/vaadin-grid-sorter-base-styles.d.ts +8 -0
  10. package/src/styles/vaadin-grid-sorter-base-styles.js +76 -0
  11. package/src/styles/vaadin-grid-tree-toggle-base-styles.d.ts +8 -0
  12. package/src/styles/vaadin-grid-tree-toggle-base-styles.js +76 -0
  13. package/src/vaadin-grid-a11y-mixin.js +26 -10
  14. package/src/vaadin-grid-column-auto-width-mixin.js +9 -6
  15. package/src/vaadin-grid-column-mixin.d.ts +1 -0
  16. package/src/vaadin-grid-column-mixin.js +1 -16
  17. package/src/vaadin-grid-column-reordering-mixin.js +2 -2
  18. package/src/vaadin-grid-data-provider-mixin.js +33 -85
  19. package/src/vaadin-grid-drag-and-drop-mixin.js +3 -0
  20. package/src/vaadin-grid-event-context-mixin.d.ts +2 -0
  21. package/src/vaadin-grid-event-context-mixin.js +1 -0
  22. package/src/vaadin-grid-filter-element-mixin.js +0 -17
  23. package/src/vaadin-grid-filter.js +7 -1
  24. package/src/vaadin-grid-helpers.js +9 -0
  25. package/src/vaadin-grid-keyboard-navigation-mixin.js +2 -6
  26. package/src/vaadin-grid-mixin.d.ts +1 -0
  27. package/src/vaadin-grid-mixin.js +64 -32
  28. package/src/vaadin-grid-row-details-mixin.js +5 -5
  29. package/src/vaadin-grid-scroll-mixin.js +57 -77
  30. package/src/vaadin-grid-selection-column-base-mixin.d.ts +1 -1
  31. package/src/vaadin-grid-selection-column-base-mixin.js +1 -1
  32. package/src/vaadin-grid-selection-column.d.ts +2 -0
  33. package/src/vaadin-grid-selection-column.js +2 -1
  34. package/src/vaadin-grid-sort-column.d.ts +2 -0
  35. package/src/vaadin-grid-sorter-mixin.js +0 -60
  36. package/src/vaadin-grid-sorter.d.ts +3 -3
  37. package/src/vaadin-grid-sorter.js +10 -4
  38. package/src/vaadin-grid-tree-column-mixin.js +2 -7
  39. package/src/vaadin-grid-tree-toggle-mixin.js +0 -77
  40. package/src/vaadin-grid-tree-toggle.d.ts +4 -4
  41. package/src/vaadin-grid-tree-toggle.js +13 -5
  42. package/src/vaadin-grid.d.ts +2 -1
  43. package/src/vaadin-grid.js +6 -3
  44. package/vaadin-grid-column-group.js +1 -1
  45. package/vaadin-grid-column.js +1 -1
  46. package/vaadin-grid-filter-column.js +1 -1
  47. package/vaadin-grid-filter.js +1 -1
  48. package/vaadin-grid-selection-column.js +1 -1
  49. package/vaadin-grid-sort-column.js +1 -1
  50. package/vaadin-grid-sorter.js +1 -1
  51. package/vaadin-grid-tree-column.js +1 -1
  52. package/vaadin-grid-tree-toggle.js +1 -1
  53. package/vaadin-grid.js +1 -1
  54. package/web-types.json +13 -13
  55. package/web-types.lit.json +12 -12
  56. package/src/vaadin-grid-styles.js +0 -389
  57. package/theme/lumo/all-imports.d.ts +0 -11
  58. package/theme/lumo/all-imports.js +0 -11
  59. package/theme/lumo/vaadin-grid-column-group.d.ts +0 -1
  60. package/theme/lumo/vaadin-grid-column-group.js +0 -1
  61. package/theme/lumo/vaadin-grid-column.d.ts +0 -1
  62. package/theme/lumo/vaadin-grid-column.js +0 -1
  63. package/theme/lumo/vaadin-grid-filter-column.d.ts +0 -2
  64. package/theme/lumo/vaadin-grid-filter-column.js +0 -2
  65. package/theme/lumo/vaadin-grid-filter.d.ts +0 -2
  66. package/theme/lumo/vaadin-grid-filter.js +0 -2
  67. package/theme/lumo/vaadin-grid-selection-column.d.ts +0 -2
  68. package/theme/lumo/vaadin-grid-selection-column.js +0 -2
  69. package/theme/lumo/vaadin-grid-sort-column.d.ts +0 -2
  70. package/theme/lumo/vaadin-grid-sort-column.js +0 -2
  71. package/theme/lumo/vaadin-grid-sorter-styles.d.ts +0 -3
  72. package/theme/lumo/vaadin-grid-sorter-styles.js +0 -52
  73. package/theme/lumo/vaadin-grid-sorter.d.ts +0 -2
  74. package/theme/lumo/vaadin-grid-sorter.js +0 -2
  75. package/theme/lumo/vaadin-grid-styles.d.ts +0 -6
  76. package/theme/lumo/vaadin-grid-styles.js +0 -405
  77. package/theme/lumo/vaadin-grid-tree-column.d.ts +0 -2
  78. package/theme/lumo/vaadin-grid-tree-column.js +0 -2
  79. package/theme/lumo/vaadin-grid-tree-toggle-styles.d.ts +0 -3
  80. package/theme/lumo/vaadin-grid-tree-toggle-styles.js +0 -81
  81. package/theme/lumo/vaadin-grid-tree-toggle.d.ts +0 -2
  82. package/theme/lumo/vaadin-grid-tree-toggle.js +0 -2
  83. package/theme/lumo/vaadin-grid.d.ts +0 -2
  84. package/theme/lumo/vaadin-grid.js +0 -2
@@ -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';
@@ -263,13 +256,21 @@ export const GridMixin = (superClass) =>
263
256
  scrollContainer: this.$.items,
264
257
  scrollTarget: this.$.table,
265
258
  reorderElements: true,
259
+ // Grid rows have a CSS-defined minimum height, so the virtualizer's height
260
+ // placeholder logic can be disabled. This helps save reflows which might
261
+ // otherwise be triggered by this logic because it reads the row height
262
+ // right after updating the rows' content.
263
+ __disableHeightPlaceholder: true,
266
264
  });
267
265
 
268
- new ResizeObserver(() =>
266
+ new ResizeObserver(() => {
269
267
  setTimeout(() => {
270
268
  this.__updateColumnsBodyContentHidden();
271
- }),
272
- ).observe(this.$.table);
269
+ });
270
+ // Updating data can change the visibility of the scroll bar. Therefore,
271
+ // the scroll position has to be recalculated.
272
+ this.__updateHorizontalScrollPosition();
273
+ }).observe(this.$.table);
273
274
 
274
275
  const minHeightObserver = new ResizeObserver(() =>
275
276
  setTimeout(() => {
@@ -353,7 +354,7 @@ export const GridMixin = (superClass) =>
353
354
  row.setAttribute('role', 'row');
354
355
  row.setAttribute('tabindex', '-1');
355
356
  if (this._columnTree) {
356
- this._updateRow(row, this._columnTree[this._columnTree.length - 1], 'body', false, true);
357
+ this.__initRow(row, this._columnTree[this._columnTree.length - 1], 'body', false, true);
357
358
  }
358
359
  rows.push(row);
359
360
  }
@@ -465,9 +466,9 @@ export const GridMixin = (superClass) =>
465
466
  * @param {?string} section
466
467
  * @param {boolean} isColumnRow
467
468
  * @param {boolean} noNotify
468
- * @protected
469
+ * @private
469
470
  */
470
- _updateRow(row, columns, section = 'body', isColumnRow = false, noNotify = false) {
471
+ __initRow(row, columns, section = 'body', isColumnRow = false, noNotify = false) {
471
472
  const contentsFragment = document.createDocumentFragment();
472
473
 
473
474
  iterateRowCells(row, (cell) => {
@@ -637,6 +638,7 @@ export const GridMixin = (superClass) =>
637
638
 
638
639
  // Make sure the section has a tabbable element
639
640
  this._resetKeyboardNavigation();
641
+ this._a11yUpdateGridSize(this.size, this._columnTree, this.__emptyState);
640
642
  }
641
643
 
642
644
  /** @private */
@@ -647,10 +649,15 @@ export const GridMixin = (superClass) =>
647
649
  return;
648
650
  }
649
651
 
652
+ row.index = index;
653
+
650
654
  this._updateRowOrderParts(row, index);
651
655
 
652
656
  this._a11yUpdateRowRowindex(row, index);
653
- this._getItem(index, row);
657
+
658
+ this.__ensureRowItem(row);
659
+ this.__ensureRowHierarchy(row);
660
+ this.__updateRow(row);
654
661
  }
655
662
 
656
663
  /** @private */
@@ -691,7 +698,7 @@ export const GridMixin = (superClass) =>
691
698
  */
692
699
  _renderColumnTree(columnTree) {
693
700
  iterateChildren(this.$.items, (row) => {
694
- this._updateRow(row, columnTree[columnTree.length - 1], 'body', false, true);
701
+ this.__initRow(row, columnTree[columnTree.length - 1], 'body', false, true);
695
702
 
696
703
  const model = this.__getRowModel(row);
697
704
  this._updateRowOrderParts(row);
@@ -718,7 +725,7 @@ export const GridMixin = (superClass) =>
718
725
  }
719
726
 
720
727
  iterateChildren(this.$.header, (headerRow, index, rows) => {
721
- this._updateRow(headerRow, columnTree[index], 'header', index === columnTree.length - 1);
728
+ this.__initRow(headerRow, columnTree[index], 'header', index === columnTree.length - 1);
722
729
 
723
730
  const cells = getBodyRowCells(headerRow);
724
731
  updateCellsPart(cells, 'first-header-row-cell', index === 0);
@@ -726,7 +733,7 @@ export const GridMixin = (superClass) =>
726
733
  });
727
734
 
728
735
  iterateChildren(this.$.footer, (footerRow, index, rows) => {
729
- this._updateRow(footerRow, columnTree[columnTree.length - 1 - index], 'footer', index === 0);
736
+ this.__initRow(footerRow, columnTree[columnTree.length - 1 - index], 'footer', index === 0);
730
737
 
731
738
  const cells = getBodyRowCells(footerRow);
732
739
  updateCellsPart(cells, 'first-footer-row-cell', index === 0);
@@ -734,7 +741,7 @@ export const GridMixin = (superClass) =>
734
741
  });
735
742
 
736
743
  // Sizer rows
737
- this._updateRow(this.$.sizer, columnTree[columnTree.length - 1]);
744
+ this.__initRow(this.$.sizer, columnTree[columnTree.length - 1]);
738
745
 
739
746
  this._resizeHandler();
740
747
  this._frozenCellsChanged();
@@ -749,10 +756,38 @@ export const GridMixin = (superClass) =>
749
756
 
750
757
  /**
751
758
  * @param {!HTMLElement} row
752
- * @param {GridItem} item
753
- * @protected
759
+ * @param {boolean} loading
760
+ * @private
754
761
  */
755
- _updateItem(row, item) {
762
+ __updateRowLoading(row, loading) {
763
+ const cells = getBodyRowCells(row);
764
+
765
+ // Row state attribute
766
+ updateState(row, 'loading', loading);
767
+
768
+ // Cells part attribute
769
+ updateCellsPart(cells, 'loading-row-cell', loading);
770
+
771
+ if (loading) {
772
+ // Run style generators for the loading row to have custom names cleared
773
+ this._generateCellClassNames(row);
774
+ this._generateCellPartNames(row);
775
+ }
776
+ }
777
+
778
+ /**
779
+ * @param {!HTMLElement} row
780
+ * @private
781
+ */
782
+ __updateRow(row) {
783
+ const item = this.__getRowItem(row);
784
+ if (item) {
785
+ this.__updateRowLoading(row, false);
786
+ } else {
787
+ this.__updateRowLoading(row, true);
788
+ return;
789
+ }
790
+
756
791
  row._item = item;
757
792
  const model = this.__getRowModel(row);
758
793
 
@@ -813,9 +848,10 @@ export const GridMixin = (superClass) =>
813
848
  return {
814
849
  index: row.index,
815
850
  item: row._item,
816
- level: this._getIndexLevel(row.index),
851
+ level: this.__getRowLevel(row),
817
852
  expanded: this._isExpanded(row._item),
818
853
  selected: this._isSelected(row._item),
854
+ hasChildren: this._hasChildren(row._item),
819
855
  detailsOpened: !!this.rowDetailsRenderer && this._isDetailsOpened(row._item),
820
856
  };
821
857
  }
@@ -929,15 +965,11 @@ export const GridMixin = (superClass) =>
929
965
 
930
966
  // 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
967
  // Prefer setting style in adopted style sheet to avoid the need to add a confusing inline style on the host element
932
- // If adopted style sheets are not supported, the style is set inline
933
- if (!this.__minHeightStyleSheet && supportsAdoptingStyleSheets) {
968
+ if (!this.__minHeightStyleSheet) {
934
969
  this.__minHeightStyleSheet = new CSSStyleSheet();
935
- this.shadowRoot.adoptedStyleSheets = [...this.shadowRoot.adoptedStyleSheets, this.__minHeightStyleSheet];
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`);
970
+ this.shadowRoot.adoptedStyleSheets.push(this.__minHeightStyleSheet);
941
971
  }
972
+
973
+ this.__minHeightStyleSheet.replaceSync(`:host { --_grid-min-height: ${minHeight}px; }`);
942
974
  }
943
975
  };
@@ -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._updateRow(row, this._columnTree[this._columnTree.length - 1]);
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._updateItem(row, row._item);
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._updateItem(row, row._item);
107
+ this.__updateRow(row);
108
108
  }
109
109
  });
110
110
  }
@@ -124,7 +124,7 @@ export const RowDetailsMixin = (superClass) =>
124
124
 
125
125
  /**
126
126
  * @param {!HTMLElement} row
127
- * @param {!GridItem} item
127
+ * @param {boolean} detailsOpened
128
128
  * @protected
129
129
  */
130
130
  _toggleDetailsCell(row, detailsOpened) {
@@ -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 `_updateItem` method.
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
  }
@@ -4,9 +4,10 @@
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';
7
- import { animationFrame, microTask, timeOut } from '@vaadin/component-base/src/async.js';
7
+ import { microTask, timeOut } from '@vaadin/component-base/src/async.js';
8
8
  import { Debouncer } from '@vaadin/component-base/src/debounce.js';
9
9
  import { getNormalizedScrollLeft } from '@vaadin/component-base/src/dir-utils.js';
10
+ import { OverflowController } from '@vaadin/component-base/src/overflow-controller.js';
10
11
  import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
11
12
 
12
13
  const timeouts = {
@@ -122,10 +123,23 @@ export const ScrollMixin = (superClass) =>
122
123
  const row = composedPath[composedPath.indexOf(this.$.items) - 1];
123
124
 
124
125
  if (row) {
125
- // Make sure the row with the focused element is fully inside the visible viewport
126
- // Don't change scroll position if the user is interacting with the mouse
126
+ // Don't change scroll position if the user is interacting with the mouse.
127
127
  if (!this._isMousedown) {
128
- this.__scrollIntoViewport(row.index);
128
+ // Make sure the focused element (row, cell, or focusable element inside a cell)
129
+ // is inside the viewport. If the whole row fits into the viewport, then scroll
130
+ // the row into view. This ensures that labels, helper texts and other related
131
+ // elements of focusable elements within cells also become visible. When the row
132
+ // is larger than the viewport, scroll the focus event target into the viewport.
133
+ // This works better when focusing elements within cells, which could otherwise
134
+ // still be outside the viewport when scrolling to the top or bottom of the row.
135
+ const tableHeight = this.$.table.clientHeight;
136
+ const headerHeight = this.$.header.clientHeight;
137
+ const footerHeight = this.$.footer.clientHeight;
138
+ const viewportHeight = tableHeight - headerHeight - footerHeight;
139
+ const isRowLargerThanViewport = row.clientHeight > viewportHeight;
140
+ const scrollTarget = isRowLargerThanViewport ? e.target : row;
141
+
142
+ this.__scrollIntoViewport(scrollTarget);
129
143
  }
130
144
 
131
145
  if (!this.$.table.contains(e.relatedTarget)) {
@@ -137,6 +151,9 @@ export const ScrollMixin = (superClass) =>
137
151
  });
138
152
 
139
153
  this.$.table.addEventListener('scroll', () => this._afterScroll());
154
+
155
+ this.__overflowController = new OverflowController(this, this.$.table);
156
+ this.addController(this.__overflowController);
140
157
  }
141
158
 
142
159
  /**
@@ -144,7 +161,6 @@ export const ScrollMixin = (superClass) =>
144
161
  * @override
145
162
  */
146
163
  _onResize() {
147
- this._updateOverflow();
148
164
  this.__updateHorizontalScrollPosition();
149
165
 
150
166
  // For Firefox, manually restore last scroll position when grid becomes
@@ -171,25 +187,27 @@ export const ScrollMixin = (superClass) =>
171
187
  _scrollToFlatIndex(index) {
172
188
  index = Math.min(this._flatSize - 1, Math.max(0, index));
173
189
  this.__virtualizer.scrollToIndex(index);
174
- this.__scrollIntoViewport(index);
190
+ const rowElement = [...this.$.items.children].find((child) => child.index === index);
191
+ this.__scrollIntoViewport(rowElement);
175
192
  }
176
193
 
177
194
  /**
178
- * Makes sure the row with the given index (if found in the DOM) is fully
179
- * inside the visible viewport, taking header/footer into account.
195
+ * Makes sure the given element is fully inside the visible viewport,
196
+ * taking header/footer into account.
180
197
  * @private
181
198
  */
182
- __scrollIntoViewport(index) {
183
- const rowElement = [...this.$.items.children].find((child) => child.index === index);
184
- if (rowElement) {
185
- const dstRect = rowElement.getBoundingClientRect();
186
- const footerTop = this.$.footer.getBoundingClientRect().top;
187
- const headerBottom = this.$.header.getBoundingClientRect().bottom;
188
- if (dstRect.bottom > footerTop) {
189
- this.$.table.scrollTop += dstRect.bottom - footerTop;
190
- } else if (dstRect.top < headerBottom) {
191
- this.$.table.scrollTop -= headerBottom - dstRect.top;
192
- }
199
+ __scrollIntoViewport(element) {
200
+ if (!element) {
201
+ return;
202
+ }
203
+
204
+ const dstRect = element.getBoundingClientRect();
205
+ const footerTop = this.$.footer.getBoundingClientRect().top;
206
+ const headerBottom = this.$.header.getBoundingClientRect().bottom;
207
+ if (dstRect.bottom > footerTop) {
208
+ this.$.table.scrollTop += dstRect.bottom - footerTop;
209
+ } else if (dstRect.top < headerBottom) {
210
+ this.$.table.scrollTop -= headerBottom - dstRect.top;
193
211
  }
194
212
  }
195
213
 
@@ -217,8 +235,6 @@ export const ScrollMixin = (superClass) =>
217
235
  this._hideTooltip(true);
218
236
  }
219
237
 
220
- this._updateOverflow();
221
-
222
238
  this._debounceColumnContentVisibility = Debouncer.debounce(
223
239
  this._debounceColumnContentVisibility,
224
240
  timeOut.after(timeouts.UPDATE_CONTENT_VISIBILITY),
@@ -345,58 +361,6 @@ export const ScrollMixin = (superClass) =>
345
361
  this.__updateColumnsBodyContentHidden();
346
362
  }
347
363
 
348
- /** @private */
349
- _updateOverflow() {
350
- this._debounceOverflow = Debouncer.debounce(this._debounceOverflow, animationFrame, () => {
351
- this.__doUpdateOverflow();
352
- });
353
- }
354
-
355
- /** @private */
356
- __doUpdateOverflow() {
357
- // Set overflow styling attributes
358
- let overflow = '';
359
- const table = this.$.table;
360
- if (table.scrollTop < table.scrollHeight - table.clientHeight) {
361
- overflow += ' bottom';
362
- }
363
-
364
- if (table.scrollTop > 0) {
365
- overflow += ' top';
366
- }
367
-
368
- const scrollLeft = getNormalizedScrollLeft(table, this.getAttribute('dir'));
369
- if (scrollLeft > 0) {
370
- overflow += ' start';
371
- }
372
-
373
- if (scrollLeft < table.scrollWidth - table.clientWidth) {
374
- overflow += ' end';
375
- }
376
-
377
- if (this.__isRTL) {
378
- overflow = overflow.replace(/start|end/giu, (matched) => {
379
- return matched === 'start' ? 'end' : 'start';
380
- });
381
- }
382
-
383
- // TODO: Remove "right" and "left" values in the next major.
384
- if (table.scrollLeft < table.scrollWidth - table.clientWidth) {
385
- overflow += ' right';
386
- }
387
-
388
- if (table.scrollLeft > 0) {
389
- overflow += ' left';
390
- }
391
-
392
- const value = overflow.trim();
393
- if (value.length > 0 && this.getAttribute('overflow') !== value) {
394
- this.setAttribute('overflow', value);
395
- } else if (value.length === 0 && this.hasAttribute('overflow')) {
396
- this.removeAttribute('overflow');
397
- }
398
- }
399
-
400
364
  /** @protected */
401
365
  _frozenCellsChanged() {
402
366
  this._debouncerCacheElements = Debouncer.debounce(this._debouncerCacheElements, microTask, () => {
@@ -476,6 +440,7 @@ export const ScrollMixin = (superClass) =>
476
440
 
477
441
  // Position frozen cells
478
442
  const x = this.__isRTL ? normalizedScrollLeft + clientWidth - scrollWidth : scrollLeft;
443
+ this.__horizontalScrollPosition = x;
479
444
  const transformFrozen = `translate(${x}px, 0)`;
480
445
  this._frozenCells.forEach((cell) => {
481
446
  cell.style.transform = transformFrozen;
@@ -511,10 +476,25 @@ export const ScrollMixin = (superClass) =>
511
476
  }
512
477
  });
513
478
 
514
- // Only update the --_grid-horizontal-scroll-position custom property when navigating
515
- // on row focus mode to avoid performance issues.
516
- if (this.hasAttribute('navigating') && this.__rowFocusMode) {
517
- this.$.table.style.setProperty('--_grid-horizontal-scroll-position', `${-x}px`);
479
+ const focusedRow = this.shadowRoot.querySelector("[part~='row']:focus");
480
+ if (focusedRow) {
481
+ // Update the horizontal scroll position property of the focused row
482
+ this.__updateRowScrollPositionProperty(focusedRow);
483
+ }
484
+ }
485
+
486
+ /**
487
+ * Synchronizes the internal `--_grid-horizontal-scroll-position` CSS property
488
+ * of the given row with the current horizontal scroll position of the grid.
489
+ * @private
490
+ */
491
+ __updateRowScrollPositionProperty(row) {
492
+ if (row instanceof HTMLTableRowElement === false) {
493
+ return;
494
+ }
495
+ const newValue = `${this.__horizontalScrollPosition}px`;
496
+ if (row.style.getPropertyValue('--_grid-horizontal-scroll-position') !== newValue) {
497
+ row.style.setProperty('--_grid-horizontal-scroll-position', newValue);
518
498
  }
519
499
  }
520
500
 
@@ -28,7 +28,7 @@ export declare class GridSelectionColumnBaseMixinClass<TItem> {
28
28
  selectAll: boolean;
29
29
 
30
30
  /**
31
- * When true, the active gets automatically selected.
31
+ * When true, the active item gets automatically selected.
32
32
  * @attr {boolean} auto-select
33
33
  */
34
34
  autoSelect: boolean;
@@ -63,7 +63,7 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
63
63
  },
64
64
 
65
65
  /**
66
- * When true, the active gets automatically selected.
66
+ * When true, the active item gets automatically selected.
67
67
  * @attr {boolean} auto-select
68
68
  * @type {boolean}
69
69
  */
@@ -34,6 +34,8 @@ export * from './vaadin-grid-selection-column-mixin.js';
34
34
  * selection for all the items at once.
35
35
  *
36
36
  * __The default content can also be overridden__
37
+ *
38
+ * @fires {CustomEvent} select-all-changed - Fired when the `selectAll` property changes.
37
39
  */
38
40
  declare class GridSelectionColumn<TItem = GridDefaultItem> extends HTMLElement {}
39
41
 
@@ -30,8 +30,9 @@ import { GridSelectionColumnMixin } from './vaadin-grid-selection-column-mixin.j
30
30
  *
31
31
  * __The default content can also be overridden__
32
32
  *
33
- * @customElement
34
33
  * @fires {CustomEvent} select-all-changed - Fired when the `selectAll` property changes.
34
+ *
35
+ * @customElement
35
36
  * @extends GridColumn
36
37
  * @mixes GridSelectionColumnMixin
37
38
  */
@@ -21,6 +21,8 @@ export * from './vaadin-grid-sort-column-mixin.js';
21
21
  * <vaadin-grid-column>
22
22
  * ...
23
23
  * ```
24
+ *
25
+ * @fires {CustomEvent} direction-changed - Fired when the `direction` property changes.
24
26
  */
25
27
  declare class GridSortColumn<TItem = GridDefaultItem> extends HTMLElement {}
26
28
 
@@ -3,66 +3,6 @@
3
3
  * Copyright (c) 2016 - 2025 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
7
-
8
- const template = document.createElement('template');
9
-
10
- template.innerHTML = `
11
- <style>
12
- @font-face {
13
- font-family: 'vaadin-grid-sorter-icons';
14
- src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAQwAA0AAAAABuwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAEFAAAABkAAAAcfep+mUdERUYAAAP4AAAAHAAAAB4AJwAOT1MvMgAAAZgAAAA/AAAAYA8TBPpjbWFwAAAB7AAAAFUAAAFeF1fZ4mdhc3AAAAPwAAAACAAAAAgAAAAQZ2x5ZgAAAlgAAABcAAAAnMvguMloZWFkAAABMAAAAC8AAAA2C5Ap72hoZWEAAAFgAAAAHQAAACQGbQPHaG10eAAAAdgAAAAUAAAAHAoAAABsb2NhAAACRAAAABIAAAASAIwAYG1heHAAAAGAAAAAFgAAACAACwAKbmFtZQAAArQAAAECAAACZxWCgKhwb3N0AAADuAAAADUAAABZCrApUXicY2BkYGAA4rDECVrx/DZfGbhZGEDgyqNPOxH0/wNMq5kPALkcDEwgUQBWRA0dAHicY2BkYGA+8P8AAwMLAwgwrWZgZEAFbABY4QM8AAAAeJxjYGRgYOAAQiYGEICQSAAAAi8AFgAAeJxjYGY6yziBgZWBgWkm0xkGBoZ+CM34msGYkZMBFTAKoAkwODAwvmRiPvD/AIMDMxCD1CDJKjAwAgBktQsXAHicY2GAAMZQCM0EwqshbAALxAEKeJxjYGBgZoBgGQZGBhCIAPIYwXwWBhsgzcXAwcAEhIwMCi+Z/v/9/x+sSuElA4T9/4k4K1gHFwMMMILMY2QDYmaoABOQYGJABUA7WBiGNwAAJd4NIQAAAAAAAAAACAAIABAAGAAmAEAATgAAeJyNjLENgDAMBP9tIURJwQCMQccSZgk2i5fIYBDAidJjycXr7x5EPwE2wY8si7jmyBNXGo/bNBerxJNrpxhbO3/fEFpx8ZICpV+ghxJ74fAMe+h7Ox14AbrsHB14nK2QQWrDMBRER4mTkhQK3ZRQKOgCNk7oGQqhhEIX2WSlWEI1BAlkJ5CDdNsj5Ey9Rncdi38ES+jzNJo/HwTgATcoDEthhY3wBHc4CE+pfwsX5F/hGe7Vo/AcK/UhvMSz+mGXKhZU6pww8ISz3oWn1BvhgnwTnuEJf8Jz1OpFeIlX9YULDLdFi4ASHolkSR0iuYdjLak1vAequBhj21D61Nqyi6l3qWybGPjySbPHGScGJl6dP58MYcQRI0bts7mjebBqrFENH7t3qWtj0OuqHnXcW7b0HOTZFnKryRGW2hFX1m0O2vEM3opNMfTau+CS6Z3Vx6veNnEXY6jwDxhsc2gAAHicY2BiwA84GBgYmRiYGJkZmBlZGFkZ2djScyoLMgzZS/MyDQwMwLSrpYEBlIbxjQDrzgsuAAAAAAEAAf//AA94nGNgZGBg4AFiMSBmYmAEQnYgZgHzGAAD6wA2eJxjYGBgZACCKyoz1cD0o087YTQATOcIewAAAA==) format('woff');
15
- font-weight: normal;
16
- font-style: normal;
17
- }
18
- </style>
19
- `;
20
-
21
- document.head.appendChild(template.content);
22
-
23
- registerStyles(
24
- 'vaadin-grid-sorter',
25
- css`
26
- :host {
27
- display: inline-flex;
28
- cursor: pointer;
29
- max-width: 100%;
30
- }
31
-
32
- [part='content'] {
33
- flex: 1 1 auto;
34
- }
35
-
36
- [part='indicators'] {
37
- position: relative;
38
- align-self: center;
39
- flex: none;
40
- }
41
-
42
- [part='order'] {
43
- display: inline;
44
- vertical-align: super;
45
- }
46
-
47
- [part='indicators']::before {
48
- font-family: 'vaadin-grid-sorter-icons';
49
- display: inline-block;
50
- }
51
-
52
- :host(:not([direction])) [part='indicators']::before {
53
- content: '\\e901';
54
- }
55
-
56
- :host([direction='asc']) [part='indicators']::before {
57
- content: '\\e900';
58
- }
59
-
60
- :host([direction='desc']) [part='indicators']::before {
61
- content: '\\e902';
62
- }
63
- `,
64
- { moduleId: 'vaadin-grid-sorter-styles' },
65
- );
66
6
 
67
7
  /**
68
8
  * A mixin providing common sorter functionality.
@@ -41,9 +41,9 @@ export * from './vaadin-grid-sorter-mixin.js';
41
41
  *
42
42
  * The following state attributes are available for styling:
43
43
  *
44
- * Attribute | Description | Part name
45
- * -------------|-------------|------------
46
- * `direction` | Sort direction of a sorter | :host
44
+ * Attribute | Description
45
+ * -------------|---------------------------
46
+ * `direction` | Sort direction of a sorter
47
47
  *
48
48
  * @fires {CustomEvent} direction-changed - Fired when the `direction` property changes.
49
49
  * @fires {CustomEvent} sorter-changed - Fired when the `path` or `direction` property changes.
@@ -8,6 +8,8 @@ import { defineCustomElement } from '@vaadin/component-base/src/define.js';
8
8
  import { DirMixin } from '@vaadin/component-base/src/dir-mixin.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 { gridSorterStyles } from './styles/vaadin-grid-sorter-base-styles.js';
11
13
  import { GridSorterMixin } from './vaadin-grid-sorter-mixin.js';
12
14
 
13
15
  /**
@@ -42,9 +44,9 @@ import { GridSorterMixin } from './vaadin-grid-sorter-mixin.js';
42
44
  *
43
45
  * The following state attributes are available for styling:
44
46
  *
45
- * Attribute | Description | Part name
46
- * -------------|-------------|------------
47
- * `direction` | Sort direction of a sorter | :host
47
+ * Attribute | Description
48
+ * -------------|---------------------------
49
+ * `direction` | Sort direction of a sorter
48
50
  *
49
51
  * @fires {CustomEvent} direction-changed - Fired when the `direction` property changes.
50
52
  * @fires {CustomEvent} sorter-changed - Fired when the `path` or `direction` property changes.
@@ -55,11 +57,15 @@ import { GridSorterMixin } from './vaadin-grid-sorter-mixin.js';
55
57
  * @mixes ThemableMixin
56
58
  * @mixes DirMixin
57
59
  */
58
- class GridSorter extends GridSorterMixin(ThemableMixin(DirMixin(PolylitMixin(LitElement)))) {
60
+ class GridSorter extends GridSorterMixin(ThemableMixin(DirMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
59
61
  static get is() {
60
62
  return 'vaadin-grid-sorter';
61
63
  }
62
64
 
65
+ static get styles() {
66
+ return gridSorterStyles;
67
+ }
68
+
63
69
  /** @protected */
64
70
  render() {
65
71
  return html`
@@ -37,7 +37,7 @@ export const GridTreeColumnMixin = (superClass) =>
37
37
  *
38
38
  * @private
39
39
  */
40
- __defaultRenderer(root, _column, { item, expanded, level }) {
40
+ __defaultRenderer(root, _column, { item, expanded, level, hasChildren }) {
41
41
  let toggle = root.firstElementChild;
42
42
  if (!toggle) {
43
43
  toggle = document.createElement('vaadin-grid-tree-toggle');
@@ -48,7 +48,7 @@ export const GridTreeColumnMixin = (superClass) =>
48
48
  toggle.__item = item;
49
49
  toggle.__rendererExpanded = expanded;
50
50
  toggle.expanded = expanded;
51
- toggle.leaf = this.__isLeafItem(item, this._grid.itemHasChildrenPath);
51
+ toggle.leaf = !hasChildren;
52
52
  toggle.textContent = this.__getToggleContent(this.path, item);
53
53
  toggle.level = level;
54
54
  }
@@ -83,11 +83,6 @@ export const GridTreeColumnMixin = (superClass) =>
83
83
  }
84
84
  }
85
85
 
86
- /** @private */
87
- __isLeafItem(item, itemHasChildrenPath) {
88
- return !item || !item[itemHasChildrenPath];
89
- }
90
-
91
86
  /** @private */
92
87
  __getToggleContent(path, item) {
93
88
  return path && get(path, item);