From 825e2852f2739ed1ccddfc87856b5b73068b08c5 Mon Sep 17 00:00:00 2001 From: Cahit Guerguec Date: Wed, 14 Jan 2026 00:38:27 +0100 Subject: [PATCH] fix(ui5-table): improve horizontal alignment handling - use headerCell id instead of individualSlot - popin cells must always be left aligned Fixes: #11858 Fixes: #12155 Fixes: #12854 --- packages/main/cypress/specs/Table.cy.tsx | 19 +++++------- packages/main/src/Table.ts | 10 +++---- packages/main/src/TableCell.ts | 29 ++++++++++--------- packages/main/src/TableCustomAnnouncement.ts | 2 +- packages/main/src/TableHeaderCell.ts | 8 +---- .../main/src/TableHeaderCellActionBase.ts | 2 +- packages/main/src/themes/TableCellBase.css | 4 +++ packages/main/test/pages/Table.html | 2 +- 8 files changed, 36 insertions(+), 40 deletions(-) diff --git a/packages/main/cypress/specs/Table.cy.tsx b/packages/main/cypress/specs/Table.cy.tsx index 501595e4c64c..62d27762b963 100644 --- a/packages/main/cypress/specs/Table.cy.tsx +++ b/packages/main/cypress/specs/Table.cy.tsx @@ -493,12 +493,7 @@ describe("Table - Popin Mode", () => { describe("Table - Horizontal alignment of cells", () => { function check(id: string, index: number, alignment: string) { cy.get(id) - .should("have.css", "justify-content", alignment) - .and($el => { - const style = $el.attr("style"); - const variable = style?.match(/justify-content: ([^;]+)/)?.[1] ?? ""; - expect(variable).to.equal(`var(--horizontal-align-default-${index})`); - }); + .should("have.css", "justify-content", alignment); cy.get("ui5-table-row") .get(`ui5-table-cell:nth-of-type(${index})`) @@ -530,11 +525,11 @@ describe("Table - Horizontal alignment of cells", () => { - - - - - + + + + + ); @@ -647,8 +642,10 @@ describe("Table - Horizontal alignment of cells", () => { if (shouldBePoppedIn) { check(`#${id}`, index + 1, "normal"); + cy.get(`.${id}`).should("have.css", "justify-content", "normal"); } else { check(`#${id}`, index + 1, alignments[id]); + cy.get(`.${id}`).should("have.css", "justify-content", alignments[id]); } }); }); diff --git a/packages/main/src/Table.ts b/packages/main/src/Table.ts index 7dcbc0671ed5..fc3f237a3184 100644 --- a/packages/main/src/Table.ts +++ b/packages/main/src/Table.ts @@ -609,12 +609,10 @@ class Table extends UI5Element { get styles() { const virtualizer = this._getVirtualizer(); - const headerStyleMap = this.headerRow?.[0]?.cells?.reduce((headerStyles, headerCell) => { - if (headerCell.horizontalAlign !== undefined && !headerCell._popin) { - headerStyles[`--horizontal-align-${headerCell._individualSlot}`] = headerCell.horizontalAlign; - } - return headerStyles; - }, {} as { [key: string]: string }); + const headerStyleMap: Record = {}; + this.headerRow[0]?.cells.forEach(headerCell => { + headerStyleMap[`--halign-${headerCell._id}`] = headerCell.horizontalAlign || "normal"; + }); return { table: { "grid-template-columns": this._gridTemplateColumns, diff --git a/packages/main/src/TableCell.ts b/packages/main/src/TableCell.ts index 1daa5361002a..1d833f4cf0a7 100644 --- a/packages/main/src/TableCell.ts +++ b/packages/main/src/TableCell.ts @@ -40,8 +40,8 @@ class TableCell extends TableCellBase { super.onBeforeRendering(); if (this.horizontalAlign) { this.style.justifyContent = this.horizontalAlign; - } else if (this._individualSlot) { - this.style.justifyContent = `var(--horizontal-align-${this._individualSlot})`; + } else if (this._headerCell) { + this.style.justifyContent = `var(--halign-${this._headerCell._id})`; } } @@ -52,22 +52,25 @@ class TableCell extends TableCellBase { } get _headerCell() { - const row = this.parentElement as TableRow; - const table = row.parentElement as Table; - const index = row.cells.indexOf(this); - return table.headerRow[0].cells[index]; + const row = this.parentElement as TableRow | null; + const table = row?.parentElement as Table | null; + const index = row?.cells?.indexOf(this) ?? -1; + + return (index !== -1) ? table?.headerRow?.[0]?.cells?.[index] : null; } get _popinHeaderNodes() { const nodes: Node[] = []; const headerCell = this._headerCell; - if (headerCell.popinText) { - nodes.push(document.createTextNode(headerCell.popinText)); - } else { - nodes.push(...this._headerCell.content.map(node => node.cloneNode(true))); - } - if (headerCell.action[0]) { - nodes.push(headerCell.action[0].cloneNode(true)); + if (headerCell) { + if (headerCell.popinText) { + nodes.push(document.createTextNode(headerCell.popinText)); + } else { + nodes.push(...headerCell.content.map(node => node.cloneNode(true))); + } + if (headerCell.action[0]) { + nodes.push(headerCell.action[0].cloneNode(true)); + } } return nodes; } diff --git a/packages/main/src/TableCustomAnnouncement.ts b/packages/main/src/TableCustomAnnouncement.ts index 85d83f7bbd78..c8e0d79a7739 100644 --- a/packages/main/src/TableCustomAnnouncement.ts +++ b/packages/main/src/TableCustomAnnouncement.ts @@ -204,7 +204,7 @@ class TableCustomAnnouncement extends TableExtension { const cells = [...row._visibleCells, ...row._popinCells]; cells.flatMap(cell => { - return cell._popin ? [cell._popinHeader!, cell._popinContent!] : [cell._headerCell, cell]; + return cell._popin ? [cell._popinHeader!, cell._popinContent!] : [cell._headerCell!, cell]; }).forEach(node => { const nodeDescription = getAccessibilityDescription(node, true); descriptions.push(nodeDescription); diff --git a/packages/main/src/TableHeaderCell.ts b/packages/main/src/TableHeaderCell.ts index 0d4057d55853..359b3fa93afb 100644 --- a/packages/main/src/TableHeaderCell.ts +++ b/packages/main/src/TableHeaderCell.ts @@ -122,9 +122,6 @@ class TableHeaderCell extends TableCellBase { @slot() action!: Array; - @property({ type: Boolean, noAttribute: true }) - _popin = false; - @query("slot:not([name])") _defaultSlot!: HTMLSlotElement; @@ -136,10 +133,7 @@ class TableHeaderCell extends TableCellBase { onBeforeRendering() { super.onBeforeRendering(); - if (this._individualSlot) { - // overwrite setting of TableCellBase so that the TableHeaderCell always uses the slot variable - this.style.justifyContent = `var(--horizontal-align-${this._individualSlot})`; - } + this.style.justifyContent = this.horizontalAlign || ""; toggleAttribute(this, "aria-sort", this.sortIndicator !== SortOrder.None, this.sortIndicator.toLowerCase()); } diff --git a/packages/main/src/TableHeaderCellActionBase.ts b/packages/main/src/TableHeaderCellActionBase.ts index c40045b2b728..4d1df305fe03 100644 --- a/packages/main/src/TableHeaderCellActionBase.ts +++ b/packages/main/src/TableHeaderCellActionBase.ts @@ -60,7 +60,7 @@ abstract class TableHeaderCellActionBase extends UI5Element { _onClick(e: UI5CustomEvent) { // Retrieve the real action (if parent is header cell this instance is fine, otherwise retrieve it from the header cell) - const action = this.parentElement?.hasAttribute("ui5-table-header-cell") ? this : ((this.getRootNode() as ShadowRoot).host as TableCell)._headerCell.action[0] as this; + const action = this.parentElement?.hasAttribute("ui5-table-header-cell") ? this : ((this.getRootNode() as ShadowRoot).host as TableCell)._headerCell!.action[0] as this; action.fireDecoratorEvent("click", { targetRef: e.target as HTMLElement }); e.stopPropagation(); } diff --git a/packages/main/src/themes/TableCellBase.css b/packages/main/src/themes/TableCellBase.css index 8808614e30b9..82306841c121 100644 --- a/packages/main/src/themes/TableCellBase.css +++ b/packages/main/src/themes/TableCellBase.css @@ -10,6 +10,10 @@ box-sizing: border-box; } +:host([_popin]) { + justify-content: normal !important; +} + :host([tabindex]:focus) { outline: var(--sapContent_FocusWidth) var(--sapContent_FocusStyle) var(--sapContent_FocusColor); outline-offset: calc(-1 * var(--sapContent_FocusWidth)); diff --git a/packages/main/test/pages/Table.html b/packages/main/test/pages/Table.html index 65270e1770b1..129af7806a00 100644 --- a/packages/main/test/pages/Table.html +++ b/packages/main/test/pages/Table.html @@ -53,7 +53,7 @@ Very Best Screens
30 x 18 x 3 cmCalculate
4.2 KG - 956 EUR + 956 EUR Notebook Basic 16
HT-1001