@kubex/zinc 1.1.121 → 1.1.122
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/custom-elements.json +3110 -2079
- package/dist/vscode.html-custom-data.json +200 -178
- package/dist/web-types.json +528 -462
- package/dist/zn.d.ts +401 -296
- package/dist/zn.min.js +1478 -1337
- package/docs/pages/components/button.md +9 -0
- package/docs/pages/components/data-table-filter.md +60 -4
- package/docs/pages/components/data-table-search.md +3 -3
- package/docs/pages/components/data-table.md +78 -9
- package/docs/pages/components/datepicker.md +10 -0
- package/docs/pages/components/menu-item.md +16 -2
- package/package.json +1 -1
- package/src/components/button/button.component.ts +11 -4
- package/src/components/button/button.scss +12 -1
- package/src/components/data-table/data-table.component.ts +341 -139
- package/src/components/data-table/data-table.scss +105 -42
- package/src/components/data-table/data-table.test.ts +110 -0
- package/src/components/data-table-filter/data-table-filter.component.ts +487 -49
- package/src/components/data-table-filter/data-table-filter.scss +163 -9
- package/src/components/data-table-filter/data-table-filter.test.ts +328 -2
- package/src/components/data-table-search/data-table-search.component.ts +1 -1
- package/src/components/datepicker/datepicker.component.ts +23 -2
- package/src/components/datepicker/datepicker.scss +25 -0
- package/src/components/datepicker/datepicker.test.ts +28 -1
- package/src/components/input/input.component.ts +1 -0
- package/src/components/input/input.scss +1 -1
- package/src/components/menu/menu.component.ts +2 -0
- package/src/components/menu/menu.scss +23 -2
- package/src/components/menu-item/menu-item.component.ts +7 -1
- package/src/components/menu-item/menu-item.scss +4 -4
- package/src/components/menu-item/menu-item.test.ts +39 -1
- package/src/components/panel/panel.component.ts +12 -5
- package/src/components/panel/panel.scss +3 -3
- package/src/components/query-builder/query-builder.component.ts +1 -1
- package/src/components/tooltip/tooltip.component.ts +2 -2
- package/src/components/tooltip/tooltip.test.ts +70 -2
|
@@ -5,8 +5,14 @@
|
|
|
5
5
|
@include wc.scrollbars;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// Separates a top-level filter bar from the table's own panel below it
|
|
9
|
+
slot[name="filter-top"]::slotted(*) {
|
|
10
|
+
margin-bottom: var(--zn-spacing-small);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.table__scroll {
|
|
14
|
+
overflow-x: auto;
|
|
15
|
+
@include wc.scrollbars;
|
|
10
16
|
}
|
|
11
17
|
|
|
12
18
|
table {
|
|
@@ -28,17 +34,6 @@ table {
|
|
|
28
34
|
background-color: rgb(var(--zn-shadow));
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
&.table--standalone {
|
|
32
|
-
background-color: rgb(var(--zn-panel));
|
|
33
|
-
border-radius: var(--zn-border-radius);
|
|
34
|
-
border: 1px solid rgb(var(--zn-border-color));
|
|
35
|
-
overflow: hidden;
|
|
36
|
-
|
|
37
|
-
thead tr th {
|
|
38
|
-
border-top: 0;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
37
|
thead {
|
|
43
38
|
color: rgb(var(--zn-text-heading));
|
|
44
39
|
font-weight: var(--zn-font-weight-medium);
|
|
@@ -232,18 +227,31 @@ table {
|
|
|
232
227
|
display: flex;
|
|
233
228
|
flex-direction: row;
|
|
234
229
|
justify-content: space-between;
|
|
235
|
-
align-items:
|
|
236
|
-
padding
|
|
230
|
+
align-items: center;
|
|
231
|
+
padding: var(--zn-spacing-x-small) var(--zn-spacing-medium);
|
|
237
232
|
gap: var(--zn-spacing-small);
|
|
238
233
|
|
|
239
234
|
&__actions,
|
|
240
235
|
&__query-builder {
|
|
241
236
|
display: flex;
|
|
242
237
|
flex-direction: row;
|
|
243
|
-
align-items:
|
|
238
|
+
align-items: center;
|
|
244
239
|
gap: var(--zn-spacing-small);
|
|
245
240
|
}
|
|
246
241
|
|
|
242
|
+
&__toggle--active::part(base) {
|
|
243
|
+
background-color: rgb(var(--zn-color-tab));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
&__caption {
|
|
247
|
+
@include wc.text-style(h1);
|
|
248
|
+
|
|
249
|
+
margin: 0;
|
|
250
|
+
overflow: hidden;
|
|
251
|
+
white-space: nowrap;
|
|
252
|
+
text-overflow: ellipsis;
|
|
253
|
+
}
|
|
254
|
+
|
|
247
255
|
&__right {
|
|
248
256
|
display: flex;
|
|
249
257
|
flex-direction: row;
|
|
@@ -253,11 +261,31 @@ table {
|
|
|
253
261
|
}
|
|
254
262
|
}
|
|
255
263
|
|
|
264
|
+
&__filters {
|
|
265
|
+
padding: var(--zn-spacing-x-small) var(--zn-spacing-medium);
|
|
266
|
+
|
|
267
|
+
&[hidden] {
|
|
268
|
+
display: none;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
256
272
|
&__footer {
|
|
257
273
|
display: flex;
|
|
258
274
|
flex-direction: row;
|
|
259
275
|
justify-content: space-between;
|
|
260
|
-
|
|
276
|
+
flex-wrap: wrap;
|
|
277
|
+
gap: var(--zn-spacing-small);
|
|
278
|
+
padding: var(--zn-spacing-x-small) var(--zn-spacing-medium);
|
|
279
|
+
|
|
280
|
+
// The joined control must never break across lines
|
|
281
|
+
zn-button-group::part(base) {
|
|
282
|
+
flex-wrap: nowrap;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// zn-panel's footer supplies its own padding
|
|
286
|
+
&--panel {
|
|
287
|
+
padding: 0;
|
|
288
|
+
}
|
|
261
289
|
|
|
262
290
|
&__right, &__left {
|
|
263
291
|
display: flex;
|
|
@@ -270,40 +298,49 @@ table {
|
|
|
270
298
|
display: flex;
|
|
271
299
|
flex-direction: row;
|
|
272
300
|
align-items: center;
|
|
273
|
-
opacity: 0.8;
|
|
274
301
|
gap: var(--zn-spacing-x-small);
|
|
275
302
|
|
|
303
|
+
p {
|
|
304
|
+
margin: 0;
|
|
305
|
+
color: rgb(var(--zn-text));
|
|
306
|
+
opacity: 0.7;
|
|
307
|
+
white-space: nowrap;
|
|
308
|
+
}
|
|
309
|
+
|
|
276
310
|
zn-select[name="rowPerPage"] {
|
|
277
|
-
|
|
311
|
+
--zn-input-background-color: rgb(var(--zn-panel));
|
|
312
|
+
|
|
313
|
+
width: 66px;
|
|
278
314
|
}
|
|
279
315
|
|
|
316
|
+
// Matches the height of the pagination control it sits beside
|
|
280
317
|
zn-select[name="rowPerPage"]::part(combobox) {
|
|
281
|
-
|
|
318
|
+
min-height: 36px;
|
|
319
|
+
padding-inline: var(--zn-spacing-x-small);
|
|
282
320
|
}
|
|
283
321
|
|
|
284
|
-
|
|
322
|
+
zn-select[name="rowPerPage"]::part(expand-icon) {
|
|
285
323
|
margin-inline-start: 0;
|
|
286
324
|
}
|
|
287
325
|
}
|
|
288
326
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
327
|
+
// Sized to match the icon-button arrows it is joined to, but free to grow for large page numbers
|
|
328
|
+
&__pagination-page::part(base) {
|
|
329
|
+
height: 36px;
|
|
330
|
+
min-height: 36px;
|
|
331
|
+
max-height: 36px;
|
|
332
|
+
min-width: 32px;
|
|
333
|
+
padding: 0 var(--zn-spacing-2x-small);
|
|
334
|
+
justify-content: center;
|
|
335
|
+
border-color: rgb(var(--zn-border-color));
|
|
336
|
+
color: rgb(var(--zn-text));
|
|
337
|
+
font-weight: var(--zn-font-weight-normal);
|
|
338
|
+
white-space: nowrap;
|
|
294
339
|
}
|
|
295
340
|
|
|
296
341
|
&__pagination-page--active::part(base) {
|
|
297
342
|
background-color: var(--zn-color-neutral-300);
|
|
298
343
|
border-color: var(--zn-color-neutral-300);
|
|
299
|
-
color: rgb(var(--zn-text));
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
&__pagination-ellipsis {
|
|
303
|
-
display: flex;
|
|
304
|
-
align-items: center;
|
|
305
|
-
padding: 0 var(--zn-spacing-x-small);
|
|
306
|
-
color: rgb(var(--zn-text));
|
|
307
344
|
}
|
|
308
345
|
}
|
|
309
346
|
|
|
@@ -330,6 +367,30 @@ table {
|
|
|
330
367
|
}
|
|
331
368
|
}
|
|
332
369
|
|
|
370
|
+
zn-menu {
|
|
371
|
+
--zn-menu-min-width: var(--zn-size-spanel);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// A table's header and footer are chrome around the rows, so they sit tighter than
|
|
375
|
+
// the panel's own content padding. The header's trailing edge tucks in further still,
|
|
376
|
+
// since the controls there are already inset by their own button padding.
|
|
377
|
+
zn-panel {
|
|
378
|
+
--zn-panel-header-padding: var(--zn-spacing-x-small) var(--zn-spacing-x-small)
|
|
379
|
+
var(--zn-spacing-x-small) var(--zn-spacing-medium);
|
|
380
|
+
--zn-panel-footer-padding: var(--zn-spacing-x-small) var(--zn-spacing-medium);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Closes the rows off from the footer, which the panel border would otherwise do
|
|
384
|
+
zn-panel::part(footer) {
|
|
385
|
+
border-top: 1px solid rgb(var(--zn-border-color));
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Dropdowns sit over dense rows here, so they need a solid surface rather than
|
|
389
|
+
// zn-menu's translucent default
|
|
390
|
+
zn-menu::part(base) {
|
|
391
|
+
background-color: rgb(var(--zn-panel));
|
|
392
|
+
}
|
|
393
|
+
|
|
333
394
|
.reduced-opacity .table tbody {
|
|
334
395
|
opacity: 0.5;
|
|
335
396
|
}
|
|
@@ -417,16 +478,18 @@ table:has(tbody tr:first-of-type.table__row--selected) thead tr th {
|
|
|
417
478
|
border-bottom-color: var(--zn-color-purple-600) !important;
|
|
418
479
|
}
|
|
419
480
|
|
|
420
|
-
.
|
|
481
|
+
tbody tr.table__row--group th {
|
|
482
|
+
padding: var(--zn-spacing-small) var(--zn-spacing-medium);
|
|
483
|
+
text-align: left;
|
|
484
|
+
white-space: nowrap;
|
|
485
|
+
background-color: rgb(var(--zn-panel));
|
|
486
|
+
color: rgba(var(--zn-text-panel-title), 100%);
|
|
421
487
|
font-weight: var(--zn-font-weight-semibold);
|
|
422
488
|
font-size: var(--zn-font-size-large);
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
overflow: hidden;
|
|
428
|
-
white-space: nowrap;
|
|
429
|
-
text-overflow: ellipsis;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
tbody tr.table__row--group:not(:first-of-type) th {
|
|
492
|
+
border-top: 1px solid rgb(var(--zn-border-color));
|
|
430
493
|
}
|
|
431
494
|
|
|
432
495
|
tbody tr.table__row--error td {
|
|
@@ -10,6 +10,116 @@ describe('<zn-data-table>', () => {
|
|
|
10
10
|
expect(el).to.exist;
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
+
// filter-top renders above the panel, so it must not bring an otherwise empty header row with it
|
|
14
|
+
it('renders no header when only filter-top is slotted', async () => {
|
|
15
|
+
const el = await fixture<ZnDataTable>(html`
|
|
16
|
+
<zn-data-table standalone no-initial-load>
|
|
17
|
+
<div slot="filter-top">Filters</div>
|
|
18
|
+
<div slot="empty-state">Nothing yet</div>
|
|
19
|
+
</zn-data-table>`);
|
|
20
|
+
await el.updateComplete;
|
|
21
|
+
|
|
22
|
+
expect(el.shadowRoot!.querySelector('.table__header__right')).to.not.exist;
|
|
23
|
+
expect(el.shadowRoot!.querySelector('zn-header')).to.not.exist;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('leaves a bare empty state unwrapped by the standalone panel', async () => {
|
|
27
|
+
const el = await fixture<ZnDataTable>(html`
|
|
28
|
+
<zn-data-table standalone no-initial-load>
|
|
29
|
+
<div slot="empty-state">Nothing yet</div>
|
|
30
|
+
</zn-data-table>`);
|
|
31
|
+
await el.updateComplete;
|
|
32
|
+
|
|
33
|
+
expect(el.shadowRoot!.querySelector('zn-panel')).to.not.exist;
|
|
34
|
+
expect(el.shadowRoot!.querySelector('slot[name="empty-state"]')).to.exist;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('keeps the standalone panel for an empty state that has a caption', async () => {
|
|
38
|
+
const el = await fixture<ZnDataTable>(html`
|
|
39
|
+
<zn-data-table standalone no-initial-load caption="Customers">
|
|
40
|
+
<div slot="empty-state">Nothing yet</div>
|
|
41
|
+
</zn-data-table>`);
|
|
42
|
+
await el.updateComplete;
|
|
43
|
+
|
|
44
|
+
expect(el.shadowRoot!.querySelector('zn-panel')).to.exist;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Raising the page size past the total used to drop the whole footer, leaving no way back
|
|
48
|
+
it('keeps the rows-per-page selector when the page size covers every row', async () => {
|
|
49
|
+
const originalFetch = window.fetch;
|
|
50
|
+
window.fetch = () => Promise.resolve(new Response(JSON.stringify({
|
|
51
|
+
rows: Array.from({length: 24}, (_, i) => ({id: String(i), cells: [{text: 'Row', column: 'name'}]})),
|
|
52
|
+
page: 1,
|
|
53
|
+
perPage: 50,
|
|
54
|
+
total: 24,
|
|
55
|
+
}), {status: 200, headers: {'Content-Type': 'application/json'}}));
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const el = await fixture<ZnDataTable>(html`
|
|
59
|
+
<zn-data-table data-uri="/test-data" headers='{"name": {"key": "name", "label": "Name"}}'></zn-data-table>`);
|
|
60
|
+
await waitUntil(() => el.shadowRoot!.querySelector('tbody tr.table__row--data'));
|
|
61
|
+
|
|
62
|
+
expect(el.shadowRoot!.querySelector('zn-select[name="rowPerPage"]')).to.exist;
|
|
63
|
+
expect(el.shadowRoot!.querySelector('.table__footer__pagination-page')).to.not.exist;
|
|
64
|
+
} finally {
|
|
65
|
+
window.fetch = originalFetch;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('hides the rows-per-page selector when the dataset fits the smallest page size', async () => {
|
|
70
|
+
const originalFetch = window.fetch;
|
|
71
|
+
window.fetch = () => Promise.resolve(new Response(JSON.stringify({
|
|
72
|
+
rows: [{id: '1', cells: [{text: 'Row', column: 'name'}]}],
|
|
73
|
+
page: 1,
|
|
74
|
+
perPage: 10,
|
|
75
|
+
total: 1,
|
|
76
|
+
}), {status: 200, headers: {'Content-Type': 'application/json'}}));
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const el = await fixture<ZnDataTable>(html`
|
|
80
|
+
<zn-data-table data-uri="/test-data" headers='{"name": {"key": "name", "label": "Name"}}'></zn-data-table>`);
|
|
81
|
+
await waitUntil(() => el.shadowRoot!.querySelector('tbody tr.table__row--data'));
|
|
82
|
+
|
|
83
|
+
expect(el.shadowRoot!.querySelector('zn-select[name="rowPerPage"]')).to.not.exist;
|
|
84
|
+
expect(el.shadowRoot!.querySelector('.table__footer')).to.not.exist;
|
|
85
|
+
} finally {
|
|
86
|
+
window.fetch = originalFetch;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// One table per group meant two scrollbars and columns that did not line up between groups
|
|
91
|
+
it('renders grouped rows as group header rows inside a single table', async () => {
|
|
92
|
+
const originalFetch = window.fetch;
|
|
93
|
+
const row = (id: string, status: string) => ({
|
|
94
|
+
id,
|
|
95
|
+
cells: [{text: 'Card ' + id, column: 'name'}, {text: status, column: 'status'}],
|
|
96
|
+
});
|
|
97
|
+
window.fetch = () => Promise.resolve(new Response(JSON.stringify({
|
|
98
|
+
rows: [row('1', 'active'), row('2', 'active'), row('3', 'archived')],
|
|
99
|
+
page: 1,
|
|
100
|
+
perPage: 10,
|
|
101
|
+
total: 3,
|
|
102
|
+
}), {status: 200, headers: {'Content-Type': 'application/json'}}));
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const el = await fixture<ZnDataTable>(html`
|
|
106
|
+
<zn-data-table data-uri="/test-data"
|
|
107
|
+
group-by="status"
|
|
108
|
+
groups="active,archived"
|
|
109
|
+
headers='{"name": {"key": "name", "label": "Name"}, "status": {"key": "status", "label": "Status", "hideColumn": true}}'></zn-data-table>`);
|
|
110
|
+
await waitUntil(() => el.shadowRoot!.querySelector('tbody tr.table__row--data'));
|
|
111
|
+
|
|
112
|
+
const root = el.shadowRoot!;
|
|
113
|
+
expect(root.querySelectorAll('table')).to.have.length(1);
|
|
114
|
+
expect(root.querySelectorAll('.table__scroll')).to.have.length(1);
|
|
115
|
+
expect([...root.querySelectorAll('tr.table__row--group')].map(r => r.textContent!.trim()))
|
|
116
|
+
.to.deep.equal(['Active', 'Archived']);
|
|
117
|
+
expect(root.querySelectorAll('tbody tr.table__row--data')).to.have.length(3);
|
|
118
|
+
} finally {
|
|
119
|
+
window.fetch = originalFetch;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
13
123
|
it('does not throw when updating selection without a select-all button', async () => {
|
|
14
124
|
const el = await fixture<ZnDataTable>(html` <zn-data-table></zn-data-table> `);
|
|
15
125
|
|