From 6ad95b1ccc035b9615072b22959f5ee42af32757 Mon Sep 17 00:00:00 2001 From: jcgueriaud1 Date: Wed, 17 Jul 2024 09:28:39 +0300 Subject: [PATCH 1/7] Add min-width on the columns --- packages/grid/src/vaadin-grid-column-mixin.js | 24 ++++ .../src/vaadin-grid-column-resizing-mixin.js | 9 +- packages/grid/src/vaadin-grid-mixin.js | 18 ++- .../column-auto-width-min-width-lit.test.js | 3 + ...olumn-auto-width-min-width-polymer.test.js | 2 + .../column-auto-width-min-width.common.js | 105 ++++++++++++++++++ 6 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 packages/grid/test/column-auto-width-min-width-lit.test.js create mode 100644 packages/grid/test/column-auto-width-min-width-polymer.test.js create mode 100644 packages/grid/test/column-auto-width-min-width.common.js diff --git a/packages/grid/src/vaadin-grid-column-mixin.js b/packages/grid/src/vaadin-grid-column-mixin.js index 62200a1393..a6366bd7cf 100644 --- a/packages/grid/src/vaadin-grid-column-mixin.js +++ b/packages/grid/src/vaadin-grid-column-mixin.js @@ -268,6 +268,7 @@ export const ColumnBaseMixin = (superClass) => static get observers() { return [ '_widthChanged(width, _headerCell, _footerCell, _cells)', + '_minWidthChanged(minWidth, _headerCell, _footerCell, _cells)', '_frozenChanged(frozen, _headerCell, _footerCell, _cells)', '_frozenToEndChanged(frozenToEnd, _headerCell, _footerCell, _cells)', '_flexGrowChanged(flexGrow, _headerCell, _footerCell, _cells)', @@ -406,6 +407,17 @@ export const ColumnBaseMixin = (superClass) => }); } + /** @private */ + _minWidthChanged(minWidth) { + if (this.parentElement && this.parentElement._columnPropChanged) { + this.parentElement._columnPropChanged('minWidth'); + } + + this._allCells.forEach((cell) => { + cell.style.minWidth = minWidth; + }); + } + /** @private */ _frozenChanged(frozen) { if (this.parentElement && this.parentElement._columnPropChanged) { @@ -863,6 +875,18 @@ export const GridColumnMixin = (superClass) => value: '100px', sync: true, }, + /** + * Min-width of the cells for this column. + * + * Please note that using the `em` length unit is discouraged as + * it might lead to misalignment issues if the header, body, and footer + * cells have different font sizes. Instead, use `rem` if you need + * a length unit relative to the font size. + */ + minWidth: { + type: String, + sync: true, + }, /** * Flex grow ratio for the cell widths. When set to 0, cell width is fixed. diff --git a/packages/grid/src/vaadin-grid-column-resizing-mixin.js b/packages/grid/src/vaadin-grid-column-resizing-mixin.js index a2c8f7e6e5..d911abaa05 100644 --- a/packages/grid/src/vaadin-grid-column-resizing-mixin.js +++ b/packages/grid/src/vaadin-grid-column-resizing-mixin.js @@ -77,9 +77,12 @@ export const ColumnResizingMixin = (superClass) => } else { maxWidth = cellWidth + (isRTL ? cellRect.left - eventX : eventX - cellRect.right); } - - column.width = `${Math.max(minWidth, maxWidth)}px`; - column.flexGrow = 0; + const calculatedWidth = Math.max(minWidth, maxWidth); + if (column.minWidth) { + column.width = `max(${column.minWidth}, ${calculatedWidth}px)`; + } else { + column.width = `${calculatedWidth}px`; + } } // Fix width and flex-grow for all preceding columns columnRowCells diff --git a/packages/grid/src/vaadin-grid-mixin.js b/packages/grid/src/vaadin-grid-mixin.js index 1535a1fe39..380e4210e1 100644 --- a/packages/grid/src/vaadin-grid-mixin.js +++ b/packages/grid/src/vaadin-grid-mixin.js @@ -409,7 +409,12 @@ export const GridMixin = (superClass) => this.__calculateAndCacheIntrinsicWidths(cols); cols.forEach((col) => { - col.width = `${this.__getDistributedWidth(col)}px`; + const calculatedWidth = this.__getDistributedWidth(col); + if (col.minWidth) { + col.width = `max(${col.minWidth}, ${calculatedWidth}px)`; + } else { + col.width = `${calculatedWidth}px`; + } }); } @@ -507,6 +512,17 @@ export const GridMixin = (superClass) => } else { this._recalculateColumnWidths(cols); } + // update the columns without autowidth and set the min width + const noAutoWidthCols = this._getColumns().filter((col) => !col.hidden && !col.autoWidth); + + noAutoWidthCols.forEach((col) => { + const calculatedWidth = col.width; + if (col.minWidth) { + col.width = `max(${col.minWidth}, ${calculatedWidth})`; + } else { + col.width = `${calculatedWidth}`; + } + }); } /** @private */ diff --git a/packages/grid/test/column-auto-width-min-width-lit.test.js b/packages/grid/test/column-auto-width-min-width-lit.test.js new file mode 100644 index 0000000000..9a60f1d489 --- /dev/null +++ b/packages/grid/test/column-auto-width-min-width-lit.test.js @@ -0,0 +1,3 @@ +import '../theme/lumo/lit-all-imports.js'; +import '../src/lit-all-imports.js'; +import './column-auto-width-min-width.common.js'; diff --git a/packages/grid/test/column-auto-width-min-width-polymer.test.js b/packages/grid/test/column-auto-width-min-width-polymer.test.js new file mode 100644 index 0000000000..4985d3d092 --- /dev/null +++ b/packages/grid/test/column-auto-width-min-width-polymer.test.js @@ -0,0 +1,2 @@ +import '../all-imports.js'; +import './column-auto-width-min-width.common.js'; diff --git a/packages/grid/test/column-auto-width-min-width.common.js b/packages/grid/test/column-auto-width-min-width.common.js new file mode 100644 index 0000000000..4f49d8109a --- /dev/null +++ b/packages/grid/test/column-auto-width-min-width.common.js @@ -0,0 +1,105 @@ +import { expect } from '@esm-bundle/chai'; +import { aTimeout, fixtureSync, nextFrame, oneEvent } from '@vaadin/testing-helpers'; +import sinon from 'sinon'; +import { flushGrid, getContainerCell } from './helpers.js'; + +function isNumeric(str) { + if (typeof str !== 'string') return false; // we only process strings! + return !isNaN(str) && !isNaN(parseFloat(str)); +} +function expectColumnWidthsToBeOk(columns, expectedWidths = ['max(50px, 71px)', '114', '84', '107'], delta = 5) { + // Allowed margin of measurement to keep the test from failing if there are small differences in rendered text + // width on different platforms or if there are small changes to styles which affect horizontal margin/padding. + + expectedWidths.forEach((expectedWidth, index) => { + const colWidth = columns[index].width.replace('px', ''); + if (isNumeric(colWidth) && isNumeric(expectedWidth)) { + const columnWidth = parseInt(colWidth); + expect(columnWidth).to.be.closeTo(Number(expectedWidth), delta); + } else { + const columnWidth = columns[index].width; + expect(columnWidth).to.be.equal(expectedWidth); + } + }); +} + +describe('column auto-width', () => { + let grid; + let columns; + let spy; + + const testItems = [ + { a: 'fubar', b: 'foo', c: 'foo', d: 'a' }, + { a: 'foo', b: 'foo bar baz', c: 'foo', d: 'bar' }, + { a: 'foo', b: 'foo baz', c: 'foo bar', d: 'baz' }, + ]; + + function whenColumnWidthsCalculated(cb) { + if (grid._recalculateColumnWidths.called) { + cb(); + } else { + requestAnimationFrame(() => whenColumnWidthsCalculated(cb)); + } + } + + function recalculateWidths() { + return new Promise((resolve) => { + whenColumnWidthsCalculated(() => { + resolve(); + }); + }); + } + + class TestContainer extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + this.shadowRoot.innerHTML = ` + + `; + } + } + + customElements.define('test-container', TestContainer); + + it('should have correct column widths when items are set', async () => { + grid = fixtureSync(` + + `); + spy = sinon.spy(grid, '_recalculateColumnWidths'); + columns = grid.querySelectorAll('vaadin-grid-column'); + // Show the grid and wait for animationend event ("vaadin-grid-appear") + // to ensure the grid is in a consistent state before starting each test + grid.hidden = false; + await oneEvent(grid, 'animationend'); + grid.items = testItems; + + await recalculateWidths(); + expectColumnWidthsToBeOk(columns); + }); + + it('should have correct column widths when items are set', async () => { + grid = fixtureSync(` + + `); + spy = sinon.spy(grid, '_recalculateColumnWidths'); + columns = grid.querySelectorAll('vaadin-grid-column'); + // Show the grid and wait for animationend event ("vaadin-grid-appear") + // to ensure the grid is in a consistent state before starting each test + grid.hidden = false; + await oneEvent(grid, 'animationend'); + grid.items = testItems; + await recalculateWidths(); + expectColumnWidthsToBeOk(columns, ['max(150px, 151px)']); + }); +}); From c5d1b7e43c62052043a40e28e3f6dcc9330dbee3 Mon Sep 17 00:00:00 2001 From: jcgueriaud1 Date: Wed, 17 Jul 2024 09:46:37 +0300 Subject: [PATCH 2/7] Add min-width on the columns --- packages/grid/src/vaadin-grid-column-resizing-mixin.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grid/src/vaadin-grid-column-resizing-mixin.js b/packages/grid/src/vaadin-grid-column-resizing-mixin.js index d911abaa05..fe1cdeeb33 100644 --- a/packages/grid/src/vaadin-grid-column-resizing-mixin.js +++ b/packages/grid/src/vaadin-grid-column-resizing-mixin.js @@ -83,6 +83,7 @@ export const ColumnResizingMixin = (superClass) => } else { column.width = `${calculatedWidth}px`; } + column.flexGrow = 0; } // Fix width and flex-grow for all preceding columns columnRowCells From 381a67eed8cb859cdeb555d9525613ccefb8cc5c Mon Sep 17 00:00:00 2001 From: jcgueriaud1 Date: Thu, 8 Aug 2024 11:39:18 +0300 Subject: [PATCH 3/7] Add a test for the definition and update the test to use a Regexp --- .../grid/src/vaadin-grid-column-mixin.d.ts | 9 ++++ ...> column-auto-width-min-width-lit.test.ts} | 2 +- ...olumn-auto-width-min-width-polymer.test.js | 2 - ...olumn-auto-width-min-width-polymer.test.ts | 2 + ... => column-auto-width-min-width.common.ts} | 43 +++++++++++-------- packages/grid/test/typings/grid.types.ts | 1 + 6 files changed, 39 insertions(+), 20 deletions(-) rename packages/grid/test/{column-auto-width-min-width-lit.test.js => column-auto-width-min-width-lit.test.ts} (61%) delete mode 100644 packages/grid/test/column-auto-width-min-width-polymer.test.js create mode 100644 packages/grid/test/column-auto-width-min-width-polymer.test.ts rename packages/grid/test/{column-auto-width-min-width.common.js => column-auto-width-min-width.common.ts} (73%) diff --git a/packages/grid/src/vaadin-grid-column-mixin.d.ts b/packages/grid/src/vaadin-grid-column-mixin.d.ts index 3b6a70ef1d..3ad77b78b9 100644 --- a/packages/grid/src/vaadin-grid-column-mixin.d.ts +++ b/packages/grid/src/vaadin-grid-column-mixin.d.ts @@ -126,6 +126,15 @@ export declare class GridColumnMixinClass< */ width: string | null | undefined; + /** + * Min-width of the cells for this column. + * + * Please note that using the `em` length unit is discouraged as + * it might lead to misalignment issues if the header, body, and footer + * cells have different font sizes. Instead, use `rem` if you need + * a length unit relative to the font size. + */ + minWidth: string | null | undefined; /** * Flex grow ratio for the cell widths. When set to 0, cell width is fixed. * @attr {number} flex-grow diff --git a/packages/grid/test/column-auto-width-min-width-lit.test.js b/packages/grid/test/column-auto-width-min-width-lit.test.ts similarity index 61% rename from packages/grid/test/column-auto-width-min-width-lit.test.js rename to packages/grid/test/column-auto-width-min-width-lit.test.ts index 9a60f1d489..556b6ea58e 100644 --- a/packages/grid/test/column-auto-width-min-width-lit.test.js +++ b/packages/grid/test/column-auto-width-min-width-lit.test.ts @@ -1,3 +1,3 @@ import '../theme/lumo/lit-all-imports.js'; import '../src/lit-all-imports.js'; -import './column-auto-width-min-width.common.js'; +import './column-auto-width-min-width.common'; diff --git a/packages/grid/test/column-auto-width-min-width-polymer.test.js b/packages/grid/test/column-auto-width-min-width-polymer.test.js deleted file mode 100644 index 4985d3d092..0000000000 --- a/packages/grid/test/column-auto-width-min-width-polymer.test.js +++ /dev/null @@ -1,2 +0,0 @@ -import '../all-imports.js'; -import './column-auto-width-min-width.common.js'; diff --git a/packages/grid/test/column-auto-width-min-width-polymer.test.ts b/packages/grid/test/column-auto-width-min-width-polymer.test.ts new file mode 100644 index 0000000000..d54d4c5a4f --- /dev/null +++ b/packages/grid/test/column-auto-width-min-width-polymer.test.ts @@ -0,0 +1,2 @@ +import '../all-imports.js'; +import './column-auto-width-min-width.common'; diff --git a/packages/grid/test/column-auto-width-min-width.common.js b/packages/grid/test/column-auto-width-min-width.common.ts similarity index 73% rename from packages/grid/test/column-auto-width-min-width.common.js rename to packages/grid/test/column-auto-width-min-width.common.ts index 4f49d8109a..78be4382f1 100644 --- a/packages/grid/test/column-auto-width-min-width.common.js +++ b/packages/grid/test/column-auto-width-min-width.common.ts @@ -1,30 +1,39 @@ import { expect } from '@esm-bundle/chai'; import { aTimeout, fixtureSync, nextFrame, oneEvent } from '@vaadin/testing-helpers'; import sinon from 'sinon'; -import { flushGrid, getContainerCell } from './helpers.js'; +import type { Grid } from '../src/vaadin-grid.js'; -function isNumeric(str) { - if (typeof str !== 'string') return false; // we only process strings! - return !isNaN(str) && !isNaN(parseFloat(str)); +interface ExpectedWidths { + pattern: RegExp; + values: number[]; } -function expectColumnWidthsToBeOk(columns, expectedWidths = ['max(50px, 71px)', '114', '84', '107'], delta = 5) { +function expectColumnWidthsToBeOk( + columns: any, + expectedWidths: ExpectedWidths[] = [ + { pattern: /max\(([0-9]+)px, ([0-9]+)px\)/u, values: [50, 71] }, + { pattern: /([0-9]+)[px]?/u, values: [114] }, + { pattern: /([0-9]+)[px]?/u, values: [84] }, + { pattern: /([0-9]+)[px]?/u, values: [107] }, + ], + delta = 5, +) { // Allowed margin of measurement to keep the test from failing if there are small differences in rendered text // width on different platforms or if there are small changes to styles which affect horizontal margin/padding. expectedWidths.forEach((expectedWidth, index) => { - const colWidth = columns[index].width.replace('px', ''); - if (isNumeric(colWidth) && isNumeric(expectedWidth)) { - const columnWidth = parseInt(colWidth); - expect(columnWidth).to.be.closeTo(Number(expectedWidth), delta); - } else { - const columnWidth = columns[index].width; - expect(columnWidth).to.be.equal(expectedWidth); + const colWidth: string = columns[index].width; + const split = colWidth.split(expectedWidth.pattern); + for (let indexValue = 0; indexValue < expectedWidth.values.length; indexValue++) { + const widthValue: string = split[indexValue + 1]; + const expectedWidthValue = expectedWidth.values[indexValue]; + const columnWidth = parseInt(widthValue); + expect(columnWidth).to.be.closeTo(expectedWidthValue, delta); } }); } describe('column auto-width', () => { - let grid; + let grid: Grid; let columns; let spy; @@ -34,8 +43,8 @@ describe('column auto-width', () => { { a: 'foo', b: 'foo baz', c: 'foo bar', d: 'baz' }, ]; - function whenColumnWidthsCalculated(cb) { - if (grid._recalculateColumnWidths.called) { + function whenColumnWidthsCalculated(cb: any) { + if ((grid as any)._recalculateColumnWidths.called) { cb(); } else { requestAnimationFrame(() => whenColumnWidthsCalculated(cb)); @@ -54,7 +63,7 @@ describe('column auto-width', () => { constructor() { super(); this.attachShadow({ mode: 'open' }); - this.shadowRoot.innerHTML = ` + this.shadowRoot!.innerHTML = ` `; } @@ -100,6 +109,6 @@ describe('column auto-width', () => { await oneEvent(grid, 'animationend'); grid.items = testItems; await recalculateWidths(); - expectColumnWidthsToBeOk(columns, ['max(150px, 151px)']); + expectColumnWidthsToBeOk(columns, [{ pattern: /max\(([0-9]+)px, ([0-9]+)px\)/u, values: [150, 151] }]); }); }); diff --git a/packages/grid/test/typings/grid.types.ts b/packages/grid/test/typings/grid.types.ts index 754b238b40..ea5f140941 100644 --- a/packages/grid/test/typings/grid.types.ts +++ b/packages/grid/test/typings/grid.types.ts @@ -239,6 +239,7 @@ assertType>(narrowedColumn); assertType(narrowedColumn.flexGrow); assertType(narrowedColumn.width); +assertType(narrowedColumn.minWidth); assertType(narrowedColumn.resizable); assertType(narrowedColumn.frozen); assertType(narrowedColumn.frozenToEnd); From fe14b5989f6a48f54c79c48c685fe8240bf689c8 Mon Sep 17 00:00:00 2001 From: jcgueriaud1 Date: Thu, 8 Aug 2024 11:48:56 +0300 Subject: [PATCH 4/7] Fix the linter --- packages/grid/test/column-auto-width-min-width.common.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grid/test/column-auto-width-min-width.common.ts b/packages/grid/test/column-auto-width-min-width.common.ts index 78be4382f1..0b867ef318 100644 --- a/packages/grid/test/column-auto-width-min-width.common.ts +++ b/packages/grid/test/column-auto-width-min-width.common.ts @@ -1,5 +1,5 @@ import { expect } from '@esm-bundle/chai'; -import { aTimeout, fixtureSync, nextFrame, oneEvent } from '@vaadin/testing-helpers'; +import { fixtureSync, oneEvent } from '@vaadin/testing-helpers'; import sinon from 'sinon'; import type { Grid } from '../src/vaadin-grid.js'; @@ -81,6 +81,7 @@ describe('column auto-width', () => { `); spy = sinon.spy(grid, '_recalculateColumnWidths'); + spy.resetHistory(); columns = grid.querySelectorAll('vaadin-grid-column'); // Show the grid and wait for animationend event ("vaadin-grid-appear") // to ensure the grid is in a consistent state before starting each test From 5fb99f840ec7e3e1eadfeb7f9c3abc8272023de1 Mon Sep 17 00:00:00 2001 From: jcgueriaud1 Date: Thu, 8 Aug 2024 15:27:14 +0300 Subject: [PATCH 5/7] Add more tests for the min-width --- ...olumn-auto-width-min-width-polymer.test.ts | 2 - .../column-auto-width-min-width.common.ts | 115 ------ ...t.test.ts => column-min-width-lit.test.ts} | 2 +- .../test/column-min-width-polymer.test.ts | 2 + packages/grid/test/column-min-width.common.ts | 326 ++++++++++++++++++ 5 files changed, 329 insertions(+), 118 deletions(-) delete mode 100644 packages/grid/test/column-auto-width-min-width-polymer.test.ts delete mode 100644 packages/grid/test/column-auto-width-min-width.common.ts rename packages/grid/test/{column-auto-width-min-width-lit.test.ts => column-min-width-lit.test.ts} (62%) create mode 100644 packages/grid/test/column-min-width-polymer.test.ts create mode 100644 packages/grid/test/column-min-width.common.ts diff --git a/packages/grid/test/column-auto-width-min-width-polymer.test.ts b/packages/grid/test/column-auto-width-min-width-polymer.test.ts deleted file mode 100644 index d54d4c5a4f..0000000000 --- a/packages/grid/test/column-auto-width-min-width-polymer.test.ts +++ /dev/null @@ -1,2 +0,0 @@ -import '../all-imports.js'; -import './column-auto-width-min-width.common'; diff --git a/packages/grid/test/column-auto-width-min-width.common.ts b/packages/grid/test/column-auto-width-min-width.common.ts deleted file mode 100644 index 0b867ef318..0000000000 --- a/packages/grid/test/column-auto-width-min-width.common.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { expect } from '@esm-bundle/chai'; -import { fixtureSync, oneEvent } from '@vaadin/testing-helpers'; -import sinon from 'sinon'; -import type { Grid } from '../src/vaadin-grid.js'; - -interface ExpectedWidths { - pattern: RegExp; - values: number[]; -} -function expectColumnWidthsToBeOk( - columns: any, - expectedWidths: ExpectedWidths[] = [ - { pattern: /max\(([0-9]+)px, ([0-9]+)px\)/u, values: [50, 71] }, - { pattern: /([0-9]+)[px]?/u, values: [114] }, - { pattern: /([0-9]+)[px]?/u, values: [84] }, - { pattern: /([0-9]+)[px]?/u, values: [107] }, - ], - delta = 5, -) { - // Allowed margin of measurement to keep the test from failing if there are small differences in rendered text - // width on different platforms or if there are small changes to styles which affect horizontal margin/padding. - - expectedWidths.forEach((expectedWidth, index) => { - const colWidth: string = columns[index].width; - const split = colWidth.split(expectedWidth.pattern); - for (let indexValue = 0; indexValue < expectedWidth.values.length; indexValue++) { - const widthValue: string = split[indexValue + 1]; - const expectedWidthValue = expectedWidth.values[indexValue]; - const columnWidth = parseInt(widthValue); - expect(columnWidth).to.be.closeTo(expectedWidthValue, delta); - } - }); -} - -describe('column auto-width', () => { - let grid: Grid; - let columns; - let spy; - - const testItems = [ - { a: 'fubar', b: 'foo', c: 'foo', d: 'a' }, - { a: 'foo', b: 'foo bar baz', c: 'foo', d: 'bar' }, - { a: 'foo', b: 'foo baz', c: 'foo bar', d: 'baz' }, - ]; - - function whenColumnWidthsCalculated(cb: any) { - if ((grid as any)._recalculateColumnWidths.called) { - cb(); - } else { - requestAnimationFrame(() => whenColumnWidthsCalculated(cb)); - } - } - - function recalculateWidths() { - return new Promise((resolve) => { - whenColumnWidthsCalculated(() => { - resolve(); - }); - }); - } - - class TestContainer extends HTMLElement { - constructor() { - super(); - this.attachShadow({ mode: 'open' }); - this.shadowRoot!.innerHTML = ` - - `; - } - } - - customElements.define('test-container', TestContainer); - - it('should have correct column widths when items are set', async () => { - grid = fixtureSync(` - - `); - spy = sinon.spy(grid, '_recalculateColumnWidths'); - spy.resetHistory(); - columns = grid.querySelectorAll('vaadin-grid-column'); - // Show the grid and wait for animationend event ("vaadin-grid-appear") - // to ensure the grid is in a consistent state before starting each test - grid.hidden = false; - await oneEvent(grid, 'animationend'); - grid.items = testItems; - - await recalculateWidths(); - expectColumnWidthsToBeOk(columns); - }); - - it('should have correct column widths when items are set', async () => { - grid = fixtureSync(` - - `); - spy = sinon.spy(grid, '_recalculateColumnWidths'); - columns = grid.querySelectorAll('vaadin-grid-column'); - // Show the grid and wait for animationend event ("vaadin-grid-appear") - // to ensure the grid is in a consistent state before starting each test - grid.hidden = false; - await oneEvent(grid, 'animationend'); - grid.items = testItems; - await recalculateWidths(); - expectColumnWidthsToBeOk(columns, [{ pattern: /max\(([0-9]+)px, ([0-9]+)px\)/u, values: [150, 151] }]); - }); -}); diff --git a/packages/grid/test/column-auto-width-min-width-lit.test.ts b/packages/grid/test/column-min-width-lit.test.ts similarity index 62% rename from packages/grid/test/column-auto-width-min-width-lit.test.ts rename to packages/grid/test/column-min-width-lit.test.ts index 556b6ea58e..eaf800c03d 100644 --- a/packages/grid/test/column-auto-width-min-width-lit.test.ts +++ b/packages/grid/test/column-min-width-lit.test.ts @@ -1,3 +1,3 @@ import '../theme/lumo/lit-all-imports.js'; import '../src/lit-all-imports.js'; -import './column-auto-width-min-width.common'; +import './column-min-width.common.js'; diff --git a/packages/grid/test/column-min-width-polymer.test.ts b/packages/grid/test/column-min-width-polymer.test.ts new file mode 100644 index 0000000000..c3e261f063 --- /dev/null +++ b/packages/grid/test/column-min-width-polymer.test.ts @@ -0,0 +1,2 @@ +import '../all-imports.js'; +import './column-min-width.common.js'; diff --git a/packages/grid/test/column-min-width.common.ts b/packages/grid/test/column-min-width.common.ts new file mode 100644 index 0000000000..e166d39119 --- /dev/null +++ b/packages/grid/test/column-min-width.common.ts @@ -0,0 +1,326 @@ +import { expect } from '@esm-bundle/chai'; +import { fixtureSync, nextRender, oneEvent } from '@vaadin/testing-helpers'; +import sinon from 'sinon'; +import type { Grid } from '../src/vaadin-grid.js'; +import type { GridColumn } from '../src/vaadin-grid-column.js'; +import type { GridColumnGroup } from '../src/vaadin-grid-column-group.js'; +import { fire, flushGrid, getRowCells, getRows, infiniteDataProvider } from './helpers.js'; + +interface ExpectedWidths { + pattern: RegExp; + values: number[]; +} +function expectColumnWidthsToBeOk( + columns: NodeListOf | GridColumnGroup>, + expectedWidths: ExpectedWidths[] = [ + { pattern: /max\(([0-9]+)px, ([0-9]+)px\)/u, values: [50, 71] }, + { pattern: /([0-9]+)[px]?/u, values: [114] }, + { pattern: /([0-9]+)[px]?/u, values: [84] }, + { pattern: /([0-9]+)[px]?/u, values: [107] }, + ], + delta = 5, +) { + // Allowed margin of measurement to keep the test from failing if there are small differences in rendered text + // width on different platforms or if there are small changes to styles which affect horizontal margin/padding. + expectedWidths.forEach((expectedWidth, index) => { + const colWidth = columns[index].width; + expect(colWidth).to.be.not.undefined; + expect(colWidth).to.be.not.null; + const split = colWidth!.split(expectedWidth.pattern); + for (let indexValue = 0; indexValue < expectedWidth.values.length; indexValue++) { + const widthValue: string = split[indexValue + 1]; + const expectedWidthValue = expectedWidth.values[indexValue]; + const columnWidth = parseInt(widthValue); + expect(columnWidth).to.be.closeTo(expectedWidthValue, delta); + } + }); +} + +describe('column auto-width', () => { + let grid: Grid; + let columns: NodeListOf>; + let spy; + + const testItems = [ + { a: 'fubar', b: 'foo', c: 'foo', d: 'a' }, + { a: 'foo', b: 'foo bar baz', c: 'foo', d: 'bar' }, + { a: 'foo', b: 'foo baz', c: 'foo bar', d: 'baz' }, + ]; + + function whenColumnWidthsCalculated(cb: any) { + if ((grid as any)._recalculateColumnWidths.called) { + cb(); + } else { + requestAnimationFrame(() => whenColumnWidthsCalculated(cb)); + } + } + + function recalculateWidths() { + return new Promise((resolve) => { + whenColumnWidthsCalculated(() => { + resolve(); + }); + }); + } + + class TestContainer extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + this.shadowRoot!.innerHTML = ` + + `; + } + } + + customElements.define('test-container', TestContainer); + + it('should have correct column widths when items are set', async () => { + grid = fixtureSync(` + + `); + spy = sinon.spy(grid, '_recalculateColumnWidths'); + spy.resetHistory(); + columns = grid.querySelectorAll('vaadin-grid-column'); + // Show the grid and wait for animationend event ("vaadin-grid-appear") + // to ensure the grid is in a consistent state before starting each test + grid.hidden = false; + await oneEvent(grid, 'animationend'); + grid.items = testItems; + + await recalculateWidths(); + expectColumnWidthsToBeOk(columns); + }); + + it('should have correct column widths when items are set', async () => { + grid = fixtureSync(` + + `); + spy = sinon.spy(grid, '_recalculateColumnWidths'); + columns = grid.querySelectorAll('vaadin-grid-column'); + // Show the grid and wait for animationend event ("vaadin-grid-appear") + // to ensure the grid is in a consistent state before starting each test + grid.hidden = false; + await oneEvent(grid, 'animationend'); + grid.items = testItems; + await recalculateWidths(); + expectColumnWidthsToBeOk(columns, [{ pattern: /max\(([0-9]+)px, ([0-9]+)px\)/u, values: [150, 151] }]); + }); +}); + +describe('column group', () => { + const num = (str: string) => parseInt(str, 10); + + function createGrid(html: string, items = [{ a: 'm', b: 'mm' }]) { + const grid: Grid = fixtureSync(html); + grid.items = items; + flushGrid(grid); + + return grid; + } + + it('should consider vaadin-grid-column header when calculating column width', () => { + const grid = createGrid(` + + + + + + `); + const columns = grid.querySelectorAll('vaadin-grid-column'); + expectColumnWidthsToBeOk( + columns, + [ + { + pattern: /max\(([0-9]+)px, ([0-9]+)px\)/u, + values: [200, 420], + }, + ], + 25, + ); + const columnGroups = grid.querySelectorAll('vaadin-grid-column-group'); + expectColumnWidthsToBeOk( + columnGroups, + [ + { + pattern: /calc\(max\(([0-9]+)px, ([0-9]+)px\)\)/u, + values: [200, 420], + }, + ], + 25, + ); + }); + it('should consider vaadin-grid-column header when calculating column width', () => { + const grid = createGrid(` + + + + + + + `); + const columnGroups = grid.querySelectorAll('vaadin-grid-column-group'); + expectColumnWidthsToBeOk( + columnGroups, + [ + { + pattern: /calc\(max\(([0-9]+)px, ([0-9]+)px\) \+ max\(([0-9]+)px, ([0-9]+)px\)\)/u, + values: [200, 420, 190, 420], + }, + ], + 25, + ); + }); + it('should consider calculate the width of the group based on the min-width', () => { + const grid = createGrid(` + + + + + + + `); + const columnGroups = grid.querySelectorAll('vaadin-grid-column-group'); + expectColumnWidthsToBeOk( + columnGroups, + [ + { + pattern: /calc\(max\(([0-9]+)px, ([0-9]+)px\) \+ max\(([0-9]+)px, ([0-9]+)px\)\)/u, + values: [200, 201, 190, 191], + }, + ], + 25, + ); + }); + it('should consider ignore the hidden columns', () => { + const grid = createGrid(` + + + + + + + + `); + const columnGroups = grid.querySelectorAll('vaadin-grid-column-group'); + expectColumnWidthsToBeOk( + columnGroups, + [ + { + pattern: /calc\(max\(([0-9]+)px, ([0-9]+)px\) \+ max\(([0-9]+)px, ([0-9]+)px\)\)/u, + values: [200, 201, 190, 191], + }, + ], + 25, + ); + }); +}); + +describe('column resizing', () => { + let grid: Grid, headerCells: NodeListOf, handle: Element; + + beforeEach(async () => { + grid = fixtureSync(` + + + + + `); + grid.querySelectorAll('vaadin-grid-column').forEach((col, idx) => { + col.renderer = (root) => { + root.textContent = idx.toString(); + }; + }); + grid.dataProvider = infiniteDataProvider; + flushGrid(grid); + headerCells = getRowCells(getRows((grid as any).$.header)[0]); + handle = headerCells[0].querySelector('[part~="resize-handle"]')!; + await nextRender(grid); + }); + it('should set min width based on the min width value', () => { + const options = { node: handle }; + const rect = headerCells[0].getBoundingClientRect(); + + expect(headerCells[0].clientWidth).to.be.closeTo(149, 5); + + fire('track', { state: 'start' }, options); + fire('track', { state: 'track', x: rect.left + 130, y: 0 }, options); + expect(headerCells[0].clientWidth).to.be.equal(130); + + fire('track', { state: 'start' }, options); + fire('track', { state: 'track', x: rect.left + 100, y: 0 }, options); + expect(headerCells[0].clientWidth).to.be.equal(100); + }); +}); + +describe('column group resizing', () => { + let grid: Grid; + + beforeEach(async () => { + grid = fixtureSync(` + + + + + + + `); + grid.querySelectorAll('vaadin-grid-column').forEach((col, idx) => { + col.renderer = (root) => { + root.textContent = idx.toString(); + }; + }); + grid.dataProvider = infiniteDataProvider; + flushGrid(grid); + await nextRender(grid); + }); + ['rtl', 'ltr'].forEach((direction) => { + describe(`child columns resizing in ${direction}`, () => { + beforeEach(() => { + grid.setAttribute('dir', direction); + }); + + it('should resize the child column', () => { + const headerRows = getRows((grid as any).$.header); + const groupCell = getRowCells(headerRows[0])[0]; + const handle = groupCell.querySelector('[part~="resize-handle"]'); + + const cell = getRowCells(headerRows[1])[1]; + const rect = cell.getBoundingClientRect(); + const options = { node: handle }; + expect(cell.clientWidth).to.equal(100); + fire('track', { state: 'start' }, options); + fire('track', { state: 'track', x: rect.right + (direction === 'rtl' ? -50 : 50), y: 0 }, options); + + expect(cell.clientWidth).to.equal(direction === 'rtl' ? 70 : 150); + expect(groupCell.clientWidth).to.equal(direction === 'rtl' ? 190 : 270); + }); + + it('should resize the last non-hidden child column', () => { + (grid as any)._columnTree[1][1].hidden = true; + const headerRows = getRows((grid as any).$.header); + const groupCell = getRowCells(headerRows[0])[0]; + const handle = groupCell.querySelector('[part~="resize-handle"]'); + + const cell = getRowCells(headerRows[1])[0]; + const rect = cell.getBoundingClientRect(); + const options = { node: handle }; + fire('track', { state: 'start' }, options); + fire('track', { state: 'track', x: rect.right + (direction === 'rtl' ? -100 : 100), y: 0 }, options); + + expect(cell.clientWidth).to.equal(direction === 'rtl' ? 120 : 220); + expect(groupCell.clientWidth).to.equal(direction === 'rtl' ? 120 : 220); + }); + }); + }); +}); From ad254b7d0b57d86e8bbb73f16353d1c908378318 Mon Sep 17 00:00:00 2001 From: jcgueriaud1 Date: Thu, 8 Aug 2024 15:30:36 +0300 Subject: [PATCH 6/7] Add more tests for the min-width --- packages/grid/test/column-min-width.common.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/grid/test/column-min-width.common.ts b/packages/grid/test/column-min-width.common.ts index e166d39119..7c1722e500 100644 --- a/packages/grid/test/column-min-width.common.ts +++ b/packages/grid/test/column-min-width.common.ts @@ -119,8 +119,6 @@ describe('column auto-width', () => { }); describe('column group', () => { - const num = (str: string) => parseInt(str, 10); - function createGrid(html: string, items = [{ a: 'm', b: 'mm' }]) { const grid: Grid = fixtureSync(html); grid.items = items; From 1fa5ab3550abb29c9544fe7d4a13f88411d7ce4e Mon Sep 17 00:00:00 2001 From: jcgueriaud1 Date: Thu, 8 Aug 2024 15:34:00 +0300 Subject: [PATCH 7/7] Fix sonarcloud issue --- packages/grid/test/column-min-width.common.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/grid/test/column-min-width.common.ts b/packages/grid/test/column-min-width.common.ts index 7c1722e500..0aa604d922 100644 --- a/packages/grid/test/column-min-width.common.ts +++ b/packages/grid/test/column-min-width.common.ts @@ -13,10 +13,10 @@ interface ExpectedWidths { function expectColumnWidthsToBeOk( columns: NodeListOf | GridColumnGroup>, expectedWidths: ExpectedWidths[] = [ - { pattern: /max\(([0-9]+)px, ([0-9]+)px\)/u, values: [50, 71] }, - { pattern: /([0-9]+)[px]?/u, values: [114] }, - { pattern: /([0-9]+)[px]?/u, values: [84] }, - { pattern: /([0-9]+)[px]?/u, values: [107] }, + { pattern: /max\((\d+)px, (\d+)px\)/u, values: [50, 71] }, + { pattern: /(\d+)[px]?/u, values: [114] }, + { pattern: /(\d+)[px]?/u, values: [84] }, + { pattern: /(\d+)[px]?/u, values: [107] }, ], delta = 5, ) { @@ -114,7 +114,7 @@ describe('column auto-width', () => { await oneEvent(grid, 'animationend'); grid.items = testItems; await recalculateWidths(); - expectColumnWidthsToBeOk(columns, [{ pattern: /max\(([0-9]+)px, ([0-9]+)px\)/u, values: [150, 151] }]); + expectColumnWidthsToBeOk(columns, [{ pattern: /max\((\d+)px, (\d+)px\)/u, values: [150, 151] }]); }); }); @@ -140,7 +140,7 @@ describe('column group', () => { columns, [ { - pattern: /max\(([0-9]+)px, ([0-9]+)px\)/u, + pattern: /max\((\d+)px, (\d+)px\)/u, values: [200, 420], }, ], @@ -151,7 +151,7 @@ describe('column group', () => { columnGroups, [ { - pattern: /calc\(max\(([0-9]+)px, ([0-9]+)px\)\)/u, + pattern: /calc\(max\((\d+)px, (\d+)px\)\)/u, values: [200, 420], }, ], @@ -172,7 +172,7 @@ describe('column group', () => { columnGroups, [ { - pattern: /calc\(max\(([0-9]+)px, ([0-9]+)px\) \+ max\(([0-9]+)px, ([0-9]+)px\)\)/u, + pattern: /calc\(max\((\d+)px, (\d+)px\) \+ max\((\d+)px, (\d+)px\)\)/u, values: [200, 420, 190, 420], }, ], @@ -193,7 +193,7 @@ describe('column group', () => { columnGroups, [ { - pattern: /calc\(max\(([0-9]+)px, ([0-9]+)px\) \+ max\(([0-9]+)px, ([0-9]+)px\)\)/u, + pattern: /calc\(max\((\d+)px, (\d+)px\) \+ max\((\d+)px, (\d+)px\)\)/u, values: [200, 201, 190, 191], }, ], @@ -215,7 +215,7 @@ describe('column group', () => { columnGroups, [ { - pattern: /calc\(max\(([0-9]+)px, ([0-9]+)px\) \+ max\(([0-9]+)px, ([0-9]+)px\)\)/u, + pattern: /calc\(max\((\d+)px, (\d+)px\) \+ max\((\d+)px, (\d+)px\)\)/u, values: [200, 201, 190, 191], }, ],