Skip to content

Commit

Permalink
refactor: clean up grid column auto width mixin
Browse files Browse the repository at this point in the history
  • Loading branch information
tomivirkki committed Jan 15, 2025
1 parent 08798b8 commit 6096b16
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 67 deletions.
125 changes: 96 additions & 29 deletions packages/grid/src/vaadin-grid-column-auto-width-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,58 @@ export const ColumnAutoWidthMixin = (superClass) =>
};
}

static get observers() {
return [
'__dataProviderChangedAutoWidth(dataProvider)',
'__columnTreeChangedAutoWidth(_columnTree)',
'__flatSizeChangedAutoWidth(_flatSize)',
];
}

constructor() {
super();
this.addEventListener('animationend', this.__onAnimationEndAutoWidth);
}

/** @private */
__onAnimationEndAutoWidth(e) {
if (e.animationName.indexOf('vaadin-grid-appear') === 0) {
this.__tryToRecalculateColumnWidthsIfPending();
}
}

/** @private */
__dataProviderChangedAutoWidth(_dataProvider) {
if (this.__hasHadRenderedRowsForColumnWidthCalculation) {
return;
}
// Recalculate column widths when the data provider changes if the grid has not yet had any rendered rows
// during previous column width calculations
this.recalculateColumnWidths();
}

/** @private */
__columnTreeChangedAutoWidth(_columnTree) {
// Column tree changed, recalculate column widths
this.recalculateColumnWidths();
}

/** @private */
__flatSizeChangedAutoWidth() {
// Flat size changed, recalculate column widths if pending (asynchronously, to allow grid to render row elements first)
requestAnimationFrame(() => this.__tryToRecalculateColumnWidthsIfPending());
}

/**
* @protected
* @override
*/
_onDataProviderPageLoaded() {
super._onDataProviderPageLoaded();
// Data provider page loaded, recalculate column widths if there's a pending recalculation
this.__tryToRecalculateColumnWidthsIfPending();
}

/** @private */
__getIntrinsicWidth(col) {
if (!this.__intrinsicWidthCache.has(col)) {
Expand Down Expand Up @@ -73,7 +125,7 @@ export const ColumnAutoWidthMixin = (superClass) =>
* @param {!Array<!GridColumn>} cols the columns to auto size based on their content width
* @private
*/
_recalculateColumnWidths(cols) {
_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) => {
Expand All @@ -82,10 +134,7 @@ export const ColumnAutoWidthMixin = (superClass) =>
}
});

// Flush to account for any changes to the visibility of the columns
if (this._debouncerHiddenChanged) {
this._debouncerHiddenChanged.flush();
}
this.__hasHadRenderedRowsForColumnWidthCalculation ||= this._getRenderedRows().length > 0;

this.__intrinsicWidthCache = new Map();
// Cache the viewport rows to avoid unnecessary reflows while measuring the column widths
Expand All @@ -94,6 +143,7 @@ export const ColumnAutoWidthMixin = (superClass) =>
this.__viewportRowsCache = this._getRenderedRows().filter((row) => row.index >= fvi && row.index <= lvi);

// Pre-cache the intrinsic width of each column
const cols = this.__getAutoWidthColumns();
this.__calculateAndCacheIntrinsicWidths(cols);

cols.forEach((col) => {
Expand Down Expand Up @@ -177,30 +227,47 @@ export const ColumnAutoWidthMixin = (superClass) =>
* Updates the `width` of all columns which have `autoWidth` set to `true`.
*/
recalculateColumnWidths() {
if (!this._columnTree) {
return; // No columns
}
if (isElementHidden(this) || this._dataProviderController.isLoading()) {
if (!this.__isReadyForColumnWidthCalculation()) {
this.__pendingRecalculateColumnWidths = true;
return;
}
const cols = this._getColumns().filter((col) => !col.hidden && col.autoWidth);
this._recalculateColumnWidths();
}

const undefinedCols = cols.filter((col) => !customElements.get(col.localName));
if (undefinedCols.length) {
// Some of the columns are not defined yet, wait for them to be defined before measuring
Promise.all(undefinedCols.map((col) => customElements.whenDefined(col.localName))).then(() => {
this._recalculateColumnWidths(cols);
});
} else {
this._recalculateColumnWidths(cols);
/**
* This internal method should be called whenever a condition that may have prevented
* previous column width calculation is resolved.
* @private
*/
__tryToRecalculateColumnWidthsIfPending() {
if (!this.__pendingRecalculateColumnWidths) {
return;
}
this.__pendingRecalculateColumnWidths = false;
this.recalculateColumnWidths();
}

/** @private */
__tryToRecalculateColumnWidthsIfPending() {
if (!this.__pendingRecalculateColumnWidths || isElementHidden(this) || this._dataProviderController.isLoading()) {
return;
__getAutoWidthColumns() {
return this._getColumns().filter((col) => !col.hidden && col.autoWidth);
}

/**
* Returns true if the grid is ready for column width calculation, false otherwise.
* @private
*/
__isReadyForColumnWidthCalculation() {
if (!this._columnTree) {
return false;
}

const undefinedCols = this.__getAutoWidthColumns().filter((col) => !customElements.get(col.localName));
if (undefinedCols.length) {
// Some of the columns are not defined yet, wait for them to be defined before measuring
Promise.all(undefinedCols.map((col) => customElements.whenDefined(col.localName))).then(() => {
this.__tryToRecalculateColumnWidthsIfPending();
});
return false;
}

// Delay recalculation if any rows are missing an index.
Expand All @@ -213,14 +280,14 @@ export const ColumnAutoWidthMixin = (superClass) =>
// before all the data is loaded. Note, rows without index get updated in later iterations
// of the virtualizer update loop, ensuring the grid eventually reaches a stable state.
const hasRowsWithUndefinedIndex = [...this.$.items.children].some((row) => row.index === undefined);
if (hasRowsWithUndefinedIndex) {
return;
}

const hasRowsWithClientHeight = [...this.$.items.children].some((row) => row.clientHeight > 0);
if (hasRowsWithClientHeight) {
this.__pendingRecalculateColumnWidths = false;
this.recalculateColumnWidths();
}
const debouncingHiddenChanged = this._debouncerHiddenChanged && this._debouncerHiddenChanged.isActive();

return (
!this._dataProviderController.isLoading() &&
!hasRowsWithUndefinedIndex &&
!isElementHidden(this) &&
!debouncingHiddenChanged
);
}
};
44 changes: 15 additions & 29 deletions packages/grid/src/vaadin-grid-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,21 @@ import { StylingMixin } from './vaadin-grid-styling-mixin.js';
* @mixes DragAndDropMixin
*/
export const GridMixin = (superClass) =>
class extends ArrayDataProviderMixin(
DataProviderMixin(
DynamicColumnsMixin(
ActiveItemMixin(
ScrollMixin(
SelectionMixin(
SortMixin(
RowDetailsMixin(
KeyboardNavigationMixin(
A11yMixin(
FilterMixin(
ColumnReorderingMixin(
ColumnResizingMixin(
EventContextMixin(
DragAndDropMixin(ColumnAutoWidthMixin(StylingMixin(TabindexMixin(superClass)))),
class extends ColumnAutoWidthMixin(
ArrayDataProviderMixin(
DataProviderMixin(
DynamicColumnsMixin(
ActiveItemMixin(
ScrollMixin(
SelectionMixin(
SortMixin(
RowDetailsMixin(
KeyboardNavigationMixin(
A11yMixin(
FilterMixin(
ColumnReorderingMixin(
ColumnResizingMixin(
EventContextMixin(DragAndDropMixin(StylingMixin(TabindexMixin(superClass)))),
),
),
),
Expand Down Expand Up @@ -197,7 +197,6 @@ export const GridMixin = (superClass) =>
connectedCallback() {
super.connectedCallback();
this.isAttached = true;
this.recalculateColumnWidths();
}

/** @protected */
Expand Down Expand Up @@ -269,7 +268,6 @@ export const GridMixin = (superClass) =>
new ResizeObserver(() =>
setTimeout(() => {
this.__updateColumnsBodyContentHidden();
this.__tryToRecalculateColumnWidthsIfPending();
}),
).observe(this.$.table);

Expand Down Expand Up @@ -348,15 +346,6 @@ export const GridMixin = (superClass) =>
}
}

/**
* @protected
* @override
*/
_onDataProviderPageLoaded() {
super._onDataProviderPageLoaded();
this.__tryToRecalculateColumnWidthsIfPending();
}

/** @private */
_createScrollerRows(count) {
const rows = [];
Expand Down Expand Up @@ -384,7 +373,6 @@ export const GridMixin = (superClass) =>
animationFrame,
() => {
this._afterScroll();
this.__tryToRecalculateColumnWidthsIfPending();
},
);
return rows;
Expand Down Expand Up @@ -670,7 +658,6 @@ export const GridMixin = (superClass) =>
/** @private */
_columnTreeChanged(columnTree) {
this._renderColumnTree(columnTree);
this.recalculateColumnWidths();
this.__updateColumnsBodyContentHidden();
}

Expand Down Expand Up @@ -809,7 +796,6 @@ export const GridMixin = (superClass) =>
// ShadyCSS applies scoping suffixes to animation names
if (e.animationName.indexOf('vaadin-grid-appear') === 0) {
e.stopPropagation();
this.__tryToRecalculateColumnWidthsIfPending();

// Ensure header and footer have tabbable elements
this._resetKeyboardNavigation();
Expand Down
Loading

0 comments on commit 6096b16

Please sign in to comment.