From 07c4b56fe43029822541b4442a42c757317335bf Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Tue, 4 Nov 2025 17:16:54 +0400 Subject: [PATCH 1/7] refactor: re-implement grid base styles to use CSS borders --- .../src/styles/vaadin-grid-base-styles.js | 202 +++++------------- 1 file changed, 58 insertions(+), 144 deletions(-) diff --git a/packages/grid/src/styles/vaadin-grid-base-styles.js b/packages/grid/src/styles/vaadin-grid-base-styles.js index b117a86793..3a67d37678 100644 --- a/packages/grid/src/styles/vaadin-grid-base-styles.js +++ b/packages/grid/src/styles/vaadin-grid-base-styles.js @@ -17,13 +17,14 @@ export const gridStyles = css` position: relative; box-sizing: border-box; -webkit-tap-highlight-color: transparent; + --vaadin-grid-row-background-color: red; background: var(--vaadin-grid-background, var(--vaadin-background-color)); border: var(--_border-width) solid var(--_border-color); cursor: default; --_border-color: var(--vaadin-grid-border-color, var(--vaadin-border-color-secondary)); --_border-width: 0; - --_row-border-width: var(--vaadin-grid-row-border-width, 1px); - --_column-border-width: var(--vaadin-grid-column-border-width, 0px); + --_row-border-width: var(--vaadin-grid-row-border-width, 4px); + --_column-border-width: var(--vaadin-grid-column-border-width, 4px); border-radius: var(--_border-radius); --_border-radius: 0; } @@ -95,15 +96,16 @@ export const gridStyles = css` position: sticky; left: 0; width: 100%; + z-index: 2; } - :host([overflow~='top']) #header, + /* :host([overflow~='top']) #header, :host([overflow~='bottom']) #footer, :host([navigating]) #header:has(tr:last-child:focus-within), :host([navigating]) #footer:has(tr:first-child:focus-within), [empty-state] #header { z-index: 2; - } + } */ :host([dir='rtl']) #items, :host([dir='rtl']) #header, @@ -154,32 +156,23 @@ export const gridStyles = css` height: 100%; } + [part~='row'] { + background: var(--vaadin-grid-row-background-color, var(--vaadin-background-color)); + } + [part~='cell'] { + --_cell-background-color: var(--vaadin-grid-cell-background-color, transparent); + --_cell-background-image: linear-gradient(var(--_cell-background-color), var(--_cell-background-color)); + padding: 0; box-sizing: border-box; - background: var(--vaadin-grid-cell-background, var(--vaadin-background-color)); - border-block: var(--_row-border-width) solid var(--_border-color); - margin-top: calc(var(--_row-border-width) * -1); - - /* - Box-shadows are used to create a "fake" border at the end of the cell/row, which is visible when a row/cell ends - before the edge of the grid viewport, as well as frozen columns and rows (header and footer). - If there are frozen columns, we'll make the "fake box-shadow border" on the header and footer opaque by rendering - both the border color and cell background color, so that a semi-transparent border color doesn't "stack" when - scrolling horizontally. - */ - --_fake-border: - 0 calc(var(--_top, 0) * var(--_row-border-width) * -1) 0 0 var(--_border-color), - 0 calc(var(--_top-opaque, 0) * var(--_row-border-width) * -1) 0 0 - var(--vaadin-grid-cell-background-color, var(--vaadin-background-color)), - 0 calc(var(--_bottom, 0) * var(--_row-border-width)) 0 0 var(--_border-color), - 0 calc(var(--_bottom-opaque, 0) * var(--_row-border-width)) 0 0 - var(--vaadin-grid-cell-background-color, var(--vaadin-background-color)), - calc(var(--_start, 0) * var(--_column-border-width) * -1) 0 0 0 var(--_border-color), - calc(var(--_end, 0) * var(--_column-border-width)) 0 0 0 var(--_border-color), - calc(var(--_end-opaque, 0) * var(--_column-border-width)) 0 0 0 - var(--vaadin-grid-cell-background-color, var(--vaadin-background-color)); - box-shadow: var(--_fake-border); + background-color: inherit; + background-repeat: no-repeat; + background-origin: padding-box; + background-image: + var(--_hover-background-image, none), var(--_selected-background-image, none), + var(--_highlight-background-image, none), var(--_cell-background-image); + border: var(--_row-border-width) var(--_border-color); } [part~='cell']:where(:not([part~='details-cell'])) { @@ -190,87 +183,56 @@ export const gridStyles = css` position: relative; align-items: center; white-space: nowrap; - border-inline-start: var(--_column-border-width) solid var(--_border-color); - } - - [part~='first-column-cell'] { - border-inline-start: 0; - } - - [part~='first-header-row-cell'], - [part~='first-footer-row-cell'], - [part~='first-row-cell'] { - margin-top: 0; - border-top: 0; - } - - table[has-header] [part~='first-row-cell'] { - border-top: var(--_row-border-width) solid var(--_border-color); - } - - [part~='last-column-cell'] { - --_end: 1; } - [part~='last-column-cell']:is([part~='header-cell'], [part~='footer-cell']) { - --_end-opaque: 1; - } - - [part~='last-row-cell']:where(:not([part~='details-opened-row-cell'])), - [part~='last-footer-row-cell'] { - border-bottom: 0; - --_bottom: 1; - } - - [part~='last-frozen-cell'] { - --_end: 1; - } - - [part~='last-frozen-cell'] + [part~='cell'] { - border-inline-start-color: transparent; + [part~='body-cell'] { + --_highlight-background-color: var(--vaadin-grid-row-highlight-background-color, transparent); + --_highlight-background-image: linear-gradient( + var(--_highlight-background-color), + var(--_highlight-background-color) + ); } - [part~='first-frozen-to-end-cell'] { - border-inline-start: 0; - --_start: 1; + #table[has-header] { + [part~='first-row-cell'] { + border-block-start-style: solid; + } } - [part~='last-header-row-cell'] { - border-bottom: 0; - } + #table[has-footer] { + [part~='last-row-cell'] { + border-block-end-style: solid; + } - :host([overflow~='top']) [part~='last-header-row-cell'], - [empty-state] [part~='last-header-row-cell'] { - --_bottom: 1; + [part~='last-row-cell'] + [part~='details-cell'] { + border-block-end-style: solid; + } } - #header:has(:is([frozen], [frozen-to-end])) [part~='last-header-row-cell'] { - --_bottom-opaque: 1; + [part~='header-cell']:not([part~='first-header-row-cell']), + [part~='footer-cell']:not([part~='first-footer-row-cell']), + [part~='body-cell']:not([part~='first-row-cell']) { + border-block-start-style: solid; } - :host([overflow~='bottom']) [part~='first-footer-row-cell'], - [empty-state] [part~='first-footer-row-cell'] { - --_top: 1; + [part~='details-opened-row-cell'] { + border-block-end-style: solid; } - #footer:has(:is([frozen], [frozen-to-end])) [part~='first-footer-row-cell'] { - --_top-opaque: 1; + [part~='header-cell']:not([part~='first-column-cell']), + [part~='footer-cell']:not([part~='first-column-cell']), + [part~='body-cell']:not([part~='first-column-cell']) { + border-inline-start-style: solid; } - table[has-footer] [part~='last-row-cell']:not([part~='details-opened-row-cell']) { - border-bottom: var(--_row-border-width) solid var(--_border-color); - --_bottom: 0; - } + [part~='last-frozen-cell'] { + &:not([part~='last-column-cell']) { + border-inline-end-style: solid; + } - [part~='body-cell']:where(:not([part~='details-cell'])) { - --_highlight-background-color: var(--vaadin-grid-row-highlight-background-color, transparent); - --_highlight-background-image: linear-gradient( - var(--_highlight-background-color), - var(--_highlight-background-color) - ); - background: - var(--_hover-background-image, none), var(--_selected-background-image, none), var(--_highlight-background-image), - var(--vaadin-grid-cell-background-color, var(--vaadin-background-color)); + &:not([part~='last-column-cell']) + [part~='cell'] { + border-inline-start-style: none; + } } /* Variant: wrap cell contents */ @@ -280,10 +242,6 @@ export const gridStyles = css` } /* Variant: row stripes */ - [part~='odd-row'] { - --vaadin-grid-cell-background-color: var(--vaadin-grid-row-odd-background-color, var(--vaadin-background-color)); - } - :host([theme~='row-stripes']) [part~='odd-row'] { --vaadin-grid-cell-background-color: var( --vaadin-grid-row-odd-background-color, @@ -291,29 +249,9 @@ export const gridStyles = css` ); } - /* Raise highlighted rows above others */ - - [part~='row']:focus, - [part~='row']:focus-within, - [part~='body-row']:where([selected]) { - z-index: 3; - } - - @container style(--vaadin-grid-row-odd-background-color) { - [part~='odd-row'] { - z-index: 1; - } - } - /* Row hover */ @media (any-hover: hover) { - @container style(--vaadin-grid-row-hover-background-color) { - [part~='body-row']:hover { - z-index: 2; - } - } - - [part~='body-row']:hover [part~='cell']:where(:not([part~='details-cell'])) { + [part~='body-row']:hover [part~='body-cell'] { --_hover-background-color: var(--vaadin-grid-row-hover-background-color, transparent); --_hover-background-image: linear-gradient(var(--_hover-background-color), var(--_hover-background-color)); } @@ -323,12 +261,6 @@ export const gridStyles = css` position: absolute; bottom: 0; width: 100%; - margin-top: 0; - border-top: 0; - } - - [part~='last-row-cell'] + [part~='details-cell'] { - border-bottom: 0; } [part~='cell'] ::slotted(vaadin-grid-cell-content) { @@ -348,7 +280,7 @@ export const gridStyles = css` } /* Selected row */ - [part~='body-row'][selected] { + [part~='selected-row-cell'] { --_selected-background-color: var( --vaadin-grid-row-selected-background-color, color-mix(in srgb, currentColor 8%, transparent) @@ -523,28 +455,10 @@ export const gridStyles = css` inset-inline-end: 0; } - #header [part~='row']:first-child::after, - [part~='first-header-row-cell']::after, - [part*='first-row']::after { - top: 0; - } - table[has-header] [part~='first-row-cell']::after { top: calc(var(--_row-border-width) * -1); } - #footer [part~='row']:last-child::after, - [part~='last-footer-row-cell']::after, - [part~='last-row']::after, - [part~='last-row-cell']::after { - bottom: 0; - } - - #header [part~='row']:last-child::after, - table[has-footer] [part*='last-row']::after { - bottom: calc(var(--_row-border-width) * -1); - } - :host([navigating]) [part~='row']:focus, :host([navigating]) [part~='cell']:focus { outline: 0; @@ -661,7 +575,7 @@ export const gridStyles = css` content: '-'; } - @media (forced-colors: active) { + /* @media (forced-colors: active) { :host([overflow~='top']) [part~='last-header-row-cell'] { border-bottom: var(--_row-border-width) solid; margin-bottom: calc(var(--_row-border-width) * -1); @@ -671,5 +585,5 @@ export const gridStyles = css` border-top: var(--_row-border-width) solid; margin-top: calc(var(--_row-border-width) * -1); } - } + } */ `; From 6ef89770736061f765bac520b2f2e1c312c0fa95 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Wed, 5 Nov 2025 10:52:01 +0400 Subject: [PATCH 2/7] wip --- .../src/styles/vaadin-grid-base-styles.js | 67 +++++++++---------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/packages/grid/src/styles/vaadin-grid-base-styles.js b/packages/grid/src/styles/vaadin-grid-base-styles.js index 3a67d37678..4325436384 100644 --- a/packages/grid/src/styles/vaadin-grid-base-styles.js +++ b/packages/grid/src/styles/vaadin-grid-base-styles.js @@ -17,7 +17,6 @@ export const gridStyles = css` position: relative; box-sizing: border-box; -webkit-tap-highlight-color: transparent; - --vaadin-grid-row-background-color: red; background: var(--vaadin-grid-background, var(--vaadin-background-color)); border: var(--_border-width) solid var(--_border-color); cursor: default; @@ -99,14 +98,6 @@ export const gridStyles = css` z-index: 2; } - /* :host([overflow~='top']) #header, - :host([overflow~='bottom']) #footer, - :host([navigating]) #header:has(tr:last-child:focus-within), - :host([navigating]) #footer:has(tr:first-child:focus-within), - [empty-state] #header { - z-index: 2; - } */ - :host([dir='rtl']) #items, :host([dir='rtl']) #header, :host([dir='rtl']) #footer { @@ -161,17 +152,12 @@ export const gridStyles = css` } [part~='cell'] { - --_cell-background-color: var(--vaadin-grid-cell-background-color, transparent); - --_cell-background-image: linear-gradient(var(--_cell-background-color), var(--_cell-background-color)); - padding: 0; box-sizing: border-box; background-color: inherit; background-repeat: no-repeat; background-origin: padding-box; - background-image: - var(--_hover-background-image, none), var(--_selected-background-image, none), - var(--_highlight-background-image, none), var(--_cell-background-image); + background-image: linear-gradient(var(--vaadin-grid-cell-background-color, transparent)); border: var(--_row-border-width) var(--_border-color); } @@ -186,11 +172,11 @@ export const gridStyles = css` } [part~='body-cell'] { - --_highlight-background-color: var(--vaadin-grid-row-highlight-background-color, transparent); - --_highlight-background-image: linear-gradient( - var(--_highlight-background-color), - var(--_highlight-background-color) - ); + background-image: + linear-gradient(var(--_hover-background-color, transparent)), + linear-gradient(var(--_cell-selected-background-color, transparent)), + linear-gradient(var(--vaadin-grid-row-highlight-background-color, transparent)), + linear-gradient(var(--vaadin-grid-cell-background-color, transparent)); } #table[has-header] { @@ -249,11 +235,16 @@ export const gridStyles = css` ); } + /* Raise highlighted rows above others */ + [part~='row']:focus, + [part~='row']:focus-within { + z-index: 3; + } + /* Row hover */ @media (any-hover: hover) { [part~='body-row']:hover [part~='body-cell'] { --_hover-background-color: var(--vaadin-grid-row-hover-background-color, transparent); - --_hover-background-image: linear-gradient(var(--_hover-background-color), var(--_hover-background-color)); } } @@ -281,11 +272,10 @@ export const gridStyles = css` /* Selected row */ [part~='selected-row-cell'] { - --_selected-background-color: var( + --_cell-selected-background-color: var( --vaadin-grid-row-selected-background-color, color-mix(in srgb, currentColor 8%, transparent) ); - --_selected-background-image: linear-gradient(var(--_selected-background-color), var(--_selected-background-color)); } /* Empty state */ @@ -300,7 +290,6 @@ export const gridStyles = css` inset: 0; flex: 1; overflow: hidden; - margin-top: calc(var(--_row-border-width) * -1); } #emptystaterow { @@ -440,13 +429,16 @@ export const gridStyles = css` /* Focus outline element, also used for d'n'd indication */ :is([part~='row'], [part~='cell'])::after { position: absolute; - inset: calc(var(--_row-border-width) * -1) calc(var(--_column-border-width) * -1); z-index: 3; pointer-events: none; outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color); outline-offset: calc(var(--vaadin-focus-ring-width) * -1); } + [part~='cell']::after { + inset: calc(var(--_row-border-width) * -1) calc(var(--_column-border-width) * -1); + } + [part~='first-column-cell']::after { inset-inline-start: 0; } @@ -455,8 +447,19 @@ export const gridStyles = css` inset-inline-end: 0; } - table[has-header] [part~='first-row-cell']::after { - top: calc(var(--_row-border-width) * -1); + [part~='row']::after { + inset: 0 0 calc(var(--_row-border-width) * -1); + transform: translateX(var(--_grid-horizontal-scroll-position)); + } + + [part~='first-row']::after, + #table:not([has-header]) [part~='first-row-cell']::after { + inset-block-start: 0; + } + + [part~='last-row']::after, + #table:not([has-footer]) [part~='last-row-cell']::after { + inset-block-end: 0; } :host([navigating]) [part~='row']:focus, @@ -464,12 +467,6 @@ export const gridStyles = css` outline: 0; } - [part~='row']::after { - transform: translateX(var(--_grid-horizontal-scroll-position)); - inset-inline: 0; - bottom: 0; - } - [part~='row']:focus-visible, [part~='cell']:focus-visible { outline: 0; @@ -517,8 +514,8 @@ export const gridStyles = css` } [part~='row'][dragstart] [part~='cell'] { - border-block-color: transparent !important; - box-shadow: none; + border-block: none !important; + padding-block: var(--_row-border-width) !important; } [part~='row'][dragstart] [part~='cell'][last-column] { From 4831e98635dd6f38fe5e12abc7c4fb56ee1ac491 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Wed, 5 Nov 2025 11:04:40 +0400 Subject: [PATCH 3/7] wip --- .../grid/src/styles/vaadin-grid-base-styles.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/grid/src/styles/vaadin-grid-base-styles.js b/packages/grid/src/styles/vaadin-grid-base-styles.js index 4325436384..200b7d966a 100644 --- a/packages/grid/src/styles/vaadin-grid-base-styles.js +++ b/packages/grid/src/styles/vaadin-grid-base-styles.js @@ -302,8 +302,16 @@ export const gridStyles = css` flex: 1; overflow: auto; padding: var(--vaadin-grid-cell-padding, var(--vaadin-padding-container)); - border-top: var(--_row-border-width) solid transparent; outline: none; + border-block: var(--_row-border-width) var(--_border-color); + } + + #table[has-header] #emptystatecell { + border-block-start-style: solid; + } + + #table[has-footer] #emptystatecell { + border-block-end-style: solid; } #emptystatecell:focus-visible { @@ -453,12 +461,16 @@ export const gridStyles = css` } [part~='first-row']::after, - #table:not([has-header]) [part~='first-row-cell']::after { + #table:not([has-header]) [part~='first-row-cell']::after, + #header [part~='row']:first-child::after, + #header [part~='row']:first-child [part~='cell']::after { inset-block-start: 0; } [part~='last-row']::after, - #table:not([has-footer]) [part~='last-row-cell']::after { + #table:not([has-footer]) [part~='last-row-cell']::after, + #footer [part~='row']:last-child::after, + #footer [part~='row']:last-child [part~='cell']::after { inset-block-end: 0; } From 5b7aaaf0f6358c43eca99f37b41df489b8703d27 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Wed, 5 Nov 2025 11:42:19 +0400 Subject: [PATCH 4/7] wip --- .../src/styles/vaadin-grid-base-styles.js | 22 +++++++++++++++++++ packages/grid/src/vaadin-grid-scroll-mixin.js | 21 +----------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/packages/grid/src/styles/vaadin-grid-base-styles.js b/packages/grid/src/styles/vaadin-grid-base-styles.js index 200b7d966a..102374b945 100644 --- a/packages/grid/src/styles/vaadin-grid-base-styles.js +++ b/packages/grid/src/styles/vaadin-grid-base-styles.js @@ -161,6 +161,24 @@ export const gridStyles = css` border: var(--_row-border-width) var(--_border-color); } + #header::before, + #footer::before { + position: absolute; + inset: 0; + border-block: var(--_row-border-width) solid var(--_border-color); + transform: translateX(var(--_grid-horizontal-scroll-position)); + } + + :host([overflow~='top']) #table[has-header] #header::before { + content: ''; + inset-block-end: calc(var(--_row-border-width) * -1); + } + + :host([overflow~='bottom']) #table[has-footer] #footer::before { + content: ''; + inset-block-start: calc(var(--_row-border-width) * -1); + } + [part~='cell']:where(:not([part~='details-cell'])) { flex-shrink: 0; flex-grow: 1; @@ -474,6 +492,10 @@ export const gridStyles = css` inset-block-end: 0; } + #footer [part~='row']:first-child::after { + inset-block-start: calc(var(--_row-border-width) * -1); + } + :host([navigating]) [part~='row']:focus, :host([navigating]) [part~='cell']:focus { outline: 0; diff --git a/packages/grid/src/vaadin-grid-scroll-mixin.js b/packages/grid/src/vaadin-grid-scroll-mixin.js index 5ac22f0444..4f90d24236 100644 --- a/packages/grid/src/vaadin-grid-scroll-mixin.js +++ b/packages/grid/src/vaadin-grid-scroll-mixin.js @@ -445,26 +445,7 @@ export const ScrollMixin = (superClass) => } }); - const focusedRow = this.shadowRoot.querySelector("[part~='row']:focus"); - if (focusedRow) { - // Update the horizontal scroll position property of the focused row - this.__updateRowScrollPositionProperty(focusedRow); - } - } - - /** - * Synchronizes the internal `--_grid-horizontal-scroll-position` CSS property - * of the given row with the current horizontal scroll position of the grid. - * @private - */ - __updateRowScrollPositionProperty(row) { - if (row instanceof HTMLTableRowElement === false) { - return; - } - const newValue = `${this.__horizontalScrollPosition}px`; - if (row.style.getPropertyValue('--_grid-horizontal-scroll-position') !== newValue) { - row.style.setProperty('--_grid-horizontal-scroll-position', newValue); - } + this.$.table.style.setProperty('--_grid-horizontal-scroll-position', `${this.__horizontalScrollPosition}px`); } /** @private */ From 528a28a7302b8f87ede4fee59958c7c6d0c94186 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Wed, 5 Nov 2025 14:34:23 +0400 Subject: [PATCH 5/7] wip --- .../src/styles/vaadin-grid-base-styles.js | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/grid/src/styles/vaadin-grid-base-styles.js b/packages/grid/src/styles/vaadin-grid-base-styles.js index 102374b945..8598998dee 100644 --- a/packages/grid/src/styles/vaadin-grid-base-styles.js +++ b/packages/grid/src/styles/vaadin-grid-base-styles.js @@ -174,7 +174,8 @@ export const gridStyles = css` inset-block-end: calc(var(--_row-border-width) * -1); } - :host([overflow~='bottom']) #table[has-footer] #footer::before { + :host([overflow~='bottom']) #table[has-footer] #footer::before, + :host(:not([overflow~='top']):not([overflow~='bottom'])) #table[has-footer] #footer::before { content: ''; inset-block-start: calc(var(--_row-border-width) * -1); } @@ -197,20 +198,14 @@ export const gridStyles = css` linear-gradient(var(--vaadin-grid-cell-background-color, transparent)); } - #table[has-header] { - [part~='first-row-cell'] { - border-block-start-style: solid; - } + #table[has-header] [part~='first-row-cell'] { + border-block-start-style: solid; } - #table[has-footer] { - [part~='last-row-cell'] { - border-block-end-style: solid; - } - - [part~='last-row-cell'] + [part~='details-cell'] { - border-block-end-style: solid; - } + #table[has-footer] [part~='last-row-cell'], + #table[has-footer] [part~='last-row-cell'] + [part~='details-cell'], + :host(:not([overflow~='bottom']):not([overflow~='top'])) [part~='last-row-cell'] { + border-block-end-style: solid; } [part~='header-cell']:not([part~='first-header-row-cell']), @@ -456,13 +451,18 @@ export const gridStyles = css` :is([part~='row'], [part~='cell'])::after { position: absolute; z-index: 3; + inset: 0; pointer-events: none; outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color); outline-offset: calc(var(--vaadin-focus-ring-width) * -1); } [part~='cell']::after { - inset: calc(var(--_row-border-width) * -1) calc(var(--_column-border-width) * -1); + inset-block: calc(var(--_row-border-width) * -1); + } + + [part~='body-cell']::after { + inset-inline: calc(var(--_column-border-width) * -1); } [part~='first-column-cell']::after { @@ -479,16 +479,16 @@ export const gridStyles = css` } [part~='first-row']::after, - #table:not([has-header]) [part~='first-row-cell']::after, #header [part~='row']:first-child::after, - #header [part~='row']:first-child [part~='cell']::after { + #header [part~='row']:first-child [part~='cell']::after, + #table:not([has-header]) [part~='first-row-cell']::after { inset-block-start: 0; } [part~='last-row']::after, - #table:not([has-footer]) [part~='last-row-cell']::after, #footer [part~='row']:last-child::after, - #footer [part~='row']:last-child [part~='cell']::after { + #footer [part~='row']:last-child [part~='cell']::after, + :host([overflow~='top']) #table:not([has-footer]) [part~='last-row-cell']::after { inset-block-end: 0; } From 7c11bae16d5731bcc34c672c943690211184f425 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Wed, 5 Nov 2025 17:26:57 +0400 Subject: [PATCH 6/7] wip --- .../src/styles/vaadin-grid-base-styles.js | 39 ++++++++++++------- packages/grid/src/vaadin-grid-mixin.js | 18 +++++---- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/packages/grid/src/styles/vaadin-grid-base-styles.js b/packages/grid/src/styles/vaadin-grid-base-styles.js index 8598998dee..8515c1dfc2 100644 --- a/packages/grid/src/styles/vaadin-grid-base-styles.js +++ b/packages/grid/src/styles/vaadin-grid-base-styles.js @@ -175,7 +175,7 @@ export const gridStyles = css` } :host([overflow~='bottom']) #table[has-footer] #footer::before, - :host(:not([overflow~='top']):not([overflow~='bottom'])) #table[has-footer] #footer::before { + :host(:not([overflow~='top'])) #table[has-footer] #footer::before { content: ''; inset-block-start: calc(var(--_row-border-width) * -1); } @@ -203,8 +203,9 @@ export const gridStyles = css` } #table[has-footer] [part~='last-row-cell'], - #table[has-footer] [part~='last-row-cell'] + [part~='details-cell'], - :host(:not([overflow~='bottom']):not([overflow~='top'])) [part~='last-row-cell'] { + #table[has-footer] [part~='last-row'] [part~='details-cell'], + :host(:not([overflow~='bottom']):not([overflow~='top'])) [part~='last-row-cell'], + :host(:not([overflow~='bottom']):not([overflow~='top'])) [part~='last-row'] [part~='details-cell'] { border-block-end-style: solid; } @@ -249,9 +250,13 @@ export const gridStyles = css` } /* Raise highlighted rows above others */ - [part~='row']:focus, - [part~='row']:focus-within { - z-index: 3; + [part~='row'], + [part~='frozen-cell'], + [part~='frozen-to-end-cell'] { + &:focus, + &:focus-within { + z-index: 3; + } } /* Row hover */ @@ -461,7 +466,7 @@ export const gridStyles = css` inset-block: calc(var(--_row-border-width) * -1); } - [part~='body-cell']::after { + [part~='cell']:where(:not([part~='details-cell']))::after { inset-inline: calc(var(--_column-border-width) * -1); } @@ -478,22 +483,26 @@ export const gridStyles = css` transform: translateX(var(--_grid-horizontal-scroll-position)); } - [part~='first-row']::after, - #header [part~='row']:first-child::after, - #header [part~='row']:first-child [part~='cell']::after, + [part~='first-header-row-cell']::after, #table:not([has-header]) [part~='first-row-cell']::after { inset-block-start: 0; } + [part~='first-footer-row']::after { + inset-block-start: calc(var(--_row-border-width) * -1); + } + [part~='last-row']::after, - #footer [part~='row']:last-child::after, - #footer [part~='row']:last-child [part~='cell']::after, - :host([overflow~='top']) #table:not([has-footer]) [part~='last-row-cell']::after { + [part~='last-footer-row']::after, + [part~='last-footer-row-cell']::after { inset-block-end: 0; } - #footer [part~='row']:first-child::after { - inset-block-start: calc(var(--_row-border-width) * -1); + :host([overflow~='top']) #table:not([has-footer]) { + [part~='last-row'] [part~='details-cell']::after, + [part~='last-row']:not([part~='details-opened-row']) [part~='last-row-cell']::after { + inset-block-end: 0; + } } :host([navigating]) [part~='row']:focus, diff --git a/packages/grid/src/vaadin-grid-mixin.js b/packages/grid/src/vaadin-grid-mixin.js index 5580b1597e..e986a82dfd 100644 --- a/packages/grid/src/vaadin-grid-mixin.js +++ b/packages/grid/src/vaadin-grid-mixin.js @@ -710,13 +710,13 @@ export const GridMixin = (superClass) => while (this.$.header.children.length < columnTree.length) { const headerRow = document.createElement('tr'); - headerRow.setAttribute('part', 'row'); + headerRow.setAttribute('part', 'row header-row'); headerRow.setAttribute('role', 'row'); headerRow.setAttribute('tabindex', '-1'); this.$.header.appendChild(headerRow); const footerRow = document.createElement('tr'); - footerRow.setAttribute('part', 'row'); + footerRow.setAttribute('part', 'row footer-row'); footerRow.setAttribute('role', 'row'); footerRow.setAttribute('tabindex', '-1'); this.$.footer.appendChild(footerRow); @@ -729,17 +729,19 @@ export const GridMixin = (superClass) => iterateChildren(this.$.header, (headerRow, index, rows) => { this.__initRow(headerRow, columnTree[index], 'header', index === columnTree.length - 1); - const cells = getBodyRowCells(headerRow); - updateCellsPart(cells, 'first-header-row-cell', index === 0); - updateCellsPart(cells, 'last-header-row-cell', index === rows.length - 1); + updateBooleanRowStates(headerRow, { + 'first-header': index === 0, + 'last-header': index === rows.length - 1, + }); }); iterateChildren(this.$.footer, (footerRow, index, rows) => { this.__initRow(footerRow, columnTree[columnTree.length - 1 - index], 'footer', index === 0); - const cells = getBodyRowCells(footerRow); - updateCellsPart(cells, 'first-footer-row-cell', index === 0); - updateCellsPart(cells, 'last-footer-row-cell', index === rows.length - 1); + updateBooleanRowStates(footerRow, { + 'first-footer': index === 0, + 'last-footer': index === rows.length - 1, + }); }); // Sizer rows From 6c196e208bda7fd7f107a6b36bad7583a034ac08 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Wed, 5 Nov 2025 17:34:06 +0400 Subject: [PATCH 7/7] attempt to fix tests --- packages/grid/src/vaadin-grid-drag-and-drop-mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grid/src/vaadin-grid-drag-and-drop-mixin.js b/packages/grid/src/vaadin-grid-drag-and-drop-mixin.js index 119abc762f..e2e94f6c56 100644 --- a/packages/grid/src/vaadin-grid-drag-and-drop-mixin.js +++ b/packages/grid/src/vaadin-grid-drag-and-drop-mixin.js @@ -248,7 +248,7 @@ export const DragAndDropMixin = (superClass) => let row = e.composedPath().find((node) => node.localName === 'tr'); // Update the horizontal scroll position property of the row being dragged over - this.__updateRowScrollPositionProperty(row); + // this.__updateRowScrollPositionProperty(row); if (!this._flatSize || this.dropMode === DropMode.ON_GRID) { // The grid is empty or "on-grid" drop mode was used, always default to "empty"