Skip to content

Commit

Permalink
Table: Allow complex content to be displayed in Pharos tables (#840)
Browse files Browse the repository at this point in the history
* feat(table): allow more complex data in table

* chore(table): add changeset

* feat(table): update table rowData tests

* feat(table): add tests for content added via slot

* feat(table): add test coverage for new elements

* fix: revert unintended update to changelog

* Add a resizeObserver to table cells to set cell height (#862)

* fix(table): add resizeObserver to set cell height

When using slotted content in a table cell, it currently
is not possible to set the content to be 100% of the cell.
This is because using a slot takes the content our of the normal
flow and it doesn't know what height it should use when
set to 100%. By adding a resizeObserver to see the height of the cell
and set that height manually, the descendant content can set
height:100% and it will work as expected.

While each cell will be set to it's own height, the nature of
table rows means that all cells in a row will display as the
height of the tallest cell, regardless of what height they have
manually set.

* fix(table): account for border when calculating height
  • Loading branch information
brentswisher authored Jan 30, 2025
1 parent 54c0a5b commit 308b8af
Show file tree
Hide file tree
Showing 19 changed files with 952 additions and 334 deletions.
5 changes: 5 additions & 0 deletions .changeset/shaggy-fireants-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ithaka/pharos': minor
---

Allow complex content in tables through new table body, row, and cell custom elements
6 changes: 6 additions & 0 deletions .storybook/initComponents.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ import {
PharosTabs,
PharosTab,
PharosTable,
PharosTableBody,
PharosTableRow,
PharosTableCell,
PharosTabPanel,
PharosTextInput,
PharosTextarea,
Expand Down Expand Up @@ -90,6 +93,9 @@ registerComponents('storybook', [
PharosTabs,
PharosTab,
PharosTable,
PharosTableBody,
PharosTableRow,
PharosTableCell,
PharosTabPanel,
PharosTextInput,
PharosTextarea,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:host {
display: table-row-group;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { expect } from 'chai';
import { fixture, html } from '@open-wc/testing';
import { PharosTableBody } from './pharos-table-body';

describe('PharosTableBody', () => {
let component: PharosTableBody;
beforeEach(async () => {
component = await fixture(html` <test-pharos-table-body></test-pharos-table-body> `);
});

it('should have the correct role attribute on the custom element', async () => {
expect(component.getAttribute('role')).to.equal('rowgroup');
});

it('should have the correct display style on the custom element', async () => {
const displayValue = window.getComputedStyle(component, null).getPropertyValue('display');
expect(displayValue).to.equal('table-row-group');
});
});
25 changes: 25 additions & 0 deletions packages/pharos/src/components/table-body/pharos-table-body.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { html, type CSSResultArray, type TemplateResult } from 'lit';
import ScopedRegistryMixin from '../../utils/mixins/scoped-registry';
import { PharosElement } from '../base/pharos-element';
import { tableBodyStyles } from './pharos-table-body.css';

/**
* Pharos table body component.
*
* @tag pharos-table
*
*
*/
export class PharosTableBody extends ScopedRegistryMixin(PharosElement) {
public static override get styles(): CSSResultArray {
return [tableBodyStyles];
}

protected override firstUpdated(): void {
this.setAttribute('role', 'rowgroup');
}

protected override render(): TemplateResult {
return html`<slot></slot>`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
:host {
border: 1px solid var(--pharos-table-body-color-border, var(--pharos-color-ui-30));
padding: var(--pharos-spacing-1-x);
border-collapse: collapse;
display: table-cell;
vertical-align: top;
z-index: 100;
position: relative;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { expect } from 'chai';
import { fixture, html } from '@open-wc/testing';
import { PharosTableCell } from './pharos-table-cell';

describe('PharosTableCell', () => {
let component: PharosTableCell;
beforeEach(async () => {
component = await fixture(html` <test-pharos-table-cell></test-pharos-table-cell> `);
});

it('should have the correct role attribute on the custom element', async () => {
expect(component.getAttribute('role')).to.equal('cell');
});

it('should have the correct display style on the custom element', async () => {
const displayValue = window.getComputedStyle(component, null).getPropertyValue('display');
expect(displayValue).to.equal('table-cell');
});
});
42 changes: 42 additions & 0 deletions packages/pharos/src/components/table-cell/pharos-table-cell.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { html, type CSSResultArray, type TemplateResult } from 'lit';
import ScopedRegistryMixin from '../../utils/mixins/scoped-registry';
import { PharosElement } from '../base/pharos-element';
import { tableCellStyles } from './pharos-table-cell.css';

/**
* Pharos table cell component.
*
* @tag pharos-table
*
*
*/

export class PharosTableCell extends ScopedRegistryMixin(PharosElement) {
public static override get styles(): CSSResultArray {
return [tableCellStyles];
}

protected override firstUpdated(): void {
this.setAttribute('role', 'cell');

const resizeObserver = new ResizeObserver(() => {
// Using a slot inside `display: table-cell` breaks the height calculation, so we need to set it manually
const style = getComputedStyle(this);
const height =
this.getBoundingClientRect().height -
parseFloat(style.paddingTop) -
parseFloat(style.paddingBottom) -
parseFloat(style.borderBlockWidth);

this.style.height = `${height}px`;

resizeObserver.disconnect();
});

resizeObserver.observe(this);
}

protected override render(): TemplateResult {
return html`<slot></slot>`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:host {
display: table-row;
}
19 changes: 19 additions & 0 deletions packages/pharos/src/components/table-row/pharos-table-row.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { expect } from 'chai';
import { fixture, html } from '@open-wc/testing';
import { PharosTableRow } from './pharos-table-row';

describe('PharosTableRow', () => {
let component: PharosTableRow;
beforeEach(async () => {
component = await fixture(html` <test-pharos-table-row></test-pharos-table-row> `);
});

it('should have the correct role attribute on the custom element', async () => {
expect(component.getAttribute('role')).to.equal('row');
});

it('should have the correct display style on the custom element', async () => {
const displayValue = window.getComputedStyle(component, null).getPropertyValue('display');
expect(displayValue).to.equal('table-row');
});
});
25 changes: 25 additions & 0 deletions packages/pharos/src/components/table-row/pharos-table-row.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { html, type CSSResultArray, type TemplateResult } from 'lit';
import ScopedRegistryMixin from '../../utils/mixins/scoped-registry';
import { PharosElement } from '../base/pharos-element';
import { tableRowStyles } from './pharos-table-row.css';

/**
* Pharos table row component.
*
* @tag pharos-table
*
*
*/
export class PharosTableRow extends ScopedRegistryMixin(PharosElement) {
public static override get styles(): CSSResultArray {
return [tableRowStyles];
}

protected override firstUpdated(): void {
this.setAttribute('role', 'row');
}

protected override render(): TemplateResult {
return html`<slot></slot>`;
}
}
Loading

0 comments on commit 308b8af

Please sign in to comment.