diff --git a/packages/crud/test/dom/__snapshots__/crud.test.snap.js b/packages/crud/test/dom/__snapshots__/crud.test.snap.js index 7482110a352..8828ceb384a 100644 --- a/packages/crud/test/dom/__snapshots__/crud.test.snap.js +++ b/packages/crud/test/dom/__snapshots__/crud.test.snap.js @@ -106,7 +106,7 @@ snapshots["vaadin-crud host default"] = - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + John - + 30 - + ` element for a cell. + */ +class CellContentDirective extends AsyncDirective { + #cell; + + update(part, [grid, slotName]) { + this.#cell = part.parentNode; + this.#cell._content ??= document.createElement('vaadin-grid-cell-content'); + this.#cell._content.slot = slotName; + + if (!grid.contains(this.#cell._content)) { + grid.appendChild(this.#cell._content); + } + + return html``; + } + + disconnected() { + this.#cell._content?.remove(); + } +} + +export const cellContent = directive(CellContentDirective); diff --git a/packages/grid/src/vaadin-grid-column-auto-width-mixin.js b/packages/grid/src/vaadin-grid-column-auto-width-mixin.js index ccc9b902f66..4fe473672e8 100644 --- a/packages/grid/src/vaadin-grid-column-auto-width-mixin.js +++ b/packages/grid/src/vaadin-grid-column-auto-width-mixin.js @@ -137,11 +137,7 @@ export const ColumnAutoWidthMixin = (superClass) => _recalculateColumnWidths() { // Flush to make sure DOM is up-to-date when measuring the column widths this.__virtualizer.flush(); - [...this.$.header.children, ...this.$.footer.children].forEach((row) => { - if (row.__debounceUpdateHeaderFooterRowVisibility) { - row.__debounceUpdateHeaderFooterRowVisibility.flush(); - } - }); + this.__renderHeaderFooterDebouncer?.flush(); this.__hasHadRenderedRowsForColumnWidthCalculation ||= this._getRenderedRows().length > 0; diff --git a/packages/grid/src/vaadin-grid-column-mixin.js b/packages/grid/src/vaadin-grid-column-mixin.js index 8e8dae3c7b7..4cc0a0740a3 100644 --- a/packages/grid/src/vaadin-grid-column-mixin.js +++ b/packages/grid/src/vaadin-grid-column-mixin.js @@ -7,7 +7,8 @@ import { animationFrame } from '@vaadin/component-base/src/async.js'; import { Debouncer } from '@vaadin/component-base/src/debounce.js'; import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js'; import { get } from '@vaadin/component-base/src/path-utils.js'; -import { updateCellState, updatePart } from './vaadin-grid-helpers.js'; +import { generateUniqueId } from '@vaadin/component-base/src/unique-id-utils.js'; +import { updateCellState } from './vaadin-grid-helpers.js'; export const ColumnBaseMixin = (superClass) => class ColumnBaseMixin extends superClass { @@ -270,7 +271,7 @@ export const ColumnBaseMixin = (superClass) => '_onRendererOrBindingChanged(_renderer, _cells, _bodyContentHidden, path)', '_onHeaderRendererOrBindingChanged(_headerRenderer, _headerCell, path, header)', '_onFooterRendererOrBindingChanged(_footerRenderer, _footerCell)', - '_resizableChanged(resizable, _headerCell)', + '_resizableChanged(resizable)', '_reorderStatusChanged(_reorderStatus, _headerCell, _footerCell, _cells)', '_hiddenChanged(hidden, _headerCell, _footerCell, _cells)', '_rowHeaderChanged(rowHeader, _cells)', @@ -302,6 +303,19 @@ export const ColumnBaseMixin = (superClass) => .filter((cell) => cell); } + constructor() { + super(); + + /** + * A stable unique id assigned once per column instance. Used to build + * cell content slot names that stay stable across re-renders, so lit + * can reuse the cell content elements when the column tree changes. + * + * @protected + */ + this._id = generateUniqueId(); + } + /** @protected */ connectedCallback() { super.connectedCallback(); @@ -313,7 +327,7 @@ export const ColumnBaseMixin = (superClass) => return; } - this._allCells.forEach((cell) => { + this._cells?.forEach((cell) => { if (!cell._content.parentNode) { this._grid.appendChild(cell._content); } @@ -332,7 +346,7 @@ export const ColumnBaseMixin = (superClass) => return; } - this._allCells.forEach((cell) => { + this._cells?.forEach((cell) => { if (cell._content.parentNode) { cell._content.parentNode.removeChild(cell._content); } @@ -485,27 +499,12 @@ export const ColumnBaseMixin = (superClass) => } /** @private */ - _resizableChanged(resizable, headerCell) { - if (resizable === undefined || headerCell === undefined) { + _resizableChanged(resizable) { + if (resizable === undefined || this._grid === undefined) { return; } - if (headerCell) { - [headerCell].concat(this._emptyCells).forEach((cell) => { - if (cell) { - const existingHandle = cell.querySelector('[part~="resize-handle"]'); - if (existingHandle) { - cell.removeChild(existingHandle); - } - - if (resizable) { - const handle = document.createElement('div'); - updatePart(handle, 'resize-handle', true); - cell.appendChild(handle); - } - } - }); - } + this._grid.__scheduleRenderHeaderFooter?.(); } /** @private */ @@ -531,7 +530,7 @@ export const ColumnBaseMixin = (superClass) => if (!!hidden !== !!this._previousHidden && this._grid) { if (hidden === true) { - this._allCells.forEach((cell) => { + this._cells?.forEach((cell) => { if (cell._content.parentNode) { cell._content.parentNode.removeChild(cell._content); } @@ -632,9 +631,8 @@ export const ColumnBaseMixin = (superClass) => } this.__renderCellsContent(headerRenderer, [headerCell]); - if (this._grid && headerCell.parentElement) { - this._grid.__debounceUpdateHeaderFooterRowVisibility(headerCell.parentElement); - } + + this._grid?.__scheduleRenderHeaderFooter(); } /** @protected */ @@ -689,9 +687,8 @@ export const ColumnBaseMixin = (superClass) => } this.__renderCellsContent(footerRenderer, [footerCell]); - if (this._grid && footerCell.parentElement) { - this._grid.__debounceUpdateHeaderFooterRowVisibility(footerCell.parentElement); - } + + this._grid?.__scheduleRenderHeaderFooter(); } /** @protected */ diff --git a/packages/grid/src/vaadin-grid-column-rendering-mixin.js b/packages/grid/src/vaadin-grid-column-rendering-mixin.js new file mode 100644 index 00000000000..ef23d29f9f7 --- /dev/null +++ b/packages/grid/src/vaadin-grid-column-rendering-mixin.js @@ -0,0 +1,195 @@ +/** + * @license + * Copyright (c) 2016 - 2026 Vaadin Ltd. + * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ + */ +import { html, nothing, render } from 'lit'; +import { cache } from 'lit/directives/cache.js'; +import { repeat } from 'lit/directives/repeat.js'; +import { microTask } from '@vaadin/component-base/src/async.js'; +import { Debouncer } from '@vaadin/component-base/src/debounce.js'; +import { cellContent } from './directives/cell-content-directive.js'; + +function isEmptyCell(column, level, columnTree) { + const isColumnRow = level === columnTree.length - 1; + return !isColumnRow && column.localName !== 'vaadin-grid-column-group'; +} + +function isHeaderRowVisible(columns, level, columnTree) { + return columns.some((column) => { + if (column.hidden || isEmptyCell(column, level, columnTree)) { + return false; + } + + if (column.headerRenderer) { + // The column has a header renderer -> row should be visible + return true; + } + + if (column.header === null) { + // The column header is explicitly set to null -> doesn't block hiding the row + return false; + } + + return column.path || column.header !== undefined; + }); +} + +function isFooterRowVisible(columns, level, columnTree) { + return columns.some((column) => { + if (column.hidden || isEmptyCell(column, level, columnTree)) { + return false; + } + + return column.footerRenderer; + }); +} + +/** + * A mixin providing rendering of rows based on the column tree. + */ +export const ColumnRenderingMixin = (superClass) => + class ColumnRenderingMixin extends superClass { + /** @private */ + __scheduleRenderHeaderFooter() { + this.__renderHeaderFooterDebouncer = Debouncer.debounce(this.__renderHeaderFooterDebouncer, microTask, () => { + this.__renderHeaderFooter(); + }); + } + + /** @private */ + __renderHeaderFooter() { + this.__renderHeaderFooterDebouncer?.cancel(); + + const sortedColumnTree = (this._columnTree ?? []).map((columns) => { + return columns.toSorted((a, b) => a._order - b._order); + }); + + sortedColumnTree.flat().forEach((column) => { + column._emptyCells = []; + }); + + this.#renderHeader(sortedColumnTree); + this.#renderFooter(sortedColumnTree); + + this._resetKeyboardNavigation(); + this.__a11yUpdateGridSize(this.size, this._columnTree, this.__emptyState); + } + + #renderHeader(columnTree) { + render(columnTree.map(this.#renderHeaderRow), this.$.header, { host: this }); + + this.$.table.toggleAttribute('has-header', !!this.$.header.querySelector('tr:not([hidden])')); + this.__updateHeaderFooterRowParts('header'); + + this.$.header.querySelectorAll('.header-cell').forEach((cell) => { + const column = cell._column; + const isColumnRow = cell.parentElement === this.$.header.lastElementChild; + if (isColumnRow || column.localName === 'vaadin-grid-column-group') { + column._headerCell = cell; + } else { + column._emptyCells.push(cell); + } + }); + } + + #renderHeaderRow = (columns, level, columnTree) => { + return html` + + ${repeat( + columns, + (column) => column._id, + (column) => { + // `cache` keeps the cell and its rendered content when the + // column gets hidden, so it can be restored as-is when the + // column is shown again. + if (column.hidden) { + return cache(nothing); + } + + return cache(html` + + ${cellContent(this, `vaadin-grid-header-cell-content-${level}-${column._id}`)} + ${column.resizable ? html`
` : nothing} + + `); + }, + )} + + `; + }; + + #renderFooter(columnTree) { + render(columnTree.map(this.#renderFooterRow).toReversed(), this.$.footer, { host: this }); + + this.$.table.toggleAttribute('has-footer', !!this.$.footer.querySelector('tr:not([hidden])')); + this.__updateHeaderFooterRowParts('footer'); + + this.$.footer.querySelectorAll('.footer-cell').forEach((cell) => { + const column = cell._column; + const isColumnRow = cell.parentElement === this.$.footer.firstElementChild; + if (isColumnRow || column.localName === 'vaadin-grid-column-group') { + column._footerCell = cell; + } else { + column._emptyCells.push(cell); + } + }); + } + + #renderFooterRow = (columns, level, columnTree) => { + return html` + + ${repeat( + columns, + (column) => column._id, + (column) => { + // `cache` keeps the cell and its rendered content when the + // column gets hidden, so it can be restored as-is when the + // column is shown again. + if (column.hidden) { + return cache(nothing); + } + + return cache(html` + + ${cellContent(this, `vaadin-grid-footer-cell-content-${level}-${column._id}`)} + + `); + }, + )} + + `; + }; + }; diff --git a/packages/grid/src/vaadin-grid-column-reordering-mixin.js b/packages/grid/src/vaadin-grid-column-reordering-mixin.js index fe04625a44b..43d7082762d 100644 --- a/packages/grid/src/vaadin-grid-column-reordering-mixin.js +++ b/packages/grid/src/vaadin-grid-column-reordering-mixin.js @@ -203,6 +203,8 @@ export const ColumnReorderingMixin = (superClass) => for (let i = startIndex; i !== endIndex; i += direction) { this._swapColumnOrders(this._draggedColumn, levelColumnsInOrder[i + direction]); } + + this.__renderHeaderFooter(); } this._updateGhostPosition(e.detail.x, this._touchDevice ? e.detail.y - 50 : e.detail.y); @@ -434,7 +436,7 @@ export const ColumnReorderingMixin = (superClass) => } /** - * Swaps column orders and physically reorders cells in all rows. + * Swaps column orders and reorders cells in all rows. * @param {!GridColumn} column1 * @param {!GridColumn} column2 * @protected @@ -444,8 +446,7 @@ export const ColumnReorderingMixin = (superClass) => [column1._order, column2._order] = [column2._order, column1._order]; const [firstColumn, secondColumn] = column1._order < column2._order ? [column1, column2] : [column2, column1]; - // Reorder cells in all rows (header, footer, body, sizer) - [...this.$.header.children, ...this.$.footer.children, ...this.$.items.children, this.$.sizer].forEach((row) => { + [...this.$.items.children, this.$.sizer].forEach((row) => { const cells = getBodyRowCells(row); const firstColumnCells = cells.filter((cell) => firstColumn.contains(cell._column)); const secondColumnFirstCell = cells.find((cell) => secondColumn.contains(cell._column)); @@ -456,6 +457,7 @@ export const ColumnReorderingMixin = (superClass) => } }); + this.__scheduleRenderHeaderFooter(); this._debounceUpdateFrozenColumn(); this._updateFirstAndLastColumn(); } diff --git a/packages/grid/src/vaadin-grid-mixin.js b/packages/grid/src/vaadin-grid-mixin.js index 96b56be0a60..ce65503cbc7 100644 --- a/packages/grid/src/vaadin-grid-mixin.js +++ b/packages/grid/src/vaadin-grid-mixin.js @@ -4,9 +4,7 @@ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ */ import { TabindexMixin } from '@vaadin/a11y-base/src/tabindex-mixin.js'; -import { microTask } from '@vaadin/component-base/src/async.js'; import { isAndroid, isIOS, isSafari, isTouch } from '@vaadin/component-base/src/browser-utils.js'; -import { Debouncer } from '@vaadin/component-base/src/debounce.js'; import { setTouchAction } from '@vaadin/component-base/src/gestures.js'; import { SlotObserver } from '@vaadin/component-base/src/slot-observer.js'; import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js'; @@ -15,6 +13,7 @@ import { A11yMixin } from './vaadin-grid-a11y-mixin.js'; import { ActiveItemMixin } from './vaadin-grid-active-item-mixin.js'; import { ArrayDataProviderMixin } from './vaadin-grid-array-data-provider-mixin.js'; import { ColumnAutoWidthMixin } from './vaadin-grid-column-auto-width-mixin.js'; +import { ColumnRenderingMixin } from './vaadin-grid-column-rendering-mixin.js'; import { ColumnReorderingMixin } from './vaadin-grid-column-reordering-mixin.js'; import { ColumnResizingMixin } from './vaadin-grid-column-resizing-mixin.js'; import { DataProviderMixin } from './vaadin-grid-data-provider-mixin.js'; @@ -48,17 +47,21 @@ export const GridMixin = (superClass) => ArrayDataProviderMixin( DataProviderMixin( DynamicColumnsMixin( - ActiveItemMixin( - ScrollMixin( - SelectionMixin( - SortMixin( - RowDetailsMixin( - KeyboardNavigationMixin( - A11yMixin( - FilterMixin( - ColumnReorderingMixin( - ColumnResizingMixin( - EventContextMixin(DragAndDropMixin(StylingMixin(TabindexMixin(ResizeMixin(superClass))))), + ColumnRenderingMixin( + ActiveItemMixin( + ScrollMixin( + SelectionMixin( + SortMixin( + RowDetailsMixin( + KeyboardNavigationMixin( + A11yMixin( + FilterMixin( + ColumnReorderingMixin( + ColumnResizingMixin( + EventContextMixin( + DragAndDropMixin(StylingMixin(TabindexMixin(ResizeMixin(superClass)))), + ), + ), ), ), ), @@ -351,7 +354,7 @@ export const GridMixin = (superClass) => updatePart(row, 'row', true); updatePart(row, 'body-row', true); if (this._columnTree) { - this.__initRow(row, this._columnTree[this._columnTree.length - 1], 'body', false, true); + this.__initRow(row, this._columnTree[this._columnTree.length - 1], 'body', true); } rows.push(row); } @@ -444,11 +447,10 @@ export const GridMixin = (superClass) => * @param {!HTMLTableRowElement} row * @param {!Array} columns * @param {?string} section - * @param {boolean} isColumnRow * @param {boolean} noNotify * @private */ - __initRow(row, columns, section = 'body', isColumnRow = false, noNotify = false) { + __initRow(row, columns, section = 'body', noNotify = false) { const contentsFragment = document.createDocumentFragment(); iterateRowCells(row, (cell) => { @@ -516,30 +518,6 @@ export const GridMixin = (superClass) => if (!noNotify) { column._cells = [...column._cells]; } - } else { - // Header & footer - const tagName = section === 'header' ? 'th' : 'td'; - if (isColumnRow || column.localName === 'vaadin-grid-column-group') { - cell = column[`_${section}Cell`]; - if (!cell) { - cell = this._createCell(tagName); - } - cell._column = column; - row.appendChild(cell); - column[`_${section}Cell`] = cell; - } else { - if (!column._emptyCells) { - column._emptyCells = []; - } - cell = column._emptyCells.find((cell) => cell._vacant) || this._createCell(tagName); - cell._column = column; - row.appendChild(cell); - if (column._emptyCells.indexOf(cell) === -1) { - column._emptyCells.push(cell); - } - } - updatePart(cell, 'cell', true); - updatePart(cell, `${section}-cell`, true); } if (!cell._content.parentElement) { @@ -549,10 +527,6 @@ export const GridMixin = (superClass) => cell._column = column; }); - if (section !== 'body') { - this.__debounceUpdateHeaderFooterRowVisibility(row); - } - // Might be empty if only cache was used this.appendChild(contentsFragment); @@ -560,75 +534,6 @@ export const GridMixin = (superClass) => this._updateFirstAndLastColumnForRow(row); } - /** - * @param {HTMLTableRowElement} row - * @protected - */ - __debounceUpdateHeaderFooterRowVisibility(row) { - row.__debounceUpdateHeaderFooterRowVisibility = Debouncer.debounce( - row.__debounceUpdateHeaderFooterRowVisibility, - microTask, - () => this.__updateHeaderFooterRowVisibility(row), - ); - } - - /** - * @param {HTMLTableRowElement} row - * @protected - */ - __updateHeaderFooterRowVisibility(row) { - if (!row) { - return; - } - - const visibleRowCells = Array.from(row.children).filter((cell) => { - const column = cell._column; - if (column._emptyCells && column._emptyCells.indexOf(cell) > -1) { - // The cell is an "empty cell" -> doesn't block hiding the row - return false; - } - if (row.parentElement === this.$.header) { - if (column.headerRenderer) { - // The cell is the header cell of a column that has a header renderer - // -> row should be visible - return true; - } - if (column.header === null) { - // The column header is explicilty set to null -> doesn't block hiding the row - return false; - } - if (column.path || column.header !== undefined) { - // The column has an explicit non-null header or a path that generates a header - // -> row should be visible - return true; - } - } else if (column.footerRenderer) { - // The cell is the footer cell of a column that has a footer renderer - // -> row should be visible - return true; - } - return false; - }); - - if (row.hidden !== !visibleRowCells.length) { - row.hidden = !visibleRowCells.length; - } - - if (row.parentElement === this.$.header) { - this.$.table.toggleAttribute('has-header', this.$.header.querySelector('tr:not([hidden])')); - this.__updateHeaderFooterRowParts('header'); - } - - if (row.parentElement === this.$.footer) { - this.$.table.toggleAttribute('has-footer', this.$.footer.querySelector('tr:not([hidden])')); - this.__updateHeaderFooterRowParts('footer'); - } - - // Make sure the section has a tabbable element - this._resetKeyboardNavigation(); - this.__a11yUpdateGridSize(this.size, this._columnTree, this.__emptyState); - } - /** @private */ __updateVirtualizerElement(row, index) { this._preventScrollerRotatingCellFocus(row, index); @@ -681,43 +586,15 @@ export const GridMixin = (superClass) => */ _renderColumnTree(columnTree) { iterateChildren(this.$.items, (row) => { - this.__initRow(row, columnTree[columnTree.length - 1], 'body', false, true); + this.__initRow(row, columnTree[columnTree.length - 1], 'body', true); this.__updateRow(row); }); - while (this.$.header.children.length < columnTree.length) { - const headerRow = document.createElement('tr'); - headerRow.setAttribute('role', 'row'); - headerRow.setAttribute('tabindex', '-1'); - updatePart(headerRow, 'row', true); - updatePart(headerRow, 'header-row', true); - this.$.header.appendChild(headerRow); - - const footerRow = document.createElement('tr'); - footerRow.setAttribute('role', 'row'); - footerRow.setAttribute('tabindex', '-1'); - updatePart(footerRow, 'row', true); - updatePart(footerRow, 'footer-row', true); - this.$.footer.appendChild(footerRow); - } - while (this.$.header.children.length > columnTree.length) { - this.$.header.removeChild(this.$.header.firstElementChild); - this.$.footer.removeChild(this.$.footer.firstElementChild); - } - - iterateChildren(this.$.header, (headerRow, index) => { - this.__initRow(headerRow, columnTree[index], 'header', index === columnTree.length - 1); - }); - - iterateChildren(this.$.footer, (footerRow, index) => { - this.__initRow(footerRow, columnTree[columnTree.length - 1 - index], 'footer', index === 0); - }); + this.__renderHeaderFooter(); // Sizer rows this.__initRow(this.$.sizer, columnTree[columnTree.length - 1]); - this.__updateHeaderFooterRowParts('header'); - this.__updateHeaderFooterRowParts('footer'); this._resizeHandler(); this._frozenCellsChanged(); this._updateFirstAndLastColumn(); @@ -739,6 +616,8 @@ export const GridMixin = (superClass) => updatePart(cell, `first-${section}-row-cell`, row === visibleRows.at(0)); updatePart(cell, `last-${section}-row-cell`, row === visibleRows.at(-1)); }); + + this._updateFirstAndLastColumnForRow(row); }); } diff --git a/packages/grid/src/vaadin-grid-sort-column-mixin.js b/packages/grid/src/vaadin-grid-sort-column-mixin.js index 52bf4a5c058..5f209e2d5c2 100644 --- a/packages/grid/src/vaadin-grid-sort-column-mixin.js +++ b/packages/grid/src/vaadin-grid-sort-column-mixin.js @@ -46,16 +46,25 @@ export const GridSortColumnMixin = (superClass) => */ _defaultHeaderRenderer(root, _column) { let sorter = root.firstElementChild; - if (!sorter) { + const isNewSorter = !sorter; + if (isNewSorter) { sorter = document.createElement('vaadin-grid-sorter'); sorter.addEventListener('direction-changed', this.__boundOnDirectionChanged); - root.appendChild(sorter); } sorter.path = this.path; sorter.__rendererDirection = this.direction; sorter.direction = this.direction; sorter.textContent = this.__getHeader(this.header, this.path); + + // Append the sorter only after its direction has been set. If the cell + // content is already connected (as with the declarative header rendering), + // appending an unconfigured sorter makes it notify its default `null` + // direction before `__rendererDirection` is set, which would reset the + // column's direction. See __onDirectionChanged. + if (isNewSorter) { + root.appendChild(sorter); + } } /** diff --git a/packages/grid/test/column-groups.test.js b/packages/grid/test/column-groups.test.js index e59e933d3df..f176840b5d7 100644 --- a/packages/grid/test/column-groups.test.js +++ b/packages/grid/test/column-groups.test.js @@ -328,7 +328,7 @@ describe('column groups', () => { group.footerRenderer = attributeRenderer('footer'); }); - sinon.spy(grid, '__updateHeaderFooterRowVisibility'); + sinon.spy(grid, '__renderHeaderFooter'); sinon.spy(grid, '_updateColumnTree'); grid.dataProvider = infiniteDataProvider; flushGrid(grid); @@ -336,12 +336,12 @@ describe('column groups', () => { await nextResize(grid); }); - it('should update header and footer rows visibility once', () => { - // 6 header and footer rows are created - expect(grid.__updateHeaderFooterRowVisibility.callCount).to.equal(6); + it('should not update header and footer rows too many times', () => { + // One from _updateColumnTree, another one from column observers + expect(grid.__renderHeaderFooter.callCount).to.equal(2); }); - it('should update column tree once', () => { + it('should not update column tree too many times', () => { expect(grid._updateColumnTree.callCount).to.equal(1); }); diff --git a/packages/grid/test/column-resizing.test.js b/packages/grid/test/column-resizing.test.js index 1f31518e99e..b087e8c75d6 100644 --- a/packages/grid/test/column-resizing.test.js +++ b/packages/grid/test/column-resizing.test.js @@ -174,6 +174,7 @@ describe('column resizing', () => { it('should fix width for preceding columns', () => { grid._columnTree[0][1].resizable = true; + flushGrid(grid); grid._columnTree[0][0].width = '50%'; grid._columnTree[0][0].flexGrow = 1; diff --git a/packages/grid/test/dom/__snapshots__/grid.test.snap.js b/packages/grid/test/dom/__snapshots__/grid.test.snap.js index 051a5b8e442..f699d730e82 100644 --- a/packages/grid/test/dom/__snapshots__/grid.test.snap.js +++ b/packages/grid/test/dom/__snapshots__/grid.test.snap.js @@ -7,30 +7,30 @@ snapshots["vaadin-grid basic host default"] = - + First - + Last - + - + - + - + - + Laura - + Arnaud - + Fabien - + Le gall @@ -61,25 +61,25 @@ snapshots["vaadin-grid basic shadow default"] = - + - + @@ -100,25 +100,23 @@ snapshots["vaadin-grid basic shadow default"] = - + - + @@ -145,26 +143,26 @@ snapshots["vaadin-grid basic shadow default"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell" first-column="" - id="vaadin-grid-cell-6" + id="vaadin-grid-cell-2" part="cell body-cell first-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="0" > - + - + @@ -185,26 +183,26 @@ snapshots["vaadin-grid basic shadow default"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-row-cell odd-row-cell" first-column="" - id="vaadin-grid-cell-8" + id="vaadin-grid-cell-4" part="cell body-cell first-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="-1" > - + - + @@ -236,31 +234,28 @@ snapshots["vaadin-grid basic shadow default"] = hidden="" part="row footer-row" role="row" - style="--_grid-horizontal-scroll-position: 0px;" tabindex="-1" > - + - + @@ -306,25 +301,25 @@ snapshots["vaadin-grid basic shadow selected"] = - + - + @@ -345,25 +340,23 @@ snapshots["vaadin-grid basic shadow selected"] = - + - + @@ -391,26 +384,26 @@ snapshots["vaadin-grid basic shadow selected"] = aria-selected="true" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell selected-row-cell" first-column="" - id="vaadin-grid-cell-6" + id="vaadin-grid-cell-2" part="cell body-cell first-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell selected-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="0" > - + - + @@ -431,26 +424,26 @@ snapshots["vaadin-grid basic shadow selected"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-row-cell odd-row-cell" first-column="" - id="vaadin-grid-cell-8" + id="vaadin-grid-cell-4" part="cell body-cell first-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="-1" > - + - + @@ -482,31 +475,28 @@ snapshots["vaadin-grid basic shadow selected"] = hidden="" part="row footer-row" role="row" - style="--_grid-horizontal-scroll-position: 0px;" tabindex="-1" > - + - + @@ -552,25 +542,25 @@ snapshots["vaadin-grid basic shadow details opened"] = - + - + @@ -591,25 +581,23 @@ snapshots["vaadin-grid basic shadow details opened"] = - + - + @@ -636,26 +624,26 @@ snapshots["vaadin-grid basic shadow details opened"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell" first-column="" - id="vaadin-grid-cell-6" + id="vaadin-grid-cell-2" part="cell body-cell first-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="0" > - + - + @@ -676,26 +664,26 @@ snapshots["vaadin-grid basic shadow details opened"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-row-cell odd-row-cell" first-column="" - id="vaadin-grid-cell-8" + id="vaadin-grid-cell-4" part="cell body-cell first-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="-1" > - + - + @@ -727,31 +715,28 @@ snapshots["vaadin-grid basic shadow details opened"] = hidden="" part="row footer-row" role="row" - style="--_grid-horizontal-scroll-position: 0px;" tabindex="-1" > - + - + @@ -797,14 +782,14 @@ snapshots["vaadin-grid basic shadow hidden column"] = - + @@ -825,14 +810,13 @@ snapshots["vaadin-grid basic shadow hidden column"] = - + @@ -859,14 +843,14 @@ snapshots["vaadin-grid basic shadow hidden column"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell last-column-cell" first-column="" - id="vaadin-grid-cell-7" + id="vaadin-grid-cell-3" last-column="" part="cell body-cell last-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="0" > - + @@ -887,14 +871,14 @@ snapshots["vaadin-grid basic shadow hidden column"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-column-cell last-row-cell odd-row-cell" first-column="" - id="vaadin-grid-cell-9" + id="vaadin-grid-cell-5" last-column="" part="cell body-cell last-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="-1" > - + @@ -926,20 +910,18 @@ snapshots["vaadin-grid basic shadow hidden column"] = hidden="" part="row footer-row" role="row" - style="--_grid-horizontal-scroll-position: 0px;" tabindex="-1" > - + @@ -985,14 +967,14 @@ snapshots["vaadin-grid basic shadow hidden column selected"] = - + @@ -1013,14 +995,13 @@ snapshots["vaadin-grid basic shadow hidden column selected"] = - + @@ -1048,14 +1029,14 @@ snapshots["vaadin-grid basic shadow hidden column selected"] = aria-selected="true" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell last-column-cell selected-row-cell" first-column="" - id="vaadin-grid-cell-7" + id="vaadin-grid-cell-3" last-column="" part="cell body-cell last-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell selected-row-cell first-column-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="0" > - + @@ -1076,14 +1057,14 @@ snapshots["vaadin-grid basic shadow hidden column selected"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-column-cell last-row-cell odd-row-cell" first-column="" - id="vaadin-grid-cell-9" + id="vaadin-grid-cell-5" last-column="" part="cell body-cell last-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="-1" > - + @@ -1115,20 +1096,18 @@ snapshots["vaadin-grid basic shadow hidden column selected"] = hidden="" part="row footer-row" role="row" - style="--_grid-horizontal-scroll-position: 0px;" tabindex="-1" > - + @@ -1175,25 +1154,25 @@ snapshots["vaadin-grid basic shadow with footer"] = - + - + @@ -1214,25 +1193,23 @@ snapshots["vaadin-grid basic shadow with footer"] = - + - + @@ -1259,26 +1236,26 @@ snapshots["vaadin-grid basic shadow with footer"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell" first-column="" - id="vaadin-grid-cell-6" + id="vaadin-grid-cell-2" part="cell body-cell first-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="0" > - + - + @@ -1299,26 +1276,26 @@ snapshots["vaadin-grid basic shadow with footer"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-row-cell odd-row-cell" first-column="" - id="vaadin-grid-cell-8" + id="vaadin-grid-cell-4" part="cell body-cell first-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="-1" > - + - + @@ -1349,31 +1326,28 @@ snapshots["vaadin-grid basic shadow with footer"] = class="first-footer-row footer-row last-footer-row row" part="row footer-row first-footer-row last-footer-row" role="row" - style="--_grid-horizontal-scroll-position: 0px;" tabindex="-1" > - + - + @@ -1420,25 +1394,25 @@ snapshots["vaadin-grid column groups default"] = - + - + @@ -1461,21 +1435,20 @@ snapshots["vaadin-grid column groups default"] = class="cell first-column-cell header-cell last-column-cell" colspan="2" first-column="" - id="vaadin-grid-cell-0" last-column="" part="cell header-cell first-column-cell last-column-cell" role="columnheader" style="width: calc(200px); flex-grow: 2;" tabindex="-1" > - + - + - + @@ -1528,26 +1499,26 @@ snapshots["vaadin-grid column groups default"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell" first-column="" - id="vaadin-grid-cell-8" + id="vaadin-grid-cell-2" part="cell body-cell first-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="0" > - + - + @@ -1568,26 +1539,26 @@ snapshots["vaadin-grid column groups default"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-row-cell odd-row-cell" first-column="" - id="vaadin-grid-cell-10" + id="vaadin-grid-cell-4" part="cell body-cell first-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="-1" > - + - + @@ -1624,25 +1595,23 @@ snapshots["vaadin-grid column groups default"] = - + - + @@ -1659,14 +1628,13 @@ snapshots["vaadin-grid column groups default"] = class="cell first-column-cell footer-cell last-column-cell" colspan="2" first-column="" - id="vaadin-grid-cell-5" last-column="" part="cell footer-cell first-column-cell last-column-cell" role="gridcell" style="width: calc(200px); flex-grow: 2;" tabindex="-1" > - + @@ -1706,14 +1674,13 @@ snapshots["vaadin-grid column groups with header"] = class="cell first-column-cell first-header-row-cell header-cell last-column-cell" colspan="2" first-column="" - id="vaadin-grid-cell-0" last-column="" part="cell header-cell first-column-cell last-column-cell first-header-row-cell" role="columnheader" style="width: calc(200px); flex-grow: 2;" tabindex="-1" > - + @@ -1728,25 +1695,23 @@ snapshots["vaadin-grid column groups with header"] = - + - + @@ -1771,25 +1736,23 @@ snapshots["vaadin-grid column groups with footer"] = - + - + @@ -1805,14 +1768,13 @@ snapshots["vaadin-grid column groups with footer"] = class="cell first-column-cell footer-cell last-column-cell last-footer-row-cell" colspan="2" first-column="" - id="vaadin-grid-cell-5" last-column="" part="cell footer-cell first-column-cell last-column-cell last-footer-row-cell" role="gridcell" style="width: calc(200px); flex-grow: 2;" tabindex="-1" > - + @@ -1843,14 +1805,14 @@ snapshots["vaadin-grid hidden column group with group header"] = - + @@ -1871,14 +1833,13 @@ snapshots["vaadin-grid hidden column group with group header"] = - + @@ -1888,20 +1849,18 @@ snapshots["vaadin-grid hidden column group with group header"] = hidden="" part="row header-row" role="row" - style="--_grid-horizontal-scroll-position: 0px;" tabindex="-1" > - + @@ -1928,14 +1887,14 @@ snapshots["vaadin-grid hidden column group with group header"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell last-column-cell" first-column="" - id="vaadin-grid-cell-5" + id="vaadin-grid-cell-1" last-column="" part="cell body-cell first-column-cell last-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="0" > - + @@ -1956,14 +1915,14 @@ snapshots["vaadin-grid hidden column group with group header"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-column-cell last-row-cell odd-row-cell" first-column="" - id="vaadin-grid-cell-6" + id="vaadin-grid-cell-2" last-column="" part="cell body-cell first-column-cell last-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="-1" > - + @@ -1995,20 +1954,18 @@ snapshots["vaadin-grid hidden column group with group header"] = hidden="" part="row footer-row" role="row" - style="--_grid-horizontal-scroll-position: 0px;" tabindex="-1" > - + @@ -2023,14 +1980,13 @@ snapshots["vaadin-grid hidden column group with group header"] = - + @@ -2076,14 +2032,14 @@ snapshots["vaadin-grid hidden column group with group and column header"] = - + @@ -2104,14 +2060,13 @@ snapshots["vaadin-grid hidden column group with group and column header"] = - + @@ -2126,14 +2081,13 @@ snapshots["vaadin-grid hidden column group with group and column header"] = - + @@ -2160,14 +2114,14 @@ snapshots["vaadin-grid hidden column group with group and column header"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell last-column-cell" first-column="" - id="vaadin-grid-cell-5" + id="vaadin-grid-cell-1" last-column="" part="cell body-cell first-column-cell last-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="0" > - + @@ -2188,14 +2142,14 @@ snapshots["vaadin-grid hidden column group with group and column header"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-column-cell last-row-cell odd-row-cell" first-column="" - id="vaadin-grid-cell-6" + id="vaadin-grid-cell-2" last-column="" part="cell body-cell first-column-cell last-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="-1" > - + @@ -2227,20 +2181,18 @@ snapshots["vaadin-grid hidden column group with group and column header"] = hidden="" part="row footer-row" role="row" - style="--_grid-horizontal-scroll-position: 0px;" tabindex="-1" > - + @@ -2255,14 +2207,13 @@ snapshots["vaadin-grid hidden column group with group and column header"] = - + @@ -2307,14 +2258,14 @@ snapshots["vaadin-grid hidden column group with group footer"] = - + @@ -2335,14 +2286,13 @@ snapshots["vaadin-grid hidden column group with group footer"] = - + @@ -2352,20 +2302,18 @@ snapshots["vaadin-grid hidden column group with group footer"] = hidden="" part="row header-row" role="row" - style="--_grid-horizontal-scroll-position: 0px;" tabindex="-1" > - + @@ -2392,14 +2340,14 @@ snapshots["vaadin-grid hidden column group with group footer"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell last-column-cell" first-column="" - id="vaadin-grid-cell-5" + id="vaadin-grid-cell-1" last-column="" part="cell body-cell first-column-cell last-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="0" > - + @@ -2420,14 +2368,14 @@ snapshots["vaadin-grid hidden column group with group footer"] = aria-selected="false" class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-column-cell last-row-cell odd-row-cell" first-column="" - id="vaadin-grid-cell-6" + id="vaadin-grid-cell-2" last-column="" part="cell body-cell first-column-cell last-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell" role="gridcell" style="width: 100px; flex-grow: 1;" tabindex="-1" > - + @@ -2459,20 +2407,18 @@ snapshots["vaadin-grid hidden column group with group footer"] = hidden="" part="row footer-row" role="row" - style="--_grid-horizontal-scroll-position: 0px;" tabindex="-1" > - + @@ -2487,14 +2433,13 @@ snapshots["vaadin-grid hidden column group with group footer"] = - + diff --git a/packages/grid/test/helpers.js b/packages/grid/test/helpers.js index 061f9b5fcb0..5688fd9acfd 100644 --- a/packages/grid/test/helpers.js +++ b/packages/grid/test/helpers.js @@ -15,14 +15,9 @@ export const flushGrid = (grid) => { grid._debouncerHiddenChanged, grid._debouncerApplyCachedData, grid.__debounceUpdateFrozenColumn, + grid.__renderHeaderFooterDebouncer, ].forEach((debouncer) => debouncer?.flush()); - [...grid.$.header.children, ...grid.$.footer.children].forEach((row) => { - if (row.__debounceUpdateHeaderFooterRowVisibility) { - row.__debounceUpdateHeaderFooterRowVisibility.flush(); - } - }); - grid.__virtualizer.flush(); grid.__preventScrollerRotatingCellFocusDebouncer?.flush(); grid.performUpdate?.(); diff --git a/packages/grid/test/keyboard-navigation-cell-button.test.js b/packages/grid/test/keyboard-navigation-cell-button.test.js index 89418c6a473..68d21422dbf 100644 --- a/packages/grid/test/keyboard-navigation-cell-button.test.js +++ b/packages/grid/test/keyboard-navigation-cell-button.test.js @@ -98,6 +98,6 @@ describe('keyboard navigation - focus button mode', () => { it('should not create a focusable div with role="button" inside the header cell', () => { const headerCell = getHeaderCell(grid, 0); - expect(headerCell.firstChild.localName).to.equal('slot'); + expect(headerCell.firstElementChild.localName).to.equal('slot'); }); });