@kubex/zinc 1.1.53 → 1.1.55
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.
- package/dist/chunks/zn.SBAUMVLL.js +4 -0
- package/dist/custom-elements.json +141 -78
- package/dist/vscode.html-custom-data.json +17 -12
- package/dist/web-types.json +31 -24
- package/dist/zn.d.ts +26 -1
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +561 -547
- package/docs/data/data-table-error.json +30 -0
- package/docs/pages/components/alert.md +8 -0
- package/docs/pages/components/channel-tile.md +1 -0
- package/docs/pages/components/data-table.md +44 -1
- package/docs/pages/components/datepicker.md +20 -0
- package/package.json +1 -1
- package/scss/_root.scss +52 -0
- package/scss/themes/_aura.scss +35 -0
- package/scss/themes/_index.scss +1 -0
- package/src/components/alert/alert.component.ts +1 -0
- package/src/components/alert/alert.scss +4 -0
- package/src/components/channel-tile/channel-tile.component.ts +33 -24
- package/src/components/channel-tile/channel-tile.scss +7 -2
- package/src/components/data-table/data-table.component.ts +32 -7
- package/src/components/data-table/data-table.scss +8 -0
- package/src/components/data-table/data-table.test.ts +26 -1
- package/src/components/datepicker/datepicker.component.ts +61 -3
- package/src/components/navbar/navbar.scss +10 -1
- package/src/components/page/page.scss +47 -0
- package/src/components/page/wave.svg +1 -0
- package/src/components/query-builder/query-builder.component.ts +0 -2
- package/src/components/query-builder/query-builder.scss +0 -4
- package/dist/chunks/zn.HEY2XOTB.js +0 -4
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rows": [
|
|
3
|
+
{
|
|
4
|
+
"id": "1",
|
|
5
|
+
"cells": [
|
|
6
|
+
{"text": "1", "column": "id"},
|
|
7
|
+
{"text": "Alice Johnson", "column": "name"},
|
|
8
|
+
{"text": "alice@example.com", "column": "email"},
|
|
9
|
+
{"text": "Active", "column": "status", "chipColor": "success"}
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": "2",
|
|
14
|
+
"cells": [
|
|
15
|
+
{"text": "2", "column": "id"},
|
|
16
|
+
{"text": "Bob Smith", "column": "name"},
|
|
17
|
+
{"text": "bob@example.com", "column": "email"},
|
|
18
|
+
{"text": "Active", "column": "status", "chipColor": "success"}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"page": 1,
|
|
23
|
+
"perPage": 10,
|
|
24
|
+
"total": 2,
|
|
25
|
+
"error": {
|
|
26
|
+
"text": "Results have been limited to 10 rows, please filter for more accuracy",
|
|
27
|
+
"level": "primary",
|
|
28
|
+
"icon": "info-circle"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -113,6 +113,14 @@ Use the `size` attribute to control the alert's size. Available sizes are `small
|
|
|
113
113
|
<zn-alert caption="Large Alert" size="large" level="warning">This is a large-sized alert.</zn-alert>
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
+
### Centered Text
|
|
117
|
+
|
|
118
|
+
Use the `center` attribute to center the alert's text content.
|
|
119
|
+
|
|
120
|
+
```html:preview
|
|
121
|
+
<zn-alert level="warning" center>This alert's text is centered.</zn-alert>
|
|
122
|
+
```
|
|
123
|
+
|
|
116
124
|
### Complex Content
|
|
117
125
|
|
|
118
126
|
Alerts can contain rich HTML content including lists, links, and formatted text.
|
|
@@ -624,6 +624,39 @@ This preview uses GET against a static file. In production, POST requests send p
|
|
|
624
624
|
</zn-data-table>
|
|
625
625
|
```
|
|
626
626
|
|
|
627
|
+
### Response Errors
|
|
628
|
+
|
|
629
|
+
Include an `error` object in the response to display a message inside the table, between the column headers and the first record, using the alert component. The error can be returned alongside row data — useful when results are valid but limited, or when a filter is invalid. The object supports `text`, an optional `icon`, and an optional `level` to control the alert level (defaults to `error`).
|
|
630
|
+
|
|
631
|
+
```html:preview
|
|
632
|
+
<zn-data-table
|
|
633
|
+
data-uri="/data/data-table-error.json"
|
|
634
|
+
method="GET"
|
|
635
|
+
headers='[
|
|
636
|
+
{"key":"id","label":"ID"},
|
|
637
|
+
{"key":"name","label":"Name"},
|
|
638
|
+
{"key":"email","label":"Email"},
|
|
639
|
+
{"key":"status","label":"Status"}
|
|
640
|
+
]'>
|
|
641
|
+
</zn-data-table>
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
```json
|
|
645
|
+
{
|
|
646
|
+
"rows": [...],
|
|
647
|
+
"page": 1,
|
|
648
|
+
"perPage": 10,
|
|
649
|
+
"total": 2,
|
|
650
|
+
"error": {
|
|
651
|
+
"text": "Results have been limited to 10 rows, please filter for more accuracy",
|
|
652
|
+
"icon": "warning",
|
|
653
|
+
"level": "warning"
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
If the response contains an error and no rows, the error is shown above the empty state.
|
|
659
|
+
|
|
627
660
|
### Cell Styling
|
|
628
661
|
|
|
629
662
|
Cells support various styling options through the data response format. Each cell can have colors, icons, links, chips, and hover content.
|
|
@@ -771,10 +804,20 @@ The data table expects responses in the following format:
|
|
|
771
804
|
],
|
|
772
805
|
"page": 1,
|
|
773
806
|
"perPage": 10,
|
|
774
|
-
"total": 100
|
|
807
|
+
"total": 100,
|
|
808
|
+
"error": {
|
|
809
|
+
"text": "Optional message displayed below the column headers",
|
|
810
|
+
"icon": "warning",
|
|
811
|
+
"level": "warning"
|
|
812
|
+
}
|
|
775
813
|
}
|
|
776
814
|
```
|
|
777
815
|
|
|
816
|
+
- `error`: Optional object displayed as an alert row below the column headers, alongside any returned rows
|
|
817
|
+
- `text`: The message to display
|
|
818
|
+
- `icon`: Optional icon shown in the alert
|
|
819
|
+
- `level`: Optional alert level (`primary`, `error`, `info`, `success`, `warning`, `note`), defaults to `error`
|
|
820
|
+
|
|
778
821
|
## Request Format
|
|
779
822
|
|
|
780
823
|
For POST requests, the table sends:
|
|
@@ -427,3 +427,23 @@ Displays time.
|
|
|
427
427
|
help-text="Select date and time">
|
|
428
428
|
</zn-datepicker>
|
|
429
429
|
```
|
|
430
|
+
|
|
431
|
+
### Dialogs & Shadow DOM
|
|
432
|
+
|
|
433
|
+
The calendar popup renders at the document level, so it is never clipped by ancestor shadow roots or
|
|
434
|
+
`overflow` containers. When the datepicker sits inside a modal dialog or popover, the calendar mounts
|
|
435
|
+
inside that element instead so it stays visible and interactive above the top layer.
|
|
436
|
+
|
|
437
|
+
```html:preview
|
|
438
|
+
<zn-button id="datepicker-dialog-opener">Open Dialog</zn-button>
|
|
439
|
+
<zn-dialog id="datepicker-dialog" label="Book a meeting">
|
|
440
|
+
<zn-datepicker label="Meeting date"></zn-datepicker>
|
|
441
|
+
</zn-dialog>
|
|
442
|
+
|
|
443
|
+
<script>
|
|
444
|
+
const dialog = document.querySelector('#datepicker-dialog');
|
|
445
|
+
document.querySelector('#datepicker-dialog-opener').addEventListener('click', () => dialog.show());
|
|
446
|
+
</script>
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
Use the `container` attribute only if you need to mount the calendar somewhere specific.
|
package/package.json
CHANGED
package/scss/_root.scss
CHANGED
|
@@ -305,3 +305,55 @@ ul.disc {
|
|
|
305
305
|
ul.square {
|
|
306
306
|
list-style-type: square;
|
|
307
307
|
}
|
|
308
|
+
|
|
309
|
+
// Aura — soft, light-based theme with a pastel violet identity.
|
|
310
|
+
// Appended last so it wins source-order over the :root/light defaults on the
|
|
311
|
+
// document element (which carries the `t="aura"` attribute *and* matches :root).
|
|
312
|
+
// Only the source colour tokens and the theme-specific leaf tokens are set;
|
|
313
|
+
// derived tokens (--zn-body, --zn-text, --zn-panel ...) reference these via
|
|
314
|
+
// var() and follow automatically.
|
|
315
|
+
[t="aura"], .theme-aura {
|
|
316
|
+
--zn-backdrop-color: rgba(30, 27, 60, 0.45);
|
|
317
|
+
|
|
318
|
+
--zn-color-text: 42, 32, 89;
|
|
319
|
+
--zn-color-muted-text: 128, 118, 158;
|
|
320
|
+
|
|
321
|
+
--zn-color-base: 255, 255, 255;
|
|
322
|
+
--zn-color-body: 250, 248, 255;
|
|
323
|
+
--zn-color-navigation: var(--zn-color-base);
|
|
324
|
+
--zn-color-navigation-hightlight: 245, 242, 255;
|
|
325
|
+
--zn-color-border: 228, 222, 246;
|
|
326
|
+
--zn-color-border-active: 214, 206, 240;
|
|
327
|
+
--zn-color-tab: 240, 235, 252;
|
|
328
|
+
--zn-color-panel: 255, 255, 255;
|
|
329
|
+
|
|
330
|
+
--zn-color-primary: 139, 110, 245;
|
|
331
|
+
--zn-color-info: 53, 104, 195;
|
|
332
|
+
--zn-color-success: 98, 177, 121;
|
|
333
|
+
--zn-color-warning: 241, 168, 80;
|
|
334
|
+
--zn-color-error: 236, 68, 91;
|
|
335
|
+
--zn-color-disabled: 181, 181, 181;
|
|
336
|
+
|
|
337
|
+
// Theme-specific leaf tokens (light/dark declare these in their own blocks,
|
|
338
|
+
// so aura must supply its own — they are not inherited from :root).
|
|
339
|
+
--zn-panel-opacity: 1;
|
|
340
|
+
--zn-shadow: 232, 226, 250;
|
|
341
|
+
--zn-panel-secondary: 248 246 255;
|
|
342
|
+
--zn-panel-highlight: 245, 242, 255;
|
|
343
|
+
--zn-panel-highlight-opacity: 1;
|
|
344
|
+
--zn-input-bg-accent: 240, 236, 252;
|
|
345
|
+
--zn-bright-bg: 255, 255, 255;
|
|
346
|
+
--zn-light-text: 130, 120, 160;
|
|
347
|
+
--zn-dark-text: 60, 44, 110;
|
|
348
|
+
--zn-purple-text: 124, 92, 246;
|
|
349
|
+
--zn-accent: 200, 130, 230;
|
|
350
|
+
|
|
351
|
+
// Frosted-glass inactive tabs for the zn-page tab navbar (consumed in
|
|
352
|
+
// components/navbar/navbar.scss, scoped there to :host-context(zn-page)).
|
|
353
|
+
--navbar-page-inactive-tab-background: rgba(255, 255, 255, 0.5);
|
|
354
|
+
--navbar-page-inactive-tab-filter: blur(2px);
|
|
355
|
+
|
|
356
|
+
.zn-primary {
|
|
357
|
+
color: rgb(var(--zn-color-primary));
|
|
358
|
+
}
|
|
359
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Aura — a soft, light-based theme with a pastel violet identity.
|
|
2
|
+
// It inherits the light theme primitives (defined on :root) and only
|
|
3
|
+
// re-points the primary ramp to a softer, more pastel violet so the
|
|
4
|
+
// whole UI takes on the "aura" glow without redefining every token.
|
|
5
|
+
[t="aura"],
|
|
6
|
+
.theme-aura {
|
|
7
|
+
color-scheme: light;
|
|
8
|
+
|
|
9
|
+
/**************************************************************
|
|
10
|
+
* Theme Tokens — soft violet primary
|
|
11
|
+
*************************************************************/
|
|
12
|
+
|
|
13
|
+
--zn-color-primary-50: hsl(258, 100%, 97%);
|
|
14
|
+
--zn-color-primary-100: hsl(256, 95%, 94%);
|
|
15
|
+
--zn-color-primary-200: hsl(255, 90%, 90%);
|
|
16
|
+
--zn-color-primary-300: hsl(255, 88%, 83%);
|
|
17
|
+
--zn-color-primary-400: hsl(256, 85%, 75%);
|
|
18
|
+
--zn-color-primary-500: hsl(255, 82%, 68%);
|
|
19
|
+
--zn-color-primary-600: hsl(256, 78%, 62%);
|
|
20
|
+
--zn-color-primary-700: hsl(257, 70%, 54%);
|
|
21
|
+
--zn-color-primary-800: hsl(258, 68%, 46%);
|
|
22
|
+
--zn-color-primary-900: hsl(259, 66%, 38%);
|
|
23
|
+
|
|
24
|
+
/* Soft, faintly violet-tinted elevations */
|
|
25
|
+
--zn-shadow-x-small: 0 1px 4px rgba(60, 44, 110, 0.08);
|
|
26
|
+
--zn-shadow-small: 0 3px 9px rgba(60, 44, 110, 0.12);
|
|
27
|
+
--zn-shadow-medium: 0 6px 18px rgba(60, 44, 110, 0.12);
|
|
28
|
+
--zn-shadow-large: 0 6px 20px rgba(60, 44, 110, 0.14);
|
|
29
|
+
--zn-shadow-x-large: 0 6px 20px rgba(60, 44, 110, 0.22);
|
|
30
|
+
|
|
31
|
+
--zn-border-color: 218, 212, 246;
|
|
32
|
+
|
|
33
|
+
/* Focus ring follows the softer primary */
|
|
34
|
+
--zn-input-focus-ring-color: hsl(255 82% 68% / 40%);
|
|
35
|
+
}
|
package/scss/themes/_index.scss
CHANGED
|
@@ -30,6 +30,7 @@ export default class ZnAlert extends ZincElement {
|
|
|
30
30
|
@property({type: Boolean}) collapse: boolean = false;
|
|
31
31
|
@property({type: String, reflect: true}) appearance: 'transparent' | 'solid' = 'transparent';
|
|
32
32
|
@property({type: String}) level: 'primary' | 'error' | 'info' | 'success' | 'warning' | 'note' | 'cosmic' = 'info';
|
|
33
|
+
@property({type: Boolean, reflect: true}) center: boolean = false;
|
|
33
34
|
@property({type: String}) size: 'small' | 'medium' | 'large' = 'medium';
|
|
34
35
|
|
|
35
36
|
render() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {classMap} from 'lit/directives/class-map.js';
|
|
2
|
-
import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
|
|
3
|
-
import {property} from 'lit/decorators.js';
|
|
1
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
2
|
+
import { type CSSResultGroup, html, type PropertyValues, unsafeCSS } from 'lit';
|
|
3
|
+
import { property } from 'lit/decorators.js';
|
|
4
4
|
import ZincElement from '../../internal/zinc-element';
|
|
5
5
|
|
|
6
6
|
import styles from './channel-tile.scss';
|
|
@@ -38,13 +38,13 @@ export default class ZnChannelTile extends ZincElement {
|
|
|
38
38
|
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
39
39
|
|
|
40
40
|
/** Renders the empty/available face instead of the active face. */
|
|
41
|
-
@property({type: Boolean, reflect: true}) available: boolean = false;
|
|
41
|
+
@property({ type: Boolean, reflect: true }) available: boolean = false;
|
|
42
42
|
|
|
43
43
|
/** (Available only) the tile is reserving an incoming item awaiting acceptance. */
|
|
44
|
-
@property({type: Boolean, reflect: true}) incoming: boolean = false;
|
|
44
|
+
@property({ type: Boolean, reflect: true }) incoming: boolean = false;
|
|
45
45
|
|
|
46
46
|
/** Free-form grouping/theming key (reflected so consumers can query/style by it). */
|
|
47
|
-
@property({reflect: true}) variant: string = '';
|
|
47
|
+
@property({ reflect: true }) variant: string = '';
|
|
48
48
|
|
|
49
49
|
/** Top-bar text (e.g. brand). */
|
|
50
50
|
@property() header: string = '';
|
|
@@ -53,7 +53,7 @@ export default class ZnChannelTile extends ZincElement {
|
|
|
53
53
|
@property() icon: string = '';
|
|
54
54
|
|
|
55
55
|
/** Accent color driving the leading icon and `--channel-tile-color`. */
|
|
56
|
-
@property({reflect: true}) color: ChannelTileColor = 'default';
|
|
56
|
+
@property({ reflect: true }) color: ChannelTileColor = 'default';
|
|
57
57
|
|
|
58
58
|
/** Primary line. Defaults to "Available" in the available state when unset. */
|
|
59
59
|
@property() title: string = '';
|
|
@@ -62,37 +62,37 @@ export default class ZnChannelTile extends ZincElement {
|
|
|
62
62
|
@property() subtitle: string = '';
|
|
63
63
|
|
|
64
64
|
/** (Active only) progress bar fill, 0–100. */
|
|
65
|
-
@property({type: Number}) progress: number = 0;
|
|
65
|
+
@property({ type: Number }) progress: number = 0;
|
|
66
66
|
|
|
67
67
|
/** (Active only) CSS color for the progress bar fill. */
|
|
68
|
-
@property({attribute: 'progress-color'}) progressColor: string = '';
|
|
68
|
+
@property({ attribute: 'progress-color' }) progressColor: string = '';
|
|
69
69
|
|
|
70
70
|
/** Identifier carried in `zn-accept` / `zn-reject` event details. */
|
|
71
|
-
@property({attribute: 'item-id'}) itemId: string = '';
|
|
71
|
+
@property({ attribute: 'item-id' }) itemId: string = '';
|
|
72
72
|
|
|
73
73
|
/** (Available only) when set, accepting fetches this URI unless `zn-accept` is canceled. */
|
|
74
|
-
@property({attribute: 'accept-uri'}) acceptUri: string = '';
|
|
74
|
+
@property({ attribute: 'accept-uri' }) acceptUri: string = '';
|
|
75
75
|
|
|
76
76
|
/** (Available/incoming) epoch (seconds or millis) at which the reservation window ends. */
|
|
77
|
-
@property({type: Number, attribute: 'reserved-until'}) reservedUntil: number = 0;
|
|
77
|
+
@property({ type: Number, attribute: 'reserved-until' }) reservedUntil: number = 0;
|
|
78
78
|
|
|
79
79
|
/** (Available/incoming) auto-accept window length in milliseconds. */
|
|
80
|
-
@property({type: Number, attribute: 'auto-accept-delay'}) autoAcceptDelay: number = 0;
|
|
80
|
+
@property({ type: Number, attribute: 'auto-accept-delay' }) autoAcceptDelay: number = 0;
|
|
81
81
|
|
|
82
82
|
/** (Available/incoming) whether a reject control is offered. */
|
|
83
|
-
@property({type: Boolean, reflect: true}) rejectable: boolean = false;
|
|
83
|
+
@property({ type: Boolean, reflect: true }) rejectable: boolean = false;
|
|
84
84
|
|
|
85
85
|
/** Icon for the built-in accept button. */
|
|
86
|
-
@property({attribute: 'accept-icon'}) acceptIcon: string = 'plus@lu';
|
|
86
|
+
@property({ attribute: 'accept-icon' }) acceptIcon: string = 'plus@lu';
|
|
87
87
|
|
|
88
88
|
/** Optional analytics id forwarded to the built-in accept button. */
|
|
89
|
-
@property({attribute: 'accept-gaid'}) acceptGaid: string = '';
|
|
89
|
+
@property({ attribute: 'accept-gaid' }) acceptGaid: string = '';
|
|
90
90
|
|
|
91
91
|
/** Icon for the reject control. */
|
|
92
|
-
@property({attribute: 'reject-icon'}) rejectIcon: string = '
|
|
92
|
+
@property({ attribute: 'reject-icon' }) rejectIcon: string = 'close';
|
|
93
93
|
|
|
94
94
|
/** Accessible label for the reject control. */
|
|
95
|
-
@property({attribute: 'reject-label'}) rejectLabel: string = 'Reject';
|
|
95
|
+
@property({ attribute: 'reject-label' }) rejectLabel: string = 'Reject';
|
|
96
96
|
|
|
97
97
|
private _tickInterval: number | undefined;
|
|
98
98
|
private _autoAcceptFired: string = '';
|
|
@@ -152,10 +152,10 @@ export default class ZnChannelTile extends ZincElement {
|
|
|
152
152
|
private _accept(): void {
|
|
153
153
|
const event = this.emit('zn-accept', {
|
|
154
154
|
cancelable: true,
|
|
155
|
-
detail: {itemId: this.itemId, acceptUri: this.acceptUri},
|
|
155
|
+
detail: { itemId: this.itemId, acceptUri: this.acceptUri },
|
|
156
156
|
});
|
|
157
157
|
if (event.defaultPrevented || !this.acceptUri) return;
|
|
158
|
-
fetch(this.acceptUri, {credentials: 'same-origin'}).catch((err) => {
|
|
158
|
+
fetch(this.acceptUri, { credentials: 'same-origin' }).catch((err) => {
|
|
159
159
|
console.error('Error accepting interaction', err);
|
|
160
160
|
});
|
|
161
161
|
}
|
|
@@ -186,7 +186,7 @@ export default class ZnChannelTile extends ZincElement {
|
|
|
186
186
|
private _handleReject = (e: MouseEvent) => {
|
|
187
187
|
e.preventDefault();
|
|
188
188
|
e.stopPropagation();
|
|
189
|
-
this.emit('zn-reject', {detail: {itemId: this.itemId, variant: this.variant}});
|
|
189
|
+
this.emit('zn-reject', { detail: { itemId: this.itemId, variant: this.variant } });
|
|
190
190
|
};
|
|
191
191
|
|
|
192
192
|
private _handleClick = (e: MouseEvent) => {
|
|
@@ -226,13 +226,19 @@ export default class ZnChannelTile extends ZincElement {
|
|
|
226
226
|
${remaining !== null
|
|
227
227
|
? this.title
|
|
228
228
|
? html`
|
|
229
|
-
<h3 class="channel-tile__title"
|
|
229
|
+
<h3 class="channel-tile__title">
|
|
230
|
+
<slot name="title">${this.title}</slot>
|
|
231
|
+
</h3>
|
|
230
232
|
<p class="channel-tile__subtitle">${this.subtitle} (${remaining}s)</p>`
|
|
231
233
|
: html`
|
|
232
234
|
<h3 class="channel-tile__title">${this.subtitle} (${remaining}s)</h3>`
|
|
233
235
|
: html`
|
|
234
|
-
<h3 class="channel-tile__title"
|
|
235
|
-
|
|
236
|
+
<h3 class="channel-tile__title">
|
|
237
|
+
<slot name="title">${title}</slot>
|
|
238
|
+
</h3>
|
|
239
|
+
<p class="channel-tile__subtitle">
|
|
240
|
+
<slot name="subtitle">${this.subtitle}</slot>
|
|
241
|
+
</p>`}
|
|
236
242
|
</div>
|
|
237
243
|
<slot name="footer" class="channel-tile__footer"></slot>
|
|
238
244
|
</div>
|
|
@@ -259,6 +265,9 @@ export default class ZnChannelTile extends ZincElement {
|
|
|
259
265
|
icon-size="20"
|
|
260
266
|
icon-button="round"
|
|
261
267
|
color=${this.color}
|
|
268
|
+
class="${classMap({
|
|
269
|
+
[`channel-tile--${this.color}`]: true,
|
|
270
|
+
})}"
|
|
262
271
|
no-hover></zn-button>`
|
|
263
272
|
: ''}
|
|
264
273
|
</slot>`;
|
|
@@ -145,13 +145,14 @@
|
|
|
145
145
|
border: none;
|
|
146
146
|
padding: 0;
|
|
147
147
|
margin: 0;
|
|
148
|
-
background-color:
|
|
148
|
+
background-color: rgba(var(--zn-color-panel));
|
|
149
149
|
color: rgb(var(--zn-color-error));
|
|
150
150
|
cursor: pointer;
|
|
151
151
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
|
152
152
|
|
|
153
153
|
&:hover {
|
|
154
|
-
background-color: rgba(var(--zn-color-error)
|
|
154
|
+
background-color: rgba(var(--zn-color-error));
|
|
155
|
+
color: rgb(var(--zn-color-panel));
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
|
|
@@ -195,3 +196,7 @@
|
|
|
195
196
|
.channel-tile--disabled {
|
|
196
197
|
--channel-tile-color: var(--zn-color-disabled, 204, 204, 204);
|
|
197
198
|
}
|
|
199
|
+
|
|
200
|
+
.channel-tile--incoming .channel-tile__body zn-button {
|
|
201
|
+
--zn-color-tab: var(--zn-color-panel);
|
|
202
|
+
}
|
|
@@ -10,6 +10,7 @@ import {unsafeHTML} from "lit/directives/unsafe-html.js";
|
|
|
10
10
|
import {type ZnFilterChangeEvent} from "../../events/zn-filter-change";
|
|
11
11
|
import {type ZnSearchChangeEvent} from "../../events/zn-search-change";
|
|
12
12
|
import ZincElement from '../../internal/zinc-element';
|
|
13
|
+
import ZnAlert from "../alert";
|
|
13
14
|
import ZnButton from "../button";
|
|
14
15
|
import ZnButtonGroup from "../button-group";
|
|
15
16
|
import ZnChip from "../chip";
|
|
@@ -60,11 +61,18 @@ interface Row {
|
|
|
60
61
|
cells: Cell[];
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
interface ResponseError {
|
|
65
|
+
text: string;
|
|
66
|
+
icon?: string;
|
|
67
|
+
level?: 'primary' | 'error' | 'info' | 'success' | 'warning' | 'note';
|
|
68
|
+
}
|
|
69
|
+
|
|
63
70
|
interface Response {
|
|
64
71
|
rows: Row[];
|
|
65
72
|
perPage: number;
|
|
66
73
|
total: number;
|
|
67
74
|
page: number;
|
|
75
|
+
error?: ResponseError;
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
export enum ActionSlots {
|
|
@@ -147,6 +155,7 @@ type AllowedInputElement =
|
|
|
147
155
|
* @status experimental
|
|
148
156
|
* @since 1.0
|
|
149
157
|
*
|
|
158
|
+
* @dependency zn-alert
|
|
150
159
|
* @dependency zn-button
|
|
151
160
|
* @dependency zn-empty-state
|
|
152
161
|
* @dependency zn-chip
|
|
@@ -177,6 +186,7 @@ type AllowedInputElement =
|
|
|
177
186
|
export default class ZnDataTable extends ZincElement {
|
|
178
187
|
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
179
188
|
static dependencies = {
|
|
189
|
+
'zn-alert': ZnAlert,
|
|
180
190
|
'zn-button': ZnButton,
|
|
181
191
|
'zn-empty-state': ZnEmptyState,
|
|
182
192
|
'zn-chip': ZnChip,
|
|
@@ -503,12 +513,15 @@ export default class ZnDataTable extends ZincElement {
|
|
|
503
513
|
}
|
|
504
514
|
|
|
505
515
|
renderTable(data: Response) {
|
|
506
|
-
this.itemsPerPage = Math.max(
|
|
516
|
+
this.itemsPerPage = Math.max(DEFAULT_PER_PAGE, data.perPage ?? DEFAULT_PER_PAGE);
|
|
507
517
|
this.page = Math.max(1, data.page ?? DEFAULT_PAGE);
|
|
508
518
|
this.totalPages = Math.ceil(Math.max(1, data.total) / this.itemsPerPage);
|
|
509
519
|
|
|
520
|
+
const error = data?.error?.text ? data.error : undefined;
|
|
521
|
+
|
|
510
522
|
if (!data?.rows || data.rows.length === 0) {
|
|
511
|
-
return
|
|
523
|
+
return html`${error ? html`
|
|
524
|
+
<div class="table__error">${this.renderErrorAlert(error)}</div>` : nothing}${this.emptyState()}`;
|
|
512
525
|
}
|
|
513
526
|
|
|
514
527
|
this._rows = this.getRows(data);
|
|
@@ -573,10 +586,10 @@ export default class ZnDataTable extends ZincElement {
|
|
|
573
586
|
// render a table for each group
|
|
574
587
|
return html`
|
|
575
588
|
<zn-sp flush>
|
|
576
|
-
${Object.keys(groupedRows).map((groupKey) => html`
|
|
589
|
+
${Object.keys(groupedRows).map((groupKey, index) => html`
|
|
577
590
|
<div class="table-group">
|
|
578
591
|
<h3 class="table-group__title">${(groupKey === "Ungrouped" || groupKey === "*") ? "" : groupKey}</h3>
|
|
579
|
-
${this.renderTableData(groupedRows[groupKey])}
|
|
592
|
+
${this.renderTableData(groupedRows[groupKey], index === 0 ? error : undefined)}
|
|
580
593
|
</div>`
|
|
581
594
|
)}
|
|
582
595
|
</zn-sp>
|
|
@@ -584,14 +597,22 @@ export default class ZnDataTable extends ZincElement {
|
|
|
584
597
|
}
|
|
585
598
|
|
|
586
599
|
|
|
587
|
-
return this.renderTableData(this._rows);
|
|
600
|
+
return this.renderTableData(this._rows, error);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
private renderErrorAlert(error: ResponseError) {
|
|
604
|
+
return html`
|
|
605
|
+
<zn-alert level="${error.level ?? 'error'}"
|
|
606
|
+
icon="${ifDefined(error.icon)}"
|
|
607
|
+
size="small"
|
|
608
|
+
center>${error.text}</zn-alert>`;
|
|
588
609
|
}
|
|
589
610
|
|
|
590
611
|
public humanize(str: string) {
|
|
591
612
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
592
613
|
}
|
|
593
614
|
|
|
594
|
-
public renderTableData(data: any) {
|
|
615
|
+
public renderTableData(data: any, error?: ResponseError) {
|
|
595
616
|
// Primary (visible) headers exclude those explicitly hidden and those marked as secondary
|
|
596
617
|
const filteredHeaders = Object.values(this.headers).filter((header: HeaderConfig) => {
|
|
597
618
|
if (header.hideHeader || header.hideColumn) return false;
|
|
@@ -656,6 +677,10 @@ export default class ZnDataTable extends ZincElement {
|
|
|
656
677
|
</tr>
|
|
657
678
|
</thead>
|
|
658
679
|
<tbody>
|
|
680
|
+
${error ? html`
|
|
681
|
+
<tr class="table__row--error">
|
|
682
|
+
<td colspan="${colCount}">${this.renderErrorAlert(error)}</td>
|
|
683
|
+
</tr>` : nothing}
|
|
659
684
|
${(data as Row[]).map((row: Row) => html`
|
|
660
685
|
<tr class="${classMap({
|
|
661
686
|
'table__row--selected': this.isRowSelected(row),
|
|
@@ -924,7 +949,7 @@ export default class ZnDataTable extends ZincElement {
|
|
|
924
949
|
return;
|
|
925
950
|
}
|
|
926
951
|
|
|
927
|
-
const rows = Array.from(this.renderRoot.querySelectorAll('tbody tr
|
|
952
|
+
const rows = Array.from(this.renderRoot.querySelectorAll('tbody tr.table__row--data'));
|
|
928
953
|
const index = rows.indexOf(parent as HTMLTableRowElement);
|
|
929
954
|
if (index === -1) return;
|
|
930
955
|
|
|
@@ -422,6 +422,14 @@ table:has(tbody tr:first-of-type.table__row--selected) thead tr th {
|
|
|
422
422
|
text-overflow: ellipsis;
|
|
423
423
|
}
|
|
424
424
|
|
|
425
|
+
tbody tr.table__row--error td {
|
|
426
|
+
padding-block: var(--zn-spacing-x-small);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.table__error {
|
|
430
|
+
padding-bottom: var(--zn-spacing-small);
|
|
431
|
+
}
|
|
432
|
+
|
|
425
433
|
.table__collum--datetime{
|
|
426
434
|
display:flex;
|
|
427
435
|
flex-direction:column;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import '../../../dist/zn.min.js';
|
|
2
|
-
import { expect, fixture, html } from '@open-wc/testing';
|
|
2
|
+
import { expect, fixture, html, waitUntil } from '@open-wc/testing';
|
|
3
3
|
import type ZnDataTable from './data-table.component';
|
|
4
4
|
|
|
5
5
|
describe('<zn-data-table>', () => {
|
|
@@ -24,6 +24,31 @@ describe('<zn-data-table>', () => {
|
|
|
24
24
|
expect(() => (el as unknown as {requestUpdate: () => void}).requestUpdate()).not.to.throw();
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
+
it('renders an error alert from the fetch response alongside the table content', async () => {
|
|
28
|
+
const originalFetch = window.fetch;
|
|
29
|
+
window.fetch = () => Promise.resolve(new Response(JSON.stringify({
|
|
30
|
+
rows: [{id: '1', cells: [{text: 'Row 1', column: 'name'}]}],
|
|
31
|
+
page: 1,
|
|
32
|
+
perPage: 10,
|
|
33
|
+
total: 1,
|
|
34
|
+
error: {text: 'Results limited to 10 rows, please filter for more accuracy', level: 'warning'},
|
|
35
|
+
}), {status: 200, headers: {'Content-Type': 'application/json'}}));
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const el = await fixture<ZnDataTable>(html`
|
|
39
|
+
<zn-data-table data-uri="/test-data" headers='{"name": {"key": "name", "label": "Name"}}'></zn-data-table>`);
|
|
40
|
+
await waitUntil(() => el.shadowRoot?.querySelector('zn-alert'));
|
|
41
|
+
|
|
42
|
+
const alert = el.shadowRoot!.querySelector('tbody tr:first-child zn-alert')!;
|
|
43
|
+
expect(alert).to.exist;
|
|
44
|
+
expect(alert.textContent).to.contain('limited to 10 rows');
|
|
45
|
+
expect(alert.getAttribute('level')).to.equal('warning');
|
|
46
|
+
expect(el.shadowRoot!.querySelector('tbody tr.table__row--data')).to.exist;
|
|
47
|
+
} finally {
|
|
48
|
+
window.fetch = originalFetch;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
27
52
|
it('exposes displayTemplates as an object property', async () => {
|
|
28
53
|
const el = await fixture<ZnDataTable>(html` <zn-data-table></zn-data-table> `);
|
|
29
54
|
const templates = (el as unknown as {displayTemplates: Record<string, unknown>}).displayTemplates;
|