@zywave/zui-table 4.0.0-pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +27 -0
  2. package/demo/index.html +435 -0
  3. package/dist/css/zui-table.fouc.css +1 -0
  4. package/dist/custom-elements.json +405 -0
  5. package/dist/index.d.ts +5 -0
  6. package/dist/index.js +6 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/zui-table-cell-css.d.ts +1 -0
  9. package/dist/zui-table-cell-css.js +3 -0
  10. package/dist/zui-table-cell-css.js.map +1 -0
  11. package/dist/zui-table-cell.d.ts +21 -0
  12. package/dist/zui-table-cell.js +43 -0
  13. package/dist/zui-table-cell.js.map +1 -0
  14. package/dist/zui-table-css.d.ts +1 -0
  15. package/dist/zui-table-css.js +3 -0
  16. package/dist/zui-table-css.js.map +1 -0
  17. package/dist/zui-table-footer-css.d.ts +1 -0
  18. package/dist/zui-table-footer-css.js +3 -0
  19. package/dist/zui-table-footer-css.js.map +1 -0
  20. package/dist/zui-table-footer.d.ts +17 -0
  21. package/dist/zui-table-footer.js +22 -0
  22. package/dist/zui-table-footer.js.map +1 -0
  23. package/dist/zui-table-row-css.d.ts +1 -0
  24. package/dist/zui-table-row-css.js +3 -0
  25. package/dist/zui-table-row-css.js.map +1 -0
  26. package/dist/zui-table-row.d.ts +31 -0
  27. package/dist/zui-table-row.js +52 -0
  28. package/dist/zui-table-row.js.map +1 -0
  29. package/dist/zui-table-topbar-css.d.ts +1 -0
  30. package/dist/zui-table-topbar-css.js +3 -0
  31. package/dist/zui-table-topbar-css.js.map +1 -0
  32. package/dist/zui-table-topbar.d.ts +17 -0
  33. package/dist/zui-table-topbar.js +24 -0
  34. package/dist/zui-table-topbar.js.map +1 -0
  35. package/dist/zui-table.d.ts +45 -0
  36. package/dist/zui-table.js +96 -0
  37. package/dist/zui-table.js.map +1 -0
  38. package/lab.html +467 -0
  39. package/package.json +37 -0
  40. package/src/css/zui-table.fouc.scss +137 -0
  41. package/src/index.ts +5 -0
  42. package/src/zui-table-cell-css.js +3 -0
  43. package/src/zui-table-cell.scss +5 -0
  44. package/src/zui-table-cell.ts +41 -0
  45. package/src/zui-table-css.js +3 -0
  46. package/src/zui-table-footer-css.js +3 -0
  47. package/src/zui-table-footer.scss +12 -0
  48. package/src/zui-table-footer.ts +30 -0
  49. package/src/zui-table-row-css.js +3 -0
  50. package/src/zui-table-row.scss +25 -0
  51. package/src/zui-table-row.ts +49 -0
  52. package/src/zui-table-topbar-css.js +3 -0
  53. package/src/zui-table-topbar.scss +40 -0
  54. package/src/zui-table-topbar.ts +32 -0
  55. package/src/zui-table.scss +39 -0
  56. package/src/zui-table.ts +93 -0
  57. package/test/zui-table.test.ts +129 -0
  58. package/tsconfig.build.json +10 -0
@@ -0,0 +1,41 @@
1
+ import { ZuiBaseElement } from '@zywave/zui-base';
2
+ import { html } from 'lit';
3
+ import { property } from 'lit/decorators.js';
4
+ import { style } from './zui-table-cell-css.js';
5
+
6
+ /**
7
+ * @element zui-table-cell
8
+ *
9
+ * @slot - Default slot; table cell content goes here
10
+ *
11
+ * @attr {number} span - Set number of columns the table cell should span
12
+ * @prop {number} span - Set number of columns the table cell should span
13
+ *
14
+ * @cssprop [--zui-table-cell-padding=13px 20px] - Override cell padding
15
+ */
16
+ export class ZuiTableCellElement extends ZuiBaseElement {
17
+ @property({ type: Number })
18
+ span = 1;
19
+
20
+ static get styles() {
21
+ return [super.styles, style];
22
+ }
23
+
24
+ // TODO: change role="cell" to role="columnheader" if parent is <zui-table-row header>
25
+ render() {
26
+ const spanStyle = html`<style>
27
+ :host {
28
+ grid-column: span ${this.span} !important;
29
+ }
30
+ </style>`;
31
+ return html`${this.span >= 1 ? spanStyle : ''}<div role="cell"><slot></slot></div>`;
32
+ }
33
+ }
34
+
35
+ window.customElements.define('zui-table-cell', ZuiTableCellElement);
36
+
37
+ declare global {
38
+ interface HTMLElementTagNameMap {
39
+ 'zui-table-cell': ZuiTableCellElement;
40
+ }
41
+ }
@@ -0,0 +1,3 @@
1
+ import { css } from 'lit';
2
+
3
+ export const style = css`:host{display:block}:host([banded]) ::slotted(zui-table-row:not([header]):nth-child(even)){background-color:var(--zui-gray-25)}:host([banded]) ::slotted(zui-table-row:not([header])){border:0}:host([no-results]) .no-results{padding:.75rem 1.25rem}::slotted(zui-table-row:not([header])){border-bottom:1px solid var(--zui-gray-100)}::slotted(zui-table-row:not([header]):last-of-type){border-bottom:0}.table{display:flex;width:100%;flex-direction:column;background-color:#fff;box-shadow:0 1px 3px rgba(0,0,0,.29);border-collapse:collapse;border-spacing:0}`;
@@ -0,0 +1,3 @@
1
+ import { css } from 'lit';
2
+
3
+ export const style = css`.footer{display:flex;justify-content:center;align-items:center;margin-top:var(--zui-table-footer-margin, 0.625rem)}::slotted(zui-pager){width:100%}`;
@@ -0,0 +1,12 @@
1
+ @use '@zywave/zui-sass-scripts' as *;
2
+
3
+ .footer {
4
+ display: flex;
5
+ justify-content: center;
6
+ align-items: center;
7
+ margin-top: var(--zui-table-footer-margin, #{rem(10)});
8
+ }
9
+
10
+ ::slotted(zui-pager) {
11
+ width: 100%;
12
+ }
@@ -0,0 +1,30 @@
1
+ import { ZuiBaseElement } from '@zywave/zui-base';
2
+ import { html } from 'lit';
3
+ import { style } from './zui-table-footer-css.js';
4
+
5
+ /**
6
+ * @element zui-table-footer
7
+ *
8
+ * @slot - Default slot; table footer content goes here
9
+ *
10
+ * @cssprop [--zui-table-footer-margin=10px] - Margin between the table and footer of the table
11
+ */
12
+ export class ZuiTableFooterElement extends ZuiBaseElement {
13
+ static get styles() {
14
+ return [super.styles, style];
15
+ }
16
+
17
+ render() {
18
+ return html`<div class="footer">
19
+ <slot></slot>
20
+ </div>`;
21
+ }
22
+ }
23
+
24
+ window.customElements.define('zui-table-footer', ZuiTableFooterElement);
25
+
26
+ declare global {
27
+ interface HTMLElementTagNameMap {
28
+ 'zui-table-footer': ZuiTableFooterElement;
29
+ }
30
+ }
@@ -0,0 +1,3 @@
1
+ import { css } from 'lit';
2
+
3
+ export const style = css`:host([header]){background-color:#fff;border-bottom:1px solid var(--zui-gray-200)}:host([header]) ::slotted(zui-table-cell){--zui-table-cell-padding: 0.53125rem 1.25rem;font-weight:600}div{display:grid;grid-template-columns:repeat(var(--zui-table-columns), minmax(0, 1fr))}:host([summary]){background-color:var(--zui-table-summary-background-color, var(--zui-gray-600)) !important}:host([summary]) ::slotted(zui-table-cell){font-weight:600;color:var(--zui-table-summary-text-color, #fff)}`;
@@ -0,0 +1,25 @@
1
+ @use '@zywave/zui-sass-scripts' as *;
2
+
3
+ :host([header]) {
4
+ background-color: #fff;
5
+ border-bottom: 1px solid var(--zui-gray-200);
6
+
7
+ ::slotted(zui-table-cell) {
8
+ --zui-table-cell-padding: #{rem(8.5)} #{rem(20)};
9
+ font-weight: 600;
10
+ }
11
+ }
12
+
13
+ div {
14
+ display: grid;
15
+ grid-template-columns: repeat(var(--zui-table-columns), minmax(0, 1fr));
16
+ }
17
+
18
+ :host([summary]) {
19
+ background-color: var(--zui-table-summary-background-color, var(--zui-gray-600)) !important;
20
+
21
+ ::slotted(zui-table-cell) {
22
+ font-weight: 600;
23
+ color: var(--zui-table-summary-text-color, #fff);
24
+ }
25
+ }
@@ -0,0 +1,49 @@
1
+ import { ZuiBaseElement } from '@zywave/zui-base';
2
+ import { html } from 'lit';
3
+ import { property } from 'lit/decorators.js';
4
+ import { style } from './zui-table-row-css.js';
5
+
6
+ /**
7
+ * @element zui-table-row
8
+ *
9
+ * @slot - Default slot; `<zui-table-cell>`s are declared here
10
+ *
11
+ * @attr {boolean} header - Set table header row
12
+ * @attr {boolean} summary - Set table summary row
13
+ * @prop {boolean} header - Set table header row
14
+ * @prop {boolean} summary - Set table summary row
15
+ *
16
+ * @cssprop [--zui-table-summary-background-color=var(--zui-gray-600)] - Set the table summary background color
17
+ * @cssprop [--zui-table-summary-text-color=#fff] - Set the the table summary text color
18
+ */
19
+ export class ZuiTableRowElement extends ZuiBaseElement {
20
+ /**
21
+ * property to declare the first row as the table header row
22
+ */
23
+ @property({ type: Boolean, reflect: true })
24
+ header = false;
25
+
26
+ /**
27
+ * property to declare a summary row; typically the last row in zui-table before zui-table-footer
28
+ */
29
+ @property({ type: Boolean, reflect: true })
30
+ summary = false;
31
+
32
+ static get styles() {
33
+ return [super.styles, style];
34
+ }
35
+
36
+ render() {
37
+ return html`<div role="row">
38
+ <slot></slot>
39
+ </div>`;
40
+ }
41
+ }
42
+
43
+ window.customElements.define('zui-table-row', ZuiTableRowElement);
44
+
45
+ declare global {
46
+ interface HTMLElementTagNameMap {
47
+ 'zui-table-row': ZuiTableRowElement;
48
+ }
49
+ }
@@ -0,0 +1,3 @@
1
+ import { css } from 'lit';
2
+
3
+ export const style = css`.topbar{display:flex;width:100%;min-height:3.75rem;align-items:center;padding:.625rem 1.25rem;background-color:var(--zui-gray-25)}.content{display:flex;flex:1;align-items:center}.content ::slotted(zui-search){--zui-search-border-color: var(--zui-gray-50)}.counter{flex-shrink:0;margin-left:auto;padding-left:.625rem;font-size:.75rem;color:var(--zui-gray-400)}.action{margin-left:.625rem}.action ::slotted(zui-button:not(:first-of-type)){margin-left:.625rem}slot[name=action]{display:flex}`;
@@ -0,0 +1,40 @@
1
+ @use '@zywave/zui-sass-scripts' as *;
2
+
3
+ .topbar {
4
+ display: flex;
5
+ width: 100%;
6
+ min-height: rem(60);
7
+ align-items: center;
8
+ padding: rem(10) rem(20);
9
+ background-color: var(--zui-gray-25);
10
+ }
11
+
12
+ .content {
13
+ display: flex;
14
+ flex: 1;
15
+ align-items: center;
16
+
17
+ ::slotted(zui-search) {
18
+ --zui-search-border-color: var(--zui-gray-50);
19
+ }
20
+ }
21
+
22
+ .counter {
23
+ flex-shrink: 0;
24
+ margin-left: auto;
25
+ padding-left: rem(10);
26
+ font-size: rem(12);
27
+ color: var(--zui-gray-400);
28
+ }
29
+
30
+ .action {
31
+ margin-left: rem(10);
32
+
33
+ ::slotted(zui-button:not(:first-of-type)) {
34
+ margin-left: rem(10);
35
+ }
36
+ }
37
+
38
+ slot[name='action'] {
39
+ display: flex;
40
+ }
@@ -0,0 +1,32 @@
1
+ import { ZuiBaseElement } from '@zywave/zui-base';
2
+ import { html } from 'lit';
3
+ import { style } from './zui-table-topbar-css.js';
4
+
5
+ /**
6
+ * @element zui-table-topbar
7
+ *
8
+ * @slot - Default slot; table cell content goes here
9
+ * @slot counter - Total number of results from table goes here
10
+ * @slot action - Action(s) that affect the whole table goes here
11
+ */
12
+ export class ZuiTableTopbarElement extends ZuiBaseElement {
13
+ static get styles() {
14
+ return [super.styles, style];
15
+ }
16
+
17
+ render() {
18
+ return html`<div class="topbar">
19
+ <div class="content"><slot></slot></div>
20
+ <div class="counter"><slot name="counter"></slot></div>
21
+ <div class="action"><slot name="action"></slot></div>
22
+ </div>`;
23
+ }
24
+ }
25
+
26
+ window.customElements.define('zui-table-topbar', ZuiTableTopbarElement);
27
+
28
+ declare global {
29
+ interface HTMLElementTagNameMap {
30
+ 'zui-table-topbar': ZuiTableTopbarElement;
31
+ }
32
+ }
@@ -0,0 +1,39 @@
1
+ @use '@zywave/zui-sass-scripts' as *;
2
+
3
+ :host {
4
+ display: block;
5
+ }
6
+
7
+ :host([banded]) {
8
+ ::slotted(zui-table-row:not([header]):nth-child(even)) {
9
+ background-color: var(--zui-gray-25);
10
+ }
11
+
12
+ ::slotted(zui-table-row:not([header])) {
13
+ border: 0;
14
+ }
15
+ }
16
+
17
+ :host([no-results]) {
18
+ .no-results {
19
+ padding: rem(12) rem(20);
20
+ }
21
+ }
22
+
23
+ ::slotted(zui-table-row:not([header])) {
24
+ border-bottom: 1px solid var(--zui-gray-100);
25
+ }
26
+
27
+ ::slotted(zui-table-row:not([header]):last-of-type) {
28
+ border-bottom: 0;
29
+ }
30
+
31
+ .table {
32
+ display: flex;
33
+ width: 100%;
34
+ flex-direction: column;
35
+ background-color: #fff;
36
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.29);
37
+ border-collapse: collapse;
38
+ border-spacing: 0;
39
+ }
@@ -0,0 +1,93 @@
1
+ import { ZuiBaseElement } from '@zywave/zui-base';
2
+ import { html } from 'lit';
3
+ import { property, query } from 'lit/decorators.js';
4
+ import { style } from './zui-table-css.js';
5
+ import { styleMap } from 'lit/directives/style-map.js';
6
+ import { findAssignedElement } from '@zywave/zui-base/dist/utils/find-assigned-element.js';
7
+
8
+ /**
9
+ * @element zui-table
10
+ *
11
+ * @slot - Default slot; all table content will appear here, such as table rows
12
+ * @slot no-results-message - Customize the no results message that is shown when `<zui-table>` has the attribute `no-results`: `<zui-table no-results>`
13
+ * @slot footer - Only for `<zui-table-footer>`. When there is a `<zui-table-footer>` present inside `<zui-table>`, it will be auto-assigned to this slot in order to place it outside of the rendered table for styling purposes.
14
+ *
15
+ * @attr {number} columns - Amount of columns to show in the table
16
+ * @attr {boolean} banded - Style option to alternate row background colors
17
+ * @attr {boolean} no-results - To show or hide no results message when there are no results
18
+ * @prop {number} columns - Amount of columns to show in the table
19
+ * @prop {boolean} banded - Style option to alternate row background colors
20
+ * @prop {boolean} noResults - To show or hide no results message when there are no results
21
+ *
22
+ * @cssprop [--zui-table-cell-padding=13px 20px] - Override cell padding
23
+ * @cssprop [--zui-table-summary-background-color=var(--zui-gray-600)] - Set the table summary background color
24
+ * @cssprop [--zui-table-summary-text-color=#fff] - Set the the table summary text color
25
+ * @cssprop [--zui-table-footer-margin=10px] - Margin between the table and footer of the table
26
+ */
27
+
28
+ export class ZuiTableElement extends ZuiBaseElement {
29
+ /**
30
+ * property to display number of columns
31
+ */
32
+ @property({ type: String, reflect: true })
33
+ columns = '1';
34
+
35
+ /**
36
+ * property to apply alternating background colors to table rows
37
+ */
38
+ @property({ type: Boolean, reflect: true })
39
+ banded = false;
40
+
41
+ // TODO: add divided prop so all table cells will have 1px border
42
+
43
+ /**
44
+ * property to show or hide no results message when there are no results in the table
45
+ */
46
+ @property({ type: Boolean, reflect: true, attribute: 'no-results' })
47
+ noResults = false;
48
+
49
+ @query('slot')
50
+ private _slotEl: HTMLSlotElement;
51
+
52
+ private get _footer() {
53
+ return findAssignedElement(this._slotEl, 'zui-table-footer');
54
+ }
55
+
56
+ static get styles() {
57
+ return [super.styles, style];
58
+ }
59
+
60
+ firstUpdated() {
61
+ this.#reassignFooter();
62
+ }
63
+
64
+ render() {
65
+ const columnsCssPropVal = {
66
+ '--zui-table-columns': this.columns,
67
+ };
68
+
69
+ return html`<div role="table" class="table" style="${styleMap(columnsCssPropVal)}">
70
+ <slot></slot>
71
+ ${this.noResults ? this.#renderNoResultsView() : ``}</div
72
+ >
73
+ <div><slot name="footer"></slot></div>`;
74
+ }
75
+
76
+ #renderNoResultsView() {
77
+ return html`<div class="no-results"><slot name="no-results-message"></slot></div>`;
78
+ }
79
+
80
+ #reassignFooter() {
81
+ if (this._footer) {
82
+ this._footer.setAttribute('slot', 'footer');
83
+ }
84
+ }
85
+ }
86
+
87
+ window.customElements.define('zui-table', ZuiTableElement);
88
+
89
+ declare global {
90
+ interface HTMLElementTagNameMap {
91
+ 'zui-table': ZuiTableElement;
92
+ }
93
+ }
@@ -0,0 +1,129 @@
1
+ // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2
+ /// <reference path="../../../../test/src/custom_typings/chai.d.ts" />
3
+ /* eslint-disable no-undef */
4
+ import {
5
+ ZuiTableElement,
6
+ ZuiTableRowElement,
7
+ ZuiTableCellElement,
8
+ ZuiTableTopbarElement,
9
+ ZuiTableFooterElement,
10
+ } from '@zywave/zui-table';
11
+ import { assert } from '@esm-bundle/chai';
12
+
13
+ suite('zui-table', () => {
14
+ let table: ZuiTableElement;
15
+ let row: ZuiTableRowElement;
16
+ let cell: ZuiTableCellElement;
17
+ let topbar: ZuiTableTopbarElement;
18
+ let footer: ZuiTableFooterElement;
19
+
20
+ setup(() => {
21
+ table = document.createElement('zui-table') as ZuiTableElement;
22
+ row = document.createElement('zui-table-row') as ZuiTableRowElement;
23
+ cell = document.createElement('zui-table-cell') as ZuiTableCellElement;
24
+ topbar = document.createElement('zui-table-topbar') as ZuiTableTopbarElement;
25
+ footer = document.createElement('zui-table-footer') as ZuiTableFooterElement;
26
+
27
+ row.appendChild(cell);
28
+ table.appendChild(topbar);
29
+ table.appendChild(row);
30
+ table.appendChild(footer);
31
+
32
+ document.body.appendChild(table);
33
+ });
34
+
35
+ teardown(() => {
36
+ document.body.removeChild(table);
37
+ });
38
+
39
+ test('initializes as a ZuiTableElement', () => {
40
+ assert.instanceOf(table, ZuiTableElement);
41
+ });
42
+
43
+ test('initializes as a ZuiTableRowElement', () => {
44
+ assert.instanceOf(row, ZuiTableRowElement);
45
+ });
46
+
47
+ test('initializes as a ZuiTableCellElement', () => {
48
+ assert.instanceOf(cell, ZuiTableCellElement);
49
+ });
50
+
51
+ test('initializes as a ZuiTableTopbarElement', () => {
52
+ assert.instanceOf(topbar, ZuiTableTopbarElement);
53
+ });
54
+
55
+ test('initializes as a ZuiTableFooterElement', () => {
56
+ assert.instanceOf(footer, ZuiTableFooterElement);
57
+ });
58
+
59
+ test('setting table columns number also reflects in custom CSS variable', async () => {
60
+ const randomColumnNumber = Math.floor(Math.random() * 10) + 1;
61
+ table.setAttribute('columns', `${randomColumnNumber}`);
62
+
63
+ await table.updateComplete;
64
+
65
+ const shadowEl = table.shadowRoot;
66
+ const firstChildEl = shadowEl.firstElementChild as HTMLElement;
67
+
68
+ const tableColumnsVal = table.getAttribute('columns');
69
+ const customCssPropVal = window.getComputedStyle(firstChildEl).getPropertyValue('--zui-table-columns');
70
+
71
+ assert.strictEqual(
72
+ tableColumnsVal,
73
+ customCssPropVal,
74
+ 'Expected column numbers to be reflected in CSS custom property'
75
+ );
76
+ });
77
+
78
+ test('banded attribute alternates background color for rows', async () => {
79
+ table.setAttribute('banded', '');
80
+ table.appendChild(row.cloneNode(true));
81
+
82
+ await table.updateComplete;
83
+
84
+ const tableRows = table.querySelectorAll('zui-table-row');
85
+ const tableRowBgColor = window.getComputedStyle(tableRows[1]);
86
+
87
+ assert.property(
88
+ tableRowBgColor,
89
+ 'background-color',
90
+ 'Expected alternate rows to have background color for banded tables'
91
+ );
92
+ });
93
+
94
+ test('table cells can span columns', async () => {
95
+ const randomColumnNumber = Math.floor(Math.random() * 10) + 1;
96
+ cell.setAttribute('span', `${randomColumnNumber}`);
97
+
98
+ await table.updateComplete;
99
+
100
+ const tableCell = table.querySelector('zui-table-cell');
101
+ const tableCellAttr = tableCell.getAttribute('span');
102
+ const tableCellComputedGridColumnVal = window.getComputedStyle(tableCell).getPropertyValue('grid-column-start');
103
+
104
+ assert.include(
105
+ tableCellComputedGridColumnVal,
106
+ tableCellAttr,
107
+ `Expected table cell to span ${randomColumnNumber} columns when "span" attribute is set`
108
+ );
109
+ });
110
+
111
+ test('table with no-results attribute results in a no results view', async () => {
112
+ table.setAttribute('no-results', '');
113
+ await table.updateComplete;
114
+
115
+ const shadowEl = table.shadowRoot;
116
+ const noResultsDiv = shadowEl.querySelector('.no-results');
117
+
118
+ assert.exists(noResultsDiv, 'Expected no-results view to show when zui-table as attribute no-results applied');
119
+ });
120
+
121
+ test('table with a footer will assign it to the slot "footer"', async () => {
122
+ await table.updateComplete;
123
+
124
+ const bb = table.querySelector('zui-table-footer');
125
+ const footerSlot = bb.hasAttribute('slot');
126
+
127
+ assert.isTrue(footerSlot, 'Expected zui-table-footer to be assigned to a slot');
128
+ });
129
+ });
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../../tsconfig.build.json",
3
+ "compilerOptions": {
4
+ "composite": true,
5
+ "outDir": "./dist",
6
+ "rootDir": "./src",
7
+ "tsBuildInfoFile": ".tsbuildinfo"
8
+ },
9
+ "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.js"]
10
+ }