diff --git a/packages/main/src/Table.ts b/packages/main/src/Table.ts index 709c3a65c792..1a03806967c8 100644 --- a/packages/main/src/Table.ts +++ b/packages/main/src/Table.ts @@ -465,9 +465,16 @@ class Table extends UI5Element { } get styles() { + const headerStyleMap = this.headerRow?.[0]?.cells?.reduce((headerStyles, headerCell) => { + if (headerCell.horizontalAlign !== undefined) { + headerStyles[`--horizontal-align-${headerCell._individualSlot}`] = headerCell.horizontalAlign; + } + return headerStyles; + }, {} as { [key: string]: string }); return { table: { "grid-template-columns": this._gridTemplateColumns, + ...headerStyleMap, }, }; } diff --git a/packages/main/src/TableCell.ts b/packages/main/src/TableCell.ts index f749d1ff591b..68725811ad8b 100644 --- a/packages/main/src/TableCell.ts +++ b/packages/main/src/TableCell.ts @@ -30,6 +30,15 @@ import { LABEL_COLON } from "./generated/i18n/i18n-defaults.js"; template: TableCellTemplate, }) class TableCell extends TableCellBase { + onBeforeRendering() { + super.onBeforeRendering(); + if (this.horizontalAlign) { + this.style.justifyContent = this.horizontalAlign; + } else { + this.style.justifyContent = `var(--horizontal-align-${(this as any)._individualSlot})`; + } + } + get _popinHeader() { const row = this.parentElement as TableRow; const table = row.parentElement as Table; diff --git a/packages/main/src/TableCellBase.ts b/packages/main/src/TableCellBase.ts index 6abffab2b098..ffaf468087ae 100644 --- a/packages/main/src/TableCellBase.ts +++ b/packages/main/src/TableCellBase.ts @@ -6,6 +6,7 @@ import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; import { getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import TableCellBaseStyles from "./generated/themes/TableCellBase.css.js"; +import type TableCellHorizontalAlign from "./types/TableCellHorizontalAlign.js"; /** * @class @@ -31,6 +32,17 @@ abstract class TableCellBase extends UI5Element { @property({ type: Boolean }) _popin = false; + /** + * Determines the horizontal alignment of table cells. + * Note: All values valid for justify-content can be used not just the ones inside the enum. + * @default undefined + * @public + */ + @property() + horizontalAlign?: `${TableCellHorizontalAlign}`; + + _individualSlot?: string; + protected ariaRole: string = "gridcell"; static i18nBundle: I18nBundle; diff --git a/packages/main/src/TableHeaderCell.ts b/packages/main/src/TableHeaderCell.ts index bd9e89328fc8..0c318c1291a4 100644 --- a/packages/main/src/TableHeaderCell.ts +++ b/packages/main/src/TableHeaderCell.ts @@ -85,6 +85,12 @@ class TableHeaderCell extends TableCellBase { this.style.maxWidth = this.maxWidth; this.style.width = this.width; } + + onBeforeRendering() { + super.onBeforeRendering(); + // overwrite setting of TableCellBase so that the TableHeaderCell always uses the slot variable + this.style.justifyContent = `var(--horizontal-align-${this._individualSlot})`; + } } TableHeaderCell.define(); diff --git a/packages/main/src/TableHeaderRow.ts b/packages/main/src/TableHeaderRow.ts index f2f68090f859..c839e7977c1e 100644 --- a/packages/main/src/TableHeaderRow.ts +++ b/packages/main/src/TableHeaderRow.ts @@ -56,7 +56,7 @@ class TableHeaderRow extends TableRowBase { type: HTMLElement, "default": true, invalidateOnChildChange: { - properties: ["width", "_popin"], + properties: ["width", "_popin", "horizontalAlign"], slots: false, }, individualSlots: true, diff --git a/packages/main/src/types/TableCellHorizontalAlign.ts b/packages/main/src/types/TableCellHorizontalAlign.ts new file mode 100644 index 000000000000..06b39225fd37 --- /dev/null +++ b/packages/main/src/types/TableCellHorizontalAlign.ts @@ -0,0 +1,33 @@ +/** + * Alignment of the <ui5-table-cell> component. + * + * @public + */ +enum TableCellHorizontalAlign { + /** + * @public + */ + Left = "Left", + + /** + * @public + */ + Start = "Start", + + /** + * @public + */ + Right = "Right", + + /** + * @public + */ + End = "End", + + /** + * @public + */ + Center = "Center", +} + +export default TableCellHorizontalAlign; diff --git a/packages/main/test/pages/HAlignTable.html b/packages/main/test/pages/HAlignTable.html new file mode 100644 index 000000000000..1a64c4933b0e --- /dev/null +++ b/packages/main/test/pages/HAlignTable.html @@ -0,0 +1,46 @@ + + + + + + + + Table (horizontal alignment) + + + +
+ + + Product + Supplier + Dimensions + Weight + Price + + + Notebook Basic 15
HT-1000
+ Very Best Screens + 30 x 18 x 3 cm + 4.2 KG + 956 EUR +
+ + Notebook Basic 17
HT-1001
+ Smartcards + 29 x 17 x 3.1 cm + 4.5 KG + 1249 EUR +
+ + Notebook Basic 18
HT-1002
+ Technocom + 32 x 21 x 4 cm + 3.7 KG + 29 EUR +
+
+
+ + + diff --git a/packages/main/test/specs/Table.spec.js b/packages/main/test/specs/Table.spec.js index 508d5467c4db..69325edaf986 100644 --- a/packages/main/test/specs/Table.spec.js +++ b/packages/main/test/specs/Table.spec.js @@ -156,6 +156,248 @@ describe("Table - Popin Mode", async () => { }); }); +describe("Table - Horizontal alignment of cells", async () => { + beforeEach(async () => { + await browser.url(`test/pages/HAlignTable.html`); + }); + + it("default alignment when horizontalAlign is not set", async () => { + let table = await browser.$("#table"); + assert.ok(table.isExisting(), "Table exists"); + + const headerRow = await table.$("ui5-table-header-row"); + const headerCells = await headerRow.$$("ui5-table-header-cell"); + assert.equal(headerCells.length, 5, "5 columns exist"); + + const index = 0; + const headerCell = headerCells[index]; + const alignment = "normal"; + assert.equal(await headerCell.getAttribute("id"), "productCol", "Correct cell"); + assert.equal(await headerCell.getAttribute("horizontal-align"), undefined, "horizontalAlign not set"); + + const justifyContentHeaderCell = await headerCell.getCSSProperty("justify-content"); + const style = await headerCell.getAttribute("style"); + const justifyContentHeaderCellUncomputed = style.match(/justify-content: ([^;]+)/)[1]; + const cssVariable = "var(--horizontal-align-default-1)"; + assert.equal(justifyContentHeaderCell.value, alignment, "justify-content correctly set."); + assert.equal(justifyContentHeaderCellUncomputed, cssVariable, "horizontalAlign not set"); + + const tableRows = await table.$$("ui5-table-row"); + for (const row of tableRows) { + const rowCells = await row.$$("ui5-table-cell"); + const justifyContent = await rowCells[3].getCSSProperty("justify-content"); + + assert.equal(justifyContent.value, alignment, "justify-content correctly set."); + } + }); + + it("horizontal alignment if horizontalAlign is set to a value not defined in TableCellHorizontalAlign", async () => { + let table = await browser.$("#table"); + assert.ok(table.isExisting(), "Table exists"); + + const headerRow = await table.$("ui5-table-header-row"); + const headerCells = await headerRow.$$("ui5-table-header-cell"); + assert.equal(headerCells.length, 5, "5 columns exist"); + + const index = 0; + const headerCell = headerCells[index]; + assert.equal(await headerCell.getAttribute("id"), "productCol", "Correct cell"); + + let alignment = "right"; + await headerCell.setAttribute("horizontal-align", "Right"); + + let justifyContentHeaderCell = await headerCell.getCSSProperty("justify-content"); + let style = await headerCell.getAttribute("style"); + let justifyContentHeaderCellUncomputed = style.match(/justify-content: ([^;]+)/)[1]; + const cssVariable = "var(--horizontal-align-default-1)"; + assert.equal(justifyContentHeaderCell.value, alignment, "justify-content correctly set."); + assert.equal(justifyContentHeaderCellUncomputed, cssVariable, "horizontalAlign set to css variable"); + + alignment = "normal"; + let hAlign = "valueNotDefinedInEnum"; + await headerCell.setAttribute("horizontal-align", hAlign); + + assert.equal(await headerCell.getAttribute("horizontal-align"), hAlign, "horizontalAlign correctly set"); + justifyContentHeaderCell = await headerCell.getCSSProperty("justify-content"); + assert.equal(justifyContentHeaderCell.value, alignment, "justify-content correctly set."); + style = await headerCell.getAttribute("style"); + justifyContentHeaderCellUncomputed = style.match(/justify-content: ([^;]+)/)[1]; + assert.equal(justifyContentHeaderCellUncomputed, cssVariable, "horizontalAlign set to css variable"); + + const tableRows = await table.$$("ui5-table-row"); + for (const row of tableRows) { + const rowCells = await row.$$("ui5-table-cell"); + const justifyContent = await rowCells[3].getCSSProperty("justify-content"); + + assert.equal(justifyContent.value, alignment, "justify-content correctly set."); + } + }); + + it("cells have same alignment as their headerCell", async () => { + let table = await browser.$("#table"); + assert.ok(table.isExisting(), "Table exists"); + + const headerRow = await table.$("ui5-table-header-row"); + const headerCells = await headerRow.$$("ui5-table-header-cell"); + assert.equal(headerCells.length, 5, "5 columns exist"); + + const cellIndex = 1; // second row is supplier row + const headerCell = headerCells[cellIndex]; + const id = await headerCell.getAttribute("id"); + const hAlign = await headerCell.getAttribute("horizontal-align"); + assert.equal(id, "supplierCol", "Correct cell"); + assert.ok(hAlign, "horizontalAlign set"); + + const alignment = `center`; // alignment set to center in table example + const justifyContentHeaderCell = await headerCell.getCSSProperty("justify-content"); + assert.equal(justifyContentHeaderCell.value, alignment, "justify-content correctly set."); + + const tableRows = await table.$$("ui5-table-row"); + for (const row of tableRows) { + const rowCells = await row.$$("ui5-table-cell"); + const justifyContent = await rowCells[cellIndex].getCSSProperty("justify-content"); + + assert.equal(justifyContent.value, alignment, "justify-content correctly set."); + } + }); + + it("on changing the horizontal-alignment of the headerCell, the horizontal-alignment of subsequent cells must change as well", async () => { + let table = await browser.$("#table"); + assert.ok(table.isExisting(), "Table exists"); + + const headerRow = await table.$("ui5-table-header-row"); + const headerCells = await headerRow.$$("ui5-table-header-cell"); + assert.equal(headerCells.length, 5, "5 columns exist"); + + // test setup + const cellIndex = 1; // second row is supplier row + const headerCell = headerCells[cellIndex]; + const id = await headerCell.getAttribute("id"); + let hAlign = await headerCell.getAttribute("horizontal-align"); + assert.equal(id, "supplierCol", "Correct cell"); + assert.ok(hAlign, "horizontalAlign set"); + + let alignment = `center`; // alignment set to center in table example + let justifyContentHeaderCell = await headerCell.getCSSProperty("justify-content"); + assert.equal(justifyContentHeaderCell.value, alignment, "justify-content correctly set."); + + // update the values + alignment = "left"; + await headerCell.setAttribute("horizontal-align", "Left"); + hAlign = await headerCell.getAttribute("horizontal-align"); + justifyContentHeaderCell = await headerCell.getCSSProperty("justify-content"); + + assert.equal(id, "supplierCol", "Correct cell"); + assert.ok(hAlign, "horizontalAlign set"); + assert.equal(justifyContentHeaderCell.value, alignment, "justify-content value updated."); + + const tableRows = await table.$$("ui5-table-row"); + for (const row of tableRows) { + const rowCells = await row.$$("ui5-table-cell"); + const justifyContent = await rowCells[cellIndex].getCSSProperty("justify-content"); + + assert.equal(justifyContent.value, alignment, "justify-content correctly set."); + } + }); + + it("on changing the horizontal-alignment of a cell, the horizontal-alignment of other cells must not change", async () => { + let table = await browser.$("#table"); + assert.ok(table.isExisting(), "Table exists"); + + const headerRow = await table.$("ui5-table-header-row"); + const headerCells = await headerRow.$$("ui5-table-header-cell"); + assert.equal(headerCells.length, 5, "5 columns exist"); + + const cellIndex = 1; // second row is supplier row + const headerCell = headerCells[cellIndex]; + const id = await headerCell.getAttribute("id"); + const hAlign = await headerCell.getAttribute("horizontal-align"); + assert.equal(id, "supplierCol", "Correct cell"); + assert.ok(hAlign, "horizontalAlign set"); + + const alignment = `center`; // alignment set to center in table example + const justifyContentHeaderCell = await headerCell.getCSSProperty("justify-content"); + assert.equal(justifyContentHeaderCell.value, alignment, "justify-content value of the headerCell is correct."); + + const tableRows = await table.$$("ui5-table-row"); + const rowWithChangedCell = 0; + const cell = await tableRows[rowWithChangedCell].$$("ui5-table-cell")[cellIndex]; + let hAlignCell = await cell.getAttribute("horizontal-align"); + assert.equal(hAlignCell, null, "horizontalAlign property of the cell is not set."); + + let justifyContentCell = await cell.getCSSProperty("justify-content"); + assert.equal(justifyContentCell.value, alignment, "justify-content of the cell matches the headerCell"); + + const customAlignmentCell = "left"; // alignment used for a single cell + await cell.setAttribute("horizontal-align", "Left"); + hAlignCell = await cell.getAttribute("horizontal-align"); + assert.notEqual(hAlignCell, null, "horizontalAlign property of the cell is set now."); + + justifyContentCell = await cell.getCSSProperty("justify-content"); + assert.equal(justifyContentCell.value, customAlignmentCell, "justify-content was changed and now matches the custom cell alignment value."); + + for (const [index, row] of tableRows.entries()) { + const rowCells = await row.$$("ui5-table-cell"); + const justifyContent = await rowCells[cellIndex].getCSSProperty("justify-content"); + + // the alignment of every cell but the changed one still has to match the headerCell alignment + assert.equal(justifyContent.value, index === rowWithChangedCell ? customAlignmentCell : alignment, "justify-content correctly set."); + } + }); + + it("the horizontal-alignment of a cell differs from the others, on changing the horizontal-alignment of the headerCell, the horizontal-alignment of other cells must change as well except of this one custom aligned cell", async () => { + let table = await browser.$("#table"); + assert.ok(table.isExisting(), "Table exists"); + + const headerRow = await table.$("ui5-table-header-row"); + const headerCells = await headerRow.$$("ui5-table-header-cell"); + assert.equal(headerCells.length, 5, "5 columns exist"); + + const cellIndex = 1; // second row is supplier row + const headerCell = headerCells[cellIndex]; + const id = await headerCell.getAttribute("id"); + const hAlign = await headerCell.getAttribute("horizontal-align"); + assert.equal(id, "supplierCol", "Correct cell"); + assert.ok(hAlign, "horizontalAlign set"); + + let alignment = "center"; // alignment set to center in table example + let justifyContent = await headerCell.getCSSProperty("justify-content"); + assert.equal(justifyContent.value, alignment, "justify-content correctly set."); + + const tableRows = await table.$$("ui5-table-row"); + const rowWithChangedCell = 0; + const cell = await tableRows[rowWithChangedCell].$$("ui5-table-cell")[cellIndex]; + let justifyContentCell = await cell.getCSSProperty("justify-content"); + let hAlignCell = await cell.getAttribute("horizontal-align"); + assert.equal(hAlignCell, null, "horizontalAlign property of the cell is not set."); + assert.equal(justifyContentCell.value, alignment, "justify-content value matches headerCell alignment"); + + const customAlignmentCell = "left"; // alignment used for a single cell + await cell.setAttribute("horizontal-align", "Left"); + hAlignCell = await cell.getAttribute("horizontal-align"); + + assert.notEqual(hAlignCell, null, "horizontalAlign property of the cell is set now."); + + justifyContentCell = await cell.getCSSProperty("justify-content"); + assert.equal(justifyContentCell.value, customAlignmentCell, "justify-content of cell adjusted correctly."); + + alignment = "right" + await headerCell.setAttribute("horizontal-align", "Right"); + hAlignCell = await cell.getAttribute("horizontal-align"); + justifyContent = await headerCell.getCSSProperty("justify-content"); + + assert.ok(hAlign, "horizontalAlign set"); + assert.equal(justifyContent.value, alignment, "justify-content of headerCell changed correctly."); + + for (const [index, row] of tableRows.entries()) { + const rowCells = await row.$$("ui5-table-cell"); + const justifyContent = await rowCells[cellIndex].getCSSProperty("justify-content"); + + assert.equal(justifyContent.value, index === rowWithChangedCell ? customAlignmentCell : alignment, "justify-content correctly set."); + } + }); +}); + // Tests for the fixed header, whether it is shown correctly and behaves as expected describe("Table - Fixed Header", async () => { before(async () => { diff --git a/packages/website/docs/_components_pages/main/Table/TableCell.mdx b/packages/website/docs/_components_pages/main/Table/TableCell.mdx index 18de9948c7b7..77c222924066 100644 --- a/packages/website/docs/_components_pages/main/Table/TableCell.mdx +++ b/packages/website/docs/_components_pages/main/Table/TableCell.mdx @@ -3,6 +3,22 @@ slug: ../../TableCell sidebar_class_name: newComponentBadge expComponentBadge --- +import HAlign from "../../../_samples/main/Table/HAlign/HAlign.md"; + <%COMPONENT_OVERVIEW%> <%COMPONENT_METADATA%> + +### Horizontal cell alignment + +Control the horizontal alignment of cells by utilizing the `horizontalAlign` property. + +Please note that the behaviour of `horizontalAlign` depends on where you set it: +1. `horizontalAlign` is set on `TableHeaderCell` level
+Changes the horizontal alignment of the `TableHeaderCell` and their corresponding `TableCells`. +2. `horizontalAlign` is set on `TableCell` level only
+The horizontal alignment is only changed for this one `TableCell` +3. `horizontalAlign` is set on `TableHeaderCell` and `TableCell` level
+Changing the `horizontalAlign` property on `TableHeaderCell` level changes only the `TableHeaderCell` itself and those `TableCells` without a `horizontalAlign` property. + + \ No newline at end of file diff --git a/packages/website/docs/_components_pages/main/Table/TableHeaderCell.mdx b/packages/website/docs/_components_pages/main/Table/TableHeaderCell.mdx index c91da75d5a9f..053c39cda2da 100644 --- a/packages/website/docs/_components_pages/main/Table/TableHeaderCell.mdx +++ b/packages/website/docs/_components_pages/main/Table/TableHeaderCell.mdx @@ -5,6 +5,7 @@ sidebar_class_name: newComponentBadge expComponentBadge import Popin from "../../../_samples/main/Table/Popin/Popin.md"; import ColumnWidths from "../../../_samples/main/Table/ColumnWidths/ColumnWidths.md"; +import HAlign from "../../../_samples/main/Table/HAlign/HAlign.md"; <%COMPONENT_OVERVIEW%> @@ -16,4 +17,18 @@ import ColumnWidths from "../../../_samples/main/Table/ColumnWidths/ColumnWidths ## Popin Configuration - \ No newline at end of file + + +### Horizontal cell alignment + +Control the horizontal alignment of cells by utilizing the `horizontalAlign` property. + +Please note that the behaviour of `horizontalAlign` depends on where you set it: +1. `horizontalAlign` is set on `TableHeaderCell` level
+Changes the horizontal alignment of the `TableHeaderCell` and their corresponding `TableCells`. +2. `horizontalAlign` is set on `TableCell` level only
+The horizontal alignment is only changed for this one `TableCell` +3. `horizontalAlign` is set on `TableHeaderCell` and `TableCell` level
+Changing the `horizontalAlign` property on `TableHeaderCell` level changes only the `TableHeaderCell` itself and those `TableCells` without a `horizontalAlign` property. + + \ No newline at end of file diff --git a/packages/website/docs/_samples/main/Table/HAlign/HAlign.md b/packages/website/docs/_samples/main/Table/HAlign/HAlign.md new file mode 100644 index 000000000000..17798ecc59ab --- /dev/null +++ b/packages/website/docs/_samples/main/Table/HAlign/HAlign.md @@ -0,0 +1,4 @@ +import html from '!!raw-loader!./sample.html'; +import js from '!!raw-loader!./main.js'; + + diff --git a/packages/website/docs/_samples/main/Table/HAlign/main.js b/packages/website/docs/_samples/main/Table/HAlign/main.js new file mode 100644 index 000000000000..5eef1b6cc847 --- /dev/null +++ b/packages/website/docs/_samples/main/Table/HAlign/main.js @@ -0,0 +1,4 @@ +import "@ui5/webcomponents/dist/Table.js"; +import "@ui5/webcomponents/dist/TableHeaderRow.js"; +import "@ui5/webcomponents/dist/TableHeaderCell.js"; +import "@ui5/webcomponents/dist/Label.js"; \ No newline at end of file diff --git a/packages/website/docs/_samples/main/Table/HAlign/sample.html b/packages/website/docs/_samples/main/Table/HAlign/sample.html new file mode 100644 index 000000000000..fbe97336c48d --- /dev/null +++ b/packages/website/docs/_samples/main/Table/HAlign/sample.html @@ -0,0 +1,50 @@ + + + + + + + + Sample + + + +
+ + + + Product + Supplier + Dimensions + Weight + Price + + + Notebook Basic 15
HT-1000
+ Very Best Screens + 30 x 18 x 3 cm + 4.2 KG + 956 EUR +
+ + Notebook Basic 17
HT-1001
+ Smartcards + 29 x 17 x 3.1 cm + 4.5 KG + 1249 EUR +
+ + Notebook Basic 18
HT-1002
+ Technocom + 32 x 21 x 4 cm + 3.7 KG + 29 EUR +
+
+ +
+ + + + +