@functionalcms/svelte-components 3.5.0 → 3.5.2
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/components/Spacer.svelte +17 -16
- package/dist/components/Spacer.svelte.d.ts +1 -5
- package/dist/components/agnostic/Disclose/Disclose.svelte +111 -103
- package/dist/components/agnostic/Disclose/Disclose.svelte.d.ts +2 -9
- package/dist/components/agnostic/Table/Table.svelte +518 -562
- package/package.json +1 -1
|
@@ -1,565 +1,521 @@
|
|
|
1
|
-
<style>
|
|
2
|
-
.table {
|
|
3
|
-
--table-bg: transparent;
|
|
4
|
-
--table-accent-bg: transparent;
|
|
5
|
-
--table-striped-color: var(--functional-dark);
|
|
6
|
-
--table-striped-bg: rgb(0 0 0 / 2.5%);
|
|
7
|
-
--table-active-color: var(--functional-dark);
|
|
8
|
-
--table-active-bg: rgb(0 0 0 / 1.5%);
|
|
9
|
-
--table-hoverable-color: var(--functional-dark);
|
|
10
|
-
--table-hoverable-bg: var(--functional-table-hover-bg, #f1faff);
|
|
11
|
-
|
|
12
|
-
width: 100%;
|
|
13
|
-
margin-bottom: var(--fluid-16);
|
|
14
|
-
color: var(--functional-dark);
|
|
15
|
-
vertical-align: top;
|
|
16
|
-
border-color: var(--functional-table-border-color, var(--functional-gray-light));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.table > :not(caption) > * > * {
|
|
20
|
-
padding: var(--fluid-8) var(--fluid-8);
|
|
21
|
-
background-color: var(--table-bg);
|
|
22
|
-
border-bottom-width: 1px;
|
|
23
|
-
|
|
24
|
-
/* 4th is spread --table-accent-bg will gets reset for active, hover, striped */
|
|
25
|
-
box-shadow: inset 0 0 0 9999px var(--table-accent-bg);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.table > tbody {
|
|
29
|
-
vertical-align: inherit;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.table > thead {
|
|
33
|
-
vertical-align: bottom;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.table thead th {
|
|
37
|
-
font-weight: 600;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.table-caps thead th {
|
|
41
|
-
font-size: var(--fluid-12);
|
|
42
|
-
text-transform: uppercase;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.table tbody td,
|
|
46
|
-
.table tbody th {
|
|
47
|
-
font-weight: 400;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.table > :not(thead):not(caption) {
|
|
51
|
-
border-top: var(--fluid-2) solid var(--functional-gray-light);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.caption-top {
|
|
55
|
-
caption-side: top;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.caption-bottom {
|
|
59
|
-
caption-side: bottom;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.caption-bottom,
|
|
63
|
-
.caption-top {
|
|
64
|
-
padding-block-start: var(--fluid-12);
|
|
65
|
-
padding-block-end: var(--fluid-12);
|
|
66
|
-
|
|
67
|
-
/* Takes writing mode into account -- (mdn) same as left if direction is left-to-right
|
|
68
|
-
and right if direction is right-to-left */
|
|
69
|
-
text-align: start;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.caption-end {
|
|
73
|
-
text-align: end;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.table-small > :not(caption) > * > * {
|
|
77
|
-
padding: var(--fluid-4) var(--fluid-4);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.table-large > :not(caption) > * > * {
|
|
81
|
-
padding: var(--fluid-12) var(--fluid-12);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.table-xlarge > :not(caption) > * > * {
|
|
85
|
-
padding: var(--fluid-18) var(--fluid-18);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.table-bordered > :not(caption) > * {
|
|
89
|
-
border-width: 1px 0;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.table-bordered > :not(caption) > * > * {
|
|
93
|
-
border-width: 0 1px;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.table-borderless > :not(caption) > * > * {
|
|
97
|
-
border-bottom-width: 0;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
.table-borderless > :not(:first-child) {
|
|
101
|
-
border-top-width: 0;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
.table-striped > tbody > tr:nth-of-type(odd) > * {
|
|
105
|
-
--table-accent-bg: var(--table-striped-bg);
|
|
106
|
-
|
|
107
|
-
color: var(--table-striped-color);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.table-active {
|
|
111
|
-
--table-accent-bg: var(--table-active-bg);
|
|
112
|
-
|
|
113
|
-
color: var(--table-active-color);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.table-hoverable > tbody > tr:hover > * {
|
|
117
|
-
--table-accent-bg: var(--table-hoverable-bg);
|
|
118
|
-
|
|
119
|
-
color: var(--table-hoverable-color);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/* Stacked tables */
|
|
123
|
-
.table-stacked thead {
|
|
124
|
-
display: none;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
.table-stacked tr,
|
|
128
|
-
.table-stacked tbody th,
|
|
129
|
-
.table-stacked tbody td {
|
|
130
|
-
display: block;
|
|
131
|
-
width: 100%;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
.table-stacked tbody th,
|
|
135
|
-
.table-stacked tbody td {
|
|
136
|
-
border-bottom-width: 0;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
.table-stacked td[data-label] {
|
|
140
|
-
padding-bottom: var(--fluid-12);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
.table-stacked tr {
|
|
144
|
-
border-bottom: var(--fluid-2) solid var(--functional-gray-light);
|
|
145
|
-
border-top-width: 0;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
.table-stacked th[data-label]::before,
|
|
149
|
-
.table-stacked td[data-label]::before {
|
|
150
|
-
content: attr(data-label);
|
|
151
|
-
display: block;
|
|
152
|
-
font-weight: 600;
|
|
153
|
-
margin: -0.5rem -1rem 0;
|
|
154
|
-
padding: var(--fluid-12) var(--fluid-16) var(--fluid-6);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
.table-stacked tr th:first-child,
|
|
158
|
-
.table-stacked tr td:first-child {
|
|
159
|
-
border-top-width: 0;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
.table-stacked tr:nth-child(odd) td,
|
|
163
|
-
.table-stacked tr:nth-child(odd) th {
|
|
164
|
-
background-color: inherit;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
.table-stacked tr:first-child th:first-child,
|
|
168
|
-
.table-stacked tr:first-child td:first-child {
|
|
169
|
-
border-top: var(--fluid-2) solid var(--functional-gray-light);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
.table-stacked th[data-label],
|
|
173
|
-
.table-stacked td[data-label] {
|
|
174
|
-
padding-bottom: var(--fluid-12);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/* As soon as there's not enough width, it will kick in horizontal scrolling */
|
|
178
|
-
.table-responsive {
|
|
179
|
-
overflow-x: auto;
|
|
180
|
-
-webkit-overflow-scrolling: touch;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/* Table is responsive only "up to" the breakpoint. Above it will not scroll */
|
|
184
|
-
@media (max-width: 576px) {
|
|
185
|
-
.table-responsive-small {
|
|
186
|
-
overflow-x: auto;
|
|
187
|
-
-webkit-overflow-scrolling: touch;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
@media (max-width: 768px) {
|
|
192
|
-
.table-responsive-medium {
|
|
193
|
-
overflow-x: auto;
|
|
194
|
-
-webkit-overflow-scrolling: touch;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
@media (max-width: 992px) {
|
|
199
|
-
.table-responsive-large {
|
|
200
|
-
overflow-x: auto;
|
|
201
|
-
-webkit-overflow-scrolling: touch;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
@media (max-width: 1200px) {
|
|
206
|
-
.table-responsive-xlarge {
|
|
207
|
-
overflow-x: auto;
|
|
208
|
-
-webkit-overflow-scrolling: touch;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.table-header-container {
|
|
213
|
-
display: flex;
|
|
214
|
-
align-items: center;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
.table-sort-label {
|
|
218
|
-
flex: 1;
|
|
219
|
-
padding-inline-end: 0.5rem;
|
|
220
|
-
text-align: left;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
.table-sort {
|
|
224
|
-
flex: 0 1 var(--fluid-48);
|
|
225
|
-
background-color: transparent;
|
|
226
|
-
border-color: transparent;
|
|
227
|
-
border-width: 0;
|
|
228
|
-
cursor: pointer;
|
|
229
|
-
display: flex;
|
|
230
|
-
justify-content: center;
|
|
231
|
-
padding-block-start: var(--fluid-2);
|
|
232
|
-
padding-block-end: var(--fluid-2);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
.icon-sort {
|
|
236
|
-
width: 1.125rem;
|
|
237
|
-
height: 1.125rem;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
.table-sort:focus {
|
|
241
|
-
box-shadow: 0 0 0 var(--functional-focus-ring-outline-width) var(--functional-focus-ring-color);
|
|
242
|
-
|
|
243
|
-
/* Needed for High Contrast mode */
|
|
244
|
-
outline:
|
|
245
|
-
var(--functional-focus-ring-outline-width) var(--functional-focus-ring-outline-style)
|
|
246
|
-
var(--functional-focus-ring-outline-color);
|
|
247
|
-
transition: box-shadow var(--functional-timing-fast) ease-out;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
@media (prefers-reduced-motion), (update: slow) {
|
|
251
|
-
.table-sort:focus {
|
|
252
|
-
transition-duration: 0.001ms !important;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
</style>
|
|
257
|
-
|
|
258
1
|
<script lang="ts">
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
const captionClasses = () => {
|
|
434
|
-
return [
|
|
435
|
-
// .screenreader-only is expected to be globally available via common.min.css
|
|
436
|
-
captionPosition === "hidden" ? "screenreader-only" : "",
|
|
437
|
-
captionPosition !== "hidden" ? `caption-${captionPosition}` : "",
|
|
438
|
-
]
|
|
439
|
-
.filter((klass) => klass.length)
|
|
440
|
-
.join(" ");
|
|
441
|
-
};
|
|
442
|
-
|
|
443
|
-
const getKeys = (row) => {
|
|
444
|
-
const filteredKeys = filterByKey
|
|
445
|
-
? Object.keys(columns).map((key) => [key, key])
|
|
446
|
-
: Object.keys(row).map((key, index) => [key, index]);
|
|
447
|
-
return filteredKeys;
|
|
448
|
-
};
|
|
2
|
+
import { createEventDispatcher } from 'svelte';
|
|
3
|
+
|
|
4
|
+
// Hack: Preserves way it was done in agnostic-svelte but ugly :(
|
|
5
|
+
interface ArrayMonkeyPatched extends Array<any> {
|
|
6
|
+
labelByKey(): any[];
|
|
7
|
+
}
|
|
8
|
+
export let headers: ArrayMonkeyPatched = [] as ArrayMonkeyPatched;
|
|
9
|
+
headers.labelByKey = function () {
|
|
10
|
+
return this.reduce(function (rv, x) {
|
|
11
|
+
if (!('key' in x))
|
|
12
|
+
throw new Error('Header must have key value with `sortByKey` set to `true`');
|
|
13
|
+
rv[x.key] = x;
|
|
14
|
+
return rv;
|
|
15
|
+
}, {});
|
|
16
|
+
};
|
|
17
|
+
export let rows = [];
|
|
18
|
+
|
|
19
|
+
export let caption = '';
|
|
20
|
+
export let captionPosition = 'hidden';
|
|
21
|
+
export let tableSize = '';
|
|
22
|
+
export let responsiveSize = '';
|
|
23
|
+
export let isUppercasedHeaders = false;
|
|
24
|
+
export let isBordered = false;
|
|
25
|
+
export let isBorderless = false;
|
|
26
|
+
export let isStriped = false;
|
|
27
|
+
export let isHoverable = false;
|
|
28
|
+
export let isStacked = false;
|
|
29
|
+
export let filterByKey = false;
|
|
30
|
+
export let offset = 0;
|
|
31
|
+
export let limit = 0;
|
|
32
|
+
|
|
33
|
+
// State
|
|
34
|
+
let direction = 'none';
|
|
35
|
+
let sortingKey = '';
|
|
36
|
+
|
|
37
|
+
// Trigger event on sort
|
|
38
|
+
const dispatch = createEventDispatcher();
|
|
39
|
+
$: dispatch('sort', {
|
|
40
|
+
direction,
|
|
41
|
+
sortingKey
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const pluckColumnToSort = (rowLeft, rowRight) => {
|
|
45
|
+
const colLeft =
|
|
46
|
+
rowLeft[sortingKey] === null || rowLeft[sortingKey] === undefined
|
|
47
|
+
? -Infinity
|
|
48
|
+
: rowLeft[sortingKey];
|
|
49
|
+
const colRight =
|
|
50
|
+
rowRight[sortingKey] === null || rowRight[sortingKey] === undefined
|
|
51
|
+
? -Infinity
|
|
52
|
+
: rowRight[sortingKey];
|
|
53
|
+
return {
|
|
54
|
+
colLeft,
|
|
55
|
+
colRight
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const internalSort = (rowLeft, rowRight) => {
|
|
60
|
+
let { colLeft, colRight } = pluckColumnToSort(rowLeft, rowRight);
|
|
61
|
+
|
|
62
|
+
const headerWithCustomSortFunction = headers.find((h) => h.key === sortingKey && !!h.sortFn);
|
|
63
|
+
if (headerWithCustomSortFunction && headerWithCustomSortFunction.sortFn) {
|
|
64
|
+
return headerWithCustomSortFunction.sortFn(colLeft, colRight);
|
|
65
|
+
}
|
|
66
|
+
// No custom sort method for the header cell, so we continue with our own.
|
|
67
|
+
// Strings converted to lowercase; dollar currency etc. stripped (not yet i18n safe!)
|
|
68
|
+
colLeft = typeof colLeft === 'string' ? colLeft.toLowerCase().replace(/(^\$|,)/g, '') : colLeft;
|
|
69
|
+
colRight =
|
|
70
|
+
typeof colRight === 'string' ? colRight.toLowerCase().replace(/(^\$|,)/g, '') : colRight;
|
|
71
|
+
// If raw value represents a number explicitly set to Number
|
|
72
|
+
colLeft = !Number.isNaN(Number(colLeft)) ? Number(colLeft) : colLeft;
|
|
73
|
+
colRight = !Number.isNaN(Number(colRight)) ? Number(colRight) : colRight;
|
|
74
|
+
if (colLeft > colRight) {
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
if (colLeft < colRight) {
|
|
78
|
+
return -1;
|
|
79
|
+
}
|
|
80
|
+
return 0;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// Simply flips the sign of results of the ascending sort
|
|
84
|
+
const descendingSort = (row1, row2) => internalSort(row1, row2) * -1;
|
|
85
|
+
|
|
86
|
+
$: columns = filterByKey ? headers.labelByKey() : { ...headers };
|
|
87
|
+
// Reactive declaration: ...state needs to be computed from other parts; so
|
|
88
|
+
// direction is a dependency and when it changes, sortableItems gets recomputed
|
|
89
|
+
$: sortableItems =
|
|
90
|
+
direction === 'ascending'
|
|
91
|
+
? rows.sort(internalSort)
|
|
92
|
+
: direction === 'descending'
|
|
93
|
+
? rows.sort(descendingSort)
|
|
94
|
+
: (sortableItems = [...rows]);
|
|
95
|
+
|
|
96
|
+
$: visibleItems = sortableItems.slice(offset ? offset : 0, limit ? offset + limit : undefined);
|
|
97
|
+
|
|
98
|
+
const handleSortClicked = (headerKey: string) => {
|
|
99
|
+
if (sortingKey !== headerKey) {
|
|
100
|
+
direction = 'none';
|
|
101
|
+
sortingKey = headerKey;
|
|
102
|
+
}
|
|
103
|
+
switch (direction) {
|
|
104
|
+
case 'ascending':
|
|
105
|
+
direction = 'descending';
|
|
106
|
+
break;
|
|
107
|
+
case 'descending':
|
|
108
|
+
direction = 'none';
|
|
109
|
+
break;
|
|
110
|
+
case 'none':
|
|
111
|
+
direction = 'ascending';
|
|
112
|
+
break;
|
|
113
|
+
default:
|
|
114
|
+
console.warn('Table sorting only supports directions: ascending | descending | none');
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const getSortingClassesFor = (headerKey, direction, sortingKey) => {
|
|
119
|
+
if (sortingKey === headerKey) {
|
|
120
|
+
return ['icon-sort', direction && direction !== 'none' ? `icon-sort-${direction}` : '']
|
|
121
|
+
.filter((klass) => klass.length)
|
|
122
|
+
.join(' ');
|
|
123
|
+
}
|
|
124
|
+
return 'icon-sort';
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const getSortDirectionFor = (headerKey, direction, sortingKey) => {
|
|
128
|
+
if (sortingKey !== headerKey) {
|
|
129
|
+
return 'none';
|
|
130
|
+
} else {
|
|
131
|
+
return direction;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const tableResponsiveClasses = () => {
|
|
136
|
+
return [
|
|
137
|
+
!responsiveSize ? 'table-responsive' : '',
|
|
138
|
+
responsiveSize ? `table-responsive-${responsiveSize}` : ''
|
|
139
|
+
]
|
|
140
|
+
.filter((klass) => klass.length)
|
|
141
|
+
.join(' ');
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const tableClasses = () => {
|
|
145
|
+
return [
|
|
146
|
+
'table',
|
|
147
|
+
tableSize ? `table-${tableSize}` : '',
|
|
148
|
+
isUppercasedHeaders ? 'table-caps' : '',
|
|
149
|
+
isBordered ? 'table-bordered' : '',
|
|
150
|
+
isBorderless ? 'table-borderless' : '',
|
|
151
|
+
isStriped ? 'table-striped' : '',
|
|
152
|
+
isHoverable ? 'table-hoverable' : '',
|
|
153
|
+
isStacked ? 'table-stacked' : ''
|
|
154
|
+
]
|
|
155
|
+
.filter((klass) => klass.length)
|
|
156
|
+
.join(' ');
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const captionClasses = () => {
|
|
160
|
+
return [
|
|
161
|
+
// .screenreader-only is expected to be globally available via common.min.css
|
|
162
|
+
captionPosition === 'hidden' ? 'screenreader-only' : '',
|
|
163
|
+
captionPosition !== 'hidden' ? `caption-${captionPosition}` : ''
|
|
164
|
+
]
|
|
165
|
+
.filter((klass) => klass.length)
|
|
166
|
+
.join(' ');
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const getKeys = (row) => {
|
|
170
|
+
const filteredKeys = filterByKey
|
|
171
|
+
? Object.keys(columns).map((key) => [key, key])
|
|
172
|
+
: Object.keys(row).map((key, index) => [key, index]);
|
|
173
|
+
return filteredKeys;
|
|
174
|
+
};
|
|
449
175
|
</script>
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
</div>
|
|
541
|
-
{:else}{headerCol.label}{/if}
|
|
542
|
-
</th>
|
|
543
|
-
{/each}
|
|
544
|
-
</tr>
|
|
545
|
-
</thead>
|
|
546
|
-
<tbody>
|
|
547
|
-
{#each visibleItems as row}
|
|
548
|
-
<tr>
|
|
549
|
-
{#each getKeys(row) as [key, id]}
|
|
550
|
-
<td>
|
|
551
|
-
{#if columns[id].renderComponent}
|
|
552
|
-
<svelte:component
|
|
553
|
-
this="{columns[id].renderComponent()}"
|
|
554
|
-
cellValue="{row[key]}"
|
|
555
|
-
/>
|
|
556
|
-
{:else}
|
|
557
|
-
{row[key]}
|
|
558
|
-
{/if}
|
|
559
|
-
</td>
|
|
560
|
-
{/each}
|
|
561
|
-
</tr>
|
|
562
|
-
{/each}
|
|
563
|
-
</tbody>
|
|
564
|
-
</table>
|
|
176
|
+
|
|
177
|
+
<div class={tableResponsiveClasses()}>
|
|
178
|
+
<table class={tableClasses()}>
|
|
179
|
+
<caption class={captionClasses()}>{caption}</caption>
|
|
180
|
+
<thead>
|
|
181
|
+
<tr>
|
|
182
|
+
{#each headers as headerCol}
|
|
183
|
+
<th
|
|
184
|
+
aria-sort={getSortDirectionFor(headerCol.key, direction, sortingKey)}
|
|
185
|
+
scope="col"
|
|
186
|
+
style={headerCol.width ? `width: ${headerCol.width}` : 'width: auto'}
|
|
187
|
+
>
|
|
188
|
+
{#if headerCol.sortable}
|
|
189
|
+
<div class="table-header-container">
|
|
190
|
+
<span class="table-sort-label">{headerCol.label}</span>
|
|
191
|
+
<button
|
|
192
|
+
type="button"
|
|
193
|
+
class="table-sort"
|
|
194
|
+
on:click={() => handleSortClicked(headerCol.key)}
|
|
195
|
+
>
|
|
196
|
+
<span class="screenreader-only">{headerCol.label}</span>
|
|
197
|
+
<span class={getSortingClassesFor(headerCol.key, direction, sortingKey)}>
|
|
198
|
+
{#if getSortDirectionFor(headerCol.key, direction, sortingKey) === 'none'}
|
|
199
|
+
<svg
|
|
200
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
201
|
+
class={getSortingClassesFor(headerCol.key, direction, sortingKey)}
|
|
202
|
+
fill="none"
|
|
203
|
+
viewBox="0 0 20 20"
|
|
204
|
+
width="20"
|
|
205
|
+
height="20"
|
|
206
|
+
>
|
|
207
|
+
<path
|
|
208
|
+
d="m15 13-5 5-5-5M5 7l5-5 5 5"
|
|
209
|
+
stroke="currentColor"
|
|
210
|
+
stroke-width="2"
|
|
211
|
+
stroke-linecap="round"
|
|
212
|
+
stroke-linejoin="round"
|
|
213
|
+
/>
|
|
214
|
+
</svg>
|
|
215
|
+
{:else if getSortDirectionFor(headerCol.key, direction, sortingKey) === 'descending'}
|
|
216
|
+
<svg
|
|
217
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
218
|
+
class={getSortingClassesFor(headerCol.key, direction, sortingKey)}
|
|
219
|
+
viewBox="0 0 20 20"
|
|
220
|
+
width="20"
|
|
221
|
+
height="20"
|
|
222
|
+
>
|
|
223
|
+
<path
|
|
224
|
+
d="m10.778 13.635 4.964-5.86c.586-.693.11-1.775-.78-1.775H5.037a1.01 1.01 0 0 0-.561.17c-.168.111-.3.27-.382.457a1.102 1.102 0 0 0 .164 1.147l4.963 5.86a1.006 1.006 0 0 0 1.559 0v.001Z"
|
|
225
|
+
fill="currentColor"
|
|
226
|
+
/>
|
|
227
|
+
</svg>
|
|
228
|
+
{:else}
|
|
229
|
+
<svg
|
|
230
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
231
|
+
class={getSortingClassesFor(headerCol.key, direction, sortingKey)}
|
|
232
|
+
viewBox="0 0 20 20"
|
|
233
|
+
width="20"
|
|
234
|
+
height="20"
|
|
235
|
+
>
|
|
236
|
+
<path
|
|
237
|
+
d="m9.221 6.365-4.963 5.86c-.586.693-.11 1.775.78 1.775h9.926c.2 0 .394-.059.561-.17.168-.111.3-.27.383-.457a1.102 1.102 0 0 0-.165-1.147l-4.963-5.86a1.04 1.04 0 0 0-.351-.27 1.007 1.007 0 0 0-1.208.27v-.001Z"
|
|
238
|
+
fill="currentColor"
|
|
239
|
+
/>
|
|
240
|
+
</svg>
|
|
241
|
+
{/if}
|
|
242
|
+
</span>
|
|
243
|
+
</button>
|
|
244
|
+
</div>
|
|
245
|
+
{:else}{headerCol.label}{/if}
|
|
246
|
+
</th>
|
|
247
|
+
{/each}
|
|
248
|
+
</tr>
|
|
249
|
+
</thead>
|
|
250
|
+
<tbody>
|
|
251
|
+
{#each visibleItems as row}
|
|
252
|
+
<tr>
|
|
253
|
+
{#each getKeys(row) as [key, id]}
|
|
254
|
+
<td>
|
|
255
|
+
{#if columns[id].renderComponent}
|
|
256
|
+
<svelte:component this={columns[id].renderComponent()} cellValue={row[key]} />
|
|
257
|
+
{:else}
|
|
258
|
+
{row[key]}
|
|
259
|
+
{/if}
|
|
260
|
+
</td>
|
|
261
|
+
{/each}
|
|
262
|
+
</tr>
|
|
263
|
+
{/each}
|
|
264
|
+
</tbody>
|
|
265
|
+
</table>
|
|
565
266
|
</div>
|
|
267
|
+
|
|
268
|
+
<style>
|
|
269
|
+
.table {
|
|
270
|
+
--table-bg: transparent;
|
|
271
|
+
--table-accent-bg: transparent;
|
|
272
|
+
--table-striped-color: var(--functional-dark);
|
|
273
|
+
--table-striped-bg: rgb(0 0 0 / 2.5%);
|
|
274
|
+
--table-active-color: var(--functional-dark);
|
|
275
|
+
--table-active-bg: rgb(0 0 0 / 1.5%);
|
|
276
|
+
--table-hoverable-color: var(--functional-dark);
|
|
277
|
+
--table-hoverable-bg: var(--functional-table-hover-bg, #f1faff);
|
|
278
|
+
|
|
279
|
+
width: 100%;
|
|
280
|
+
margin-bottom: var(--fluid-16);
|
|
281
|
+
color: var(--functional-dark);
|
|
282
|
+
vertical-align: top;
|
|
283
|
+
border-color: var(--functional-table-border-color, var(--functional-gray-light));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.table > :not(caption) > * > * {
|
|
287
|
+
padding: var(--fluid-8) var(--fluid-8);
|
|
288
|
+
background-color: var(--table-bg);
|
|
289
|
+
border-bottom-width: 1px;
|
|
290
|
+
|
|
291
|
+
/* 4th is spread --table-accent-bg will gets reset for active, hover, striped */
|
|
292
|
+
box-shadow: inset 0 0 0 9999px var(--table-accent-bg);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.table > tbody {
|
|
296
|
+
vertical-align: inherit;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.table > thead {
|
|
300
|
+
vertical-align: bottom;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.table thead th {
|
|
304
|
+
font-weight: 600;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.table-caps thead th {
|
|
308
|
+
font-size: var(--fluid-12);
|
|
309
|
+
text-transform: uppercase;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.table tbody td,
|
|
313
|
+
.table tbody th {
|
|
314
|
+
font-weight: 400;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.table > :not(thead):not(caption) {
|
|
318
|
+
border-top: var(--fluid-2) solid var(--functional-gray-light);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.caption-top {
|
|
322
|
+
caption-side: top;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.caption-bottom {
|
|
326
|
+
caption-side: bottom;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.caption-bottom,
|
|
330
|
+
.caption-top {
|
|
331
|
+
padding-block-start: var(--fluid-12);
|
|
332
|
+
padding-block-end: var(--fluid-12);
|
|
333
|
+
|
|
334
|
+
/* Takes writing mode into account -- (mdn) same as left if direction is left-to-right
|
|
335
|
+
and right if direction is right-to-left */
|
|
336
|
+
text-align: start;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.caption-end {
|
|
340
|
+
text-align: end;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.table-small > :not(caption) > * > * {
|
|
344
|
+
padding: var(--fluid-4) var(--fluid-4);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.table-large > :not(caption) > * > * {
|
|
348
|
+
padding: var(--fluid-12) var(--fluid-12);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.table-xlarge > :not(caption) > * > * {
|
|
352
|
+
padding: var(--fluid-18) var(--fluid-18);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.table-bordered > :not(caption) > * {
|
|
356
|
+
border-width: 1px 0;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.table-bordered > :not(caption) > * > * {
|
|
360
|
+
border-width: 0 1px;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.table-borderless > :not(caption) > * > * {
|
|
364
|
+
border-bottom-width: 0;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.table-borderless > :not(:first-child) {
|
|
368
|
+
border-top-width: 0;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.table-striped > tbody > tr:nth-of-type(odd) > * {
|
|
372
|
+
--table-accent-bg: var(--table-striped-bg);
|
|
373
|
+
|
|
374
|
+
color: var(--table-striped-color);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.table-active {
|
|
378
|
+
--table-accent-bg: var(--table-active-bg);
|
|
379
|
+
|
|
380
|
+
color: var(--table-active-color);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.table-hoverable > tbody > tr:hover > * {
|
|
384
|
+
--table-accent-bg: var(--table-hoverable-bg);
|
|
385
|
+
|
|
386
|
+
color: var(--table-hoverable-color);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* Stacked tables */
|
|
390
|
+
.table-stacked thead {
|
|
391
|
+
display: none;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.table-stacked tr,
|
|
395
|
+
.table-stacked tbody th,
|
|
396
|
+
.table-stacked tbody td {
|
|
397
|
+
display: block;
|
|
398
|
+
width: 100%;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.table-stacked tbody th,
|
|
402
|
+
.table-stacked tbody td {
|
|
403
|
+
border-bottom-width: 0;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.table-stacked td[data-label] {
|
|
407
|
+
padding-bottom: var(--fluid-12);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.table-stacked tr {
|
|
411
|
+
border-bottom: var(--fluid-2) solid var(--functional-gray-light);
|
|
412
|
+
border-top-width: 0;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.table-stacked th[data-label]::before,
|
|
416
|
+
.table-stacked td[data-label]::before {
|
|
417
|
+
content: attr(data-label);
|
|
418
|
+
display: block;
|
|
419
|
+
font-weight: 600;
|
|
420
|
+
margin: -0.5rem -1rem 0;
|
|
421
|
+
padding: var(--fluid-12) var(--fluid-16) var(--fluid-6);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.table-stacked tr th:first-child,
|
|
425
|
+
.table-stacked tr td:first-child {
|
|
426
|
+
border-top-width: 0;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.table-stacked tr:nth-child(odd) td,
|
|
430
|
+
.table-stacked tr:nth-child(odd) th {
|
|
431
|
+
background-color: inherit;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.table-stacked tr:first-child th:first-child,
|
|
435
|
+
.table-stacked tr:first-child td:first-child {
|
|
436
|
+
border-top: var(--fluid-2) solid var(--functional-gray-light);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.table-stacked th[data-label],
|
|
440
|
+
.table-stacked td[data-label] {
|
|
441
|
+
padding-bottom: var(--fluid-12);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/* As soon as there's not enough width, it will kick in horizontal scrolling */
|
|
445
|
+
.table-responsive {
|
|
446
|
+
overflow-x: auto;
|
|
447
|
+
-webkit-overflow-scrolling: touch;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/* Table is responsive only "up to" the breakpoint. Above it will not scroll */
|
|
451
|
+
@media (max-width: 576px) {
|
|
452
|
+
.table-responsive-small {
|
|
453
|
+
overflow-x: auto;
|
|
454
|
+
-webkit-overflow-scrolling: touch;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
@media (max-width: 768px) {
|
|
459
|
+
.table-responsive-medium {
|
|
460
|
+
overflow-x: auto;
|
|
461
|
+
-webkit-overflow-scrolling: touch;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
@media (max-width: 992px) {
|
|
466
|
+
.table-responsive-large {
|
|
467
|
+
overflow-x: auto;
|
|
468
|
+
-webkit-overflow-scrolling: touch;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
@media (max-width: 1200px) {
|
|
473
|
+
.table-responsive-xlarge {
|
|
474
|
+
overflow-x: auto;
|
|
475
|
+
-webkit-overflow-scrolling: touch;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.table-header-container {
|
|
480
|
+
display: flex;
|
|
481
|
+
align-items: center;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.table-sort-label {
|
|
485
|
+
flex: 1;
|
|
486
|
+
padding-inline-end: 0.5rem;
|
|
487
|
+
text-align: left;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.table-sort {
|
|
491
|
+
flex: 0 1 var(--fluid-48);
|
|
492
|
+
background-color: transparent;
|
|
493
|
+
border-color: transparent;
|
|
494
|
+
border-width: 0;
|
|
495
|
+
cursor: pointer;
|
|
496
|
+
display: flex;
|
|
497
|
+
justify-content: center;
|
|
498
|
+
padding-block-start: var(--fluid-2);
|
|
499
|
+
padding-block-end: var(--fluid-2);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
.icon-sort {
|
|
503
|
+
width: 1.125rem;
|
|
504
|
+
height: 1.125rem;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.table-sort:focus {
|
|
508
|
+
box-shadow: 0 0 0 var(--functional-focus-ring-outline-width) var(--functional-focus-ring-color);
|
|
509
|
+
|
|
510
|
+
/* Needed for High Contrast mode */
|
|
511
|
+
outline: var(--functional-focus-ring-outline-width) var(--functional-focus-ring-outline-style)
|
|
512
|
+
var(--functional-focus-ring-outline-color);
|
|
513
|
+
transition: box-shadow var(--functional-timing-fast) ease-out;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
@media (prefers-reduced-motion), (update: slow) {
|
|
517
|
+
.table-sort:focus {
|
|
518
|
+
transition-duration: 0.001ms !important;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
</style>
|