@justin_evo/evo-ui 1.2.0 → 1.2.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.
- package/LICENSE +21 -21
- package/README.md +70 -70
- package/dist/declarations.d.ts +6 -6
- package/package.json +52 -52
- package/src/Alert/Alert.tsx +49 -49
- package/src/AutoComplete/AutoComplete.tsx +810 -810
- package/src/Badge/Badge.tsx +53 -53
- package/src/Breadcrumb/Breadcrumb.tsx +53 -53
- package/src/Button/Button.tsx +125 -125
- package/src/Card/Card.tsx +257 -257
- package/src/Checkbox/Checkbox.tsx +59 -59
- package/src/CommandPalette/CommandPalette.tsx +185 -185
- package/src/Container/Container.tsx +31 -31
- package/src/Divider/Divider.tsx +31 -31
- package/src/Form/Form.tsx +185 -185
- package/src/Grid/Grid.tsx +66 -66
- package/src/ImageCropper/ImageCropper.tsx +911 -911
- package/src/Input/Input.tsx +74 -74
- package/src/Modal/Modal.tsx +77 -77
- package/src/Nav/Nav.tsx +708 -708
- package/src/Notification/Notification.tsx +1503 -1503
- package/src/Pagination/Pagination.tsx +76 -76
- package/src/Radio/Radio.tsx +69 -69
- package/src/RichTextArea/RichTextArea.tsx +886 -886
- package/src/Select/Select.tsx +515 -515
- package/src/Skeleton/Skeleton.tsx +70 -70
- package/src/Stack/Stack.tsx +52 -52
- package/src/Table/Table.tsx +335 -335
- package/src/Tabs/Tabs.tsx +90 -90
- package/src/Theme/ThemeProvider.tsx +253 -253
- package/src/Theme/ThemeToggle.tsx +79 -79
- package/src/Toggle/Toggle.tsx +48 -48
- package/src/Tooltip/Tooltip.tsx +38 -38
- package/src/TopNav/TopNav.tsx +1163 -1163
- package/src/TreeSelect/TreeSelect.tsx +825 -825
- package/src/css/alert.module.scss +93 -93
- package/src/css/autocomplete.module.scss +416 -416
- package/src/css/badge.module.scss +82 -82
- package/src/css/base/_color.scss +159 -159
- package/src/css/base/_theme.scss +237 -237
- package/src/css/base/_variables.scss +161 -161
- package/src/css/breadcrumb.module.scss +50 -50
- package/src/css/button.module.scss +385 -385
- package/src/css/card.module.scss +217 -217
- package/src/css/checkbox.module.scss +123 -123
- package/src/css/commandpalette.module.scss +211 -211
- package/src/css/container.module.scss +18 -18
- package/src/css/divider.module.scss +41 -41
- package/src/css/form.module.scss +245 -245
- package/src/css/imagecropper.module.scss +397 -397
- package/src/css/input.module.scss +89 -89
- package/src/css/modal.module.scss +105 -105
- package/src/css/nav.module.scss +494 -494
- package/src/css/notification.module.scss +691 -691
- package/src/css/pagination.module.scss +63 -63
- package/src/css/radio.module.scss +89 -89
- package/src/css/richtextarea.module.scss +307 -307
- package/src/css/select.module.scss +525 -525
- package/src/css/skeleton.module.scss +30 -30
- package/src/css/table.module.scss +386 -386
- package/src/css/tabs.module.scss +63 -63
- package/src/css/theme-toggle.module.scss +83 -83
- package/src/css/toggle.module.scss +54 -54
- package/src/css/tooltip.module.scss +97 -97
- package/src/css/topnav.module.scss +568 -568
- package/src/css/treeselect.module.scss +558 -558
- package/src/css/utilities/_borders.scss +111 -111
- package/src/css/utilities/_colors.scss +66 -66
- package/src/css/utilities/_effects.scss +216 -216
- package/src/css/utilities/_layout.scss +181 -181
- package/src/css/utilities/_position.scss +75 -75
- package/src/css/utilities/_sizing.scss +138 -138
- package/src/css/utilities/_spacing.scss +99 -99
- package/src/css/utilities/_typography.scss +121 -121
- package/src/css/utilities/index.scss +24 -24
- package/src/declarations.d.ts +6 -6
- package/src/index.ts +60 -60
|
@@ -1,386 +1,386 @@
|
|
|
1
|
-
@use './base/variables' as *;
|
|
2
|
-
@use './base/color' as *;
|
|
3
|
-
|
|
4
|
-
// ==========================================================
|
|
5
|
-
// EVO-UI TABLE
|
|
6
|
-
// ----------------------------------------------------------
|
|
7
|
-
// A lightweight, theme-aware data table.
|
|
8
|
-
// - Horizontal rules only — no busy vertical grid lines.
|
|
9
|
-
// - Density variants (sm/md/lg) tune padding + type scale.
|
|
10
|
-
// - Sticky headers, striped rows, sortable columns, and a
|
|
11
|
-
// loading skeleton state — all opt-in.
|
|
12
|
-
// - Two responsive modes for narrow viewports:
|
|
13
|
-
// `scroll` — thin overflow scrollbar
|
|
14
|
-
// `stack` — rows collapse into labelled cards
|
|
15
|
-
// ==========================================================
|
|
16
|
-
|
|
17
|
-
.wrapper {
|
|
18
|
-
width: 100%;
|
|
19
|
-
background-color: $color-surface-elevated;
|
|
20
|
-
border: 1px solid $color-border;
|
|
21
|
-
border-radius: $evo-border-radius-lg;
|
|
22
|
-
font-family: $font-sans;
|
|
23
|
-
color: $color-text-primary;
|
|
24
|
-
// Clip rounded corners against the inner scroll container.
|
|
25
|
-
overflow: hidden;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.scroll {
|
|
29
|
-
width: 100%;
|
|
30
|
-
overflow-x: auto;
|
|
31
|
-
-webkit-overflow-scrolling: touch;
|
|
32
|
-
scrollbar-color: $color-border-strong transparent;
|
|
33
|
-
scrollbar-width: thin;
|
|
34
|
-
|
|
35
|
-
&::-webkit-scrollbar {
|
|
36
|
-
height: 8px;
|
|
37
|
-
width: 8px;
|
|
38
|
-
}
|
|
39
|
-
&::-webkit-scrollbar-thumb {
|
|
40
|
-
background: $color-border-strong;
|
|
41
|
-
border-radius: $radius-full;
|
|
42
|
-
}
|
|
43
|
-
&::-webkit-scrollbar-track {
|
|
44
|
-
background: transparent;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.table {
|
|
49
|
-
width: 100%;
|
|
50
|
-
border-collapse: separate;
|
|
51
|
-
border-spacing: 0;
|
|
52
|
-
font-size: $text-sm;
|
|
53
|
-
font-variant-numeric: tabular-nums;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.caption {
|
|
57
|
-
caption-side: top;
|
|
58
|
-
text-align: left;
|
|
59
|
-
padding: 0.75rem 1rem 0;
|
|
60
|
-
color: $color-text-secondary;
|
|
61
|
-
font-size: $text-xs;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ----- Header --------------------------------------------------
|
|
65
|
-
.thead {
|
|
66
|
-
background-color: $color-surface-sunken;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.th {
|
|
70
|
-
padding: 0.625rem 1rem;
|
|
71
|
-
text-align: left;
|
|
72
|
-
font-size: $text-xs;
|
|
73
|
-
font-weight: 600;
|
|
74
|
-
color: $color-text-secondary;
|
|
75
|
-
white-space: nowrap;
|
|
76
|
-
border-bottom: 1px solid $color-border;
|
|
77
|
-
vertical-align: middle;
|
|
78
|
-
letter-spacing: 0.01em;
|
|
79
|
-
user-select: none;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.sortBtn {
|
|
83
|
-
display: inline-flex;
|
|
84
|
-
align-items: center;
|
|
85
|
-
gap: 0.375rem;
|
|
86
|
-
background: transparent;
|
|
87
|
-
border: 0;
|
|
88
|
-
padding: 0;
|
|
89
|
-
margin: 0;
|
|
90
|
-
font: inherit;
|
|
91
|
-
color: inherit;
|
|
92
|
-
cursor: pointer;
|
|
93
|
-
border-radius: $radius-sm;
|
|
94
|
-
transition: color $transition-fast;
|
|
95
|
-
|
|
96
|
-
&:hover {
|
|
97
|
-
color: $color-text-primary;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
&:focus-visible {
|
|
101
|
-
outline: 2px solid $evo-primary-focus;
|
|
102
|
-
outline-offset: 2px;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
.sortIcon {
|
|
107
|
-
display: inline-flex;
|
|
108
|
-
color: $color-text-muted;
|
|
109
|
-
flex-shrink: 0;
|
|
110
|
-
transition: color $transition-fast;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
.sortActive {
|
|
114
|
-
color: $color-text-primary;
|
|
115
|
-
|
|
116
|
-
.sortIcon {
|
|
117
|
-
color: $evo-primary-color;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// ----- Body ----------------------------------------------------
|
|
122
|
-
.tbody {
|
|
123
|
-
.tr {
|
|
124
|
-
transition: background-color $transition-fast;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.td {
|
|
129
|
-
padding: 0.75rem 1rem;
|
|
130
|
-
color: $color-text-primary;
|
|
131
|
-
vertical-align: middle;
|
|
132
|
-
border-bottom: 1px solid $color-border-subtle;
|
|
133
|
-
text-align: left;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Drop the last row border so it tucks cleanly into the rounded wrapper.
|
|
137
|
-
.tbody .tr:last-child .td {
|
|
138
|
-
border-bottom: 0;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// ----- Alignment ----------------------------------------------
|
|
142
|
-
.align-left {
|
|
143
|
-
text-align: left;
|
|
144
|
-
}
|
|
145
|
-
.align-center {
|
|
146
|
-
text-align: center;
|
|
147
|
-
}
|
|
148
|
-
.align-right {
|
|
149
|
-
text-align: right;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Sort buttons are inline-flex — `text-align` doesn't reach them.
|
|
153
|
-
.align-center .sortBtn {
|
|
154
|
-
width: 100%;
|
|
155
|
-
justify-content: center;
|
|
156
|
-
}
|
|
157
|
-
.align-right .sortBtn {
|
|
158
|
-
width: 100%;
|
|
159
|
-
justify-content: flex-end;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// ----- Density -------------------------------------------------
|
|
163
|
-
.size-sm {
|
|
164
|
-
.table {
|
|
165
|
-
font-size: $text-xs;
|
|
166
|
-
}
|
|
167
|
-
.th {
|
|
168
|
-
padding: 0.375rem 0.75rem;
|
|
169
|
-
}
|
|
170
|
-
.td {
|
|
171
|
-
padding: 0.5rem 0.75rem;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
.size-md {
|
|
176
|
-
.table {
|
|
177
|
-
font-size: $text-sm;
|
|
178
|
-
}
|
|
179
|
-
.th {
|
|
180
|
-
padding: 0.625rem 1rem;
|
|
181
|
-
}
|
|
182
|
-
.td {
|
|
183
|
-
padding: 0.75rem 1rem;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
.size-lg {
|
|
188
|
-
.table {
|
|
189
|
-
font-size: $text-base;
|
|
190
|
-
}
|
|
191
|
-
.th {
|
|
192
|
-
padding: 0.875rem 1.25rem;
|
|
193
|
-
}
|
|
194
|
-
.td {
|
|
195
|
-
padding: 1rem 1.25rem;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// ----- Modifiers ----------------------------------------------
|
|
200
|
-
.hoverable .tbody .tr:hover {
|
|
201
|
-
background-color: $color-surface-hover;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
.striped .tbody .tr:nth-child(even) {
|
|
205
|
-
background-color: $color-surface-sunken;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Hover wins over stripe.
|
|
209
|
-
.striped.hoverable .tbody .tr:nth-child(even):hover {
|
|
210
|
-
background-color: $color-surface-hover;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.bordered {
|
|
214
|
-
.th,
|
|
215
|
-
.td {
|
|
216
|
-
&:not(:last-child) {
|
|
217
|
-
border-right: 1px solid $color-border-subtle;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.stickyHeader {
|
|
223
|
-
.scroll {
|
|
224
|
-
max-height: 70vh;
|
|
225
|
-
overflow-y: auto;
|
|
226
|
-
}
|
|
227
|
-
.thead .th {
|
|
228
|
-
position: sticky;
|
|
229
|
-
top: 0;
|
|
230
|
-
z-index: 2;
|
|
231
|
-
background-color: $color-surface-sunken;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
.clickable .tbody .tr {
|
|
236
|
-
cursor: pointer;
|
|
237
|
-
|
|
238
|
-
&:active {
|
|
239
|
-
background-color: $color-surface-active;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// ----- Empty + Skeleton ---------------------------------------
|
|
244
|
-
.empty {
|
|
245
|
-
padding: 3rem 1.5rem;
|
|
246
|
-
text-align: center;
|
|
247
|
-
color: $color-text-muted;
|
|
248
|
-
font-size: $text-sm;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
.emptyText {
|
|
252
|
-
display: inline-block;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
.skeleton {
|
|
256
|
-
display: block;
|
|
257
|
-
height: 0.75rem;
|
|
258
|
-
width: 70%;
|
|
259
|
-
border-radius: $radius-sm;
|
|
260
|
-
background: linear-gradient(
|
|
261
|
-
90deg,
|
|
262
|
-
$color-skeleton-base 0%,
|
|
263
|
-
$color-skeleton-highlight 50%,
|
|
264
|
-
$color-skeleton-base 100%
|
|
265
|
-
);
|
|
266
|
-
background-size: 200% 100%;
|
|
267
|
-
animation: evoTableShimmer 1.4s ease-in-out infinite;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
@keyframes evoTableShimmer {
|
|
271
|
-
0% {
|
|
272
|
-
background-position: 200% 0;
|
|
273
|
-
}
|
|
274
|
-
100% {
|
|
275
|
-
background-position: -200% 0;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
@media (prefers-reduced-motion: reduce) {
|
|
280
|
-
.skeleton {
|
|
281
|
-
animation: none;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// ----- Responsive: stack mode ---------------------------------
|
|
286
|
-
// Below ~640px, transform rows into vertical "cards" where each
|
|
287
|
-
// cell becomes a labelled row. The visual header is removed
|
|
288
|
-
// (kept in DOM, hidden visually, for screen readers).
|
|
289
|
-
.responsiveStack {
|
|
290
|
-
@media (max-width: 640px) {
|
|
291
|
-
border: 0;
|
|
292
|
-
background: transparent;
|
|
293
|
-
overflow: visible;
|
|
294
|
-
|
|
295
|
-
.scroll {
|
|
296
|
-
overflow: visible;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
.table,
|
|
300
|
-
.tbody,
|
|
301
|
-
.tr {
|
|
302
|
-
display: block;
|
|
303
|
-
width: 100%;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
.thead {
|
|
307
|
-
// Screen-reader-only — keeps semantics while removing visuals.
|
|
308
|
-
position: absolute;
|
|
309
|
-
width: 1px;
|
|
310
|
-
height: 1px;
|
|
311
|
-
padding: 0;
|
|
312
|
-
margin: -1px;
|
|
313
|
-
overflow: hidden;
|
|
314
|
-
clip: rect(0, 0, 0, 0);
|
|
315
|
-
white-space: nowrap;
|
|
316
|
-
border: 0;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
.tbody .tr {
|
|
320
|
-
background-color: $color-surface-elevated;
|
|
321
|
-
border: 1px solid $color-border;
|
|
322
|
-
border-radius: $evo-border-radius-lg;
|
|
323
|
-
padding: 0.25rem 0;
|
|
324
|
-
margin-bottom: 0.75rem;
|
|
325
|
-
|
|
326
|
-
&:last-child {
|
|
327
|
-
margin-bottom: 0;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Empty-state row should look like a single full-width card, not
|
|
331
|
-
// a normal data row with internal padding.
|
|
332
|
-
&.emptyRow {
|
|
333
|
-
padding: 0;
|
|
334
|
-
margin-bottom: 0;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
.td {
|
|
339
|
-
display: flex;
|
|
340
|
-
align-items: center;
|
|
341
|
-
justify-content: space-between;
|
|
342
|
-
gap: 1rem;
|
|
343
|
-
padding: 0.625rem 1rem;
|
|
344
|
-
border-bottom: 1px dashed $color-border-subtle;
|
|
345
|
-
text-align: right;
|
|
346
|
-
|
|
347
|
-
&:last-child {
|
|
348
|
-
border-bottom: 0;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
&::before {
|
|
352
|
-
content: attr(data-label);
|
|
353
|
-
font-size: $text-xs;
|
|
354
|
-
font-weight: 600;
|
|
355
|
-
color: $color-text-secondary;
|
|
356
|
-
letter-spacing: 0.02em;
|
|
357
|
-
text-align: left;
|
|
358
|
-
flex-shrink: 0;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// Vertical dividers don't apply in stack mode.
|
|
363
|
-
&.bordered .td:not(:last-child) {
|
|
364
|
-
border-right: 0;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// Reset stripe/hover on the card layout — each row is its own card.
|
|
368
|
-
&.striped .tbody .tr:nth-child(even),
|
|
369
|
-
&.hoverable .tbody .tr:hover {
|
|
370
|
-
background-color: $color-surface-elevated;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// In stack mode the empty cell is the only td in its row.
|
|
374
|
-
// Reset it back to a block so the message stays centred.
|
|
375
|
-
.empty {
|
|
376
|
-
display: block;
|
|
377
|
-
text-align: center;
|
|
378
|
-
padding: 2.5rem 1rem;
|
|
379
|
-
border-bottom: 0;
|
|
380
|
-
|
|
381
|
-
&::before {
|
|
382
|
-
content: none;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
1
|
+
@use './base/variables' as *;
|
|
2
|
+
@use './base/color' as *;
|
|
3
|
+
|
|
4
|
+
// ==========================================================
|
|
5
|
+
// EVO-UI TABLE
|
|
6
|
+
// ----------------------------------------------------------
|
|
7
|
+
// A lightweight, theme-aware data table.
|
|
8
|
+
// - Horizontal rules only — no busy vertical grid lines.
|
|
9
|
+
// - Density variants (sm/md/lg) tune padding + type scale.
|
|
10
|
+
// - Sticky headers, striped rows, sortable columns, and a
|
|
11
|
+
// loading skeleton state — all opt-in.
|
|
12
|
+
// - Two responsive modes for narrow viewports:
|
|
13
|
+
// `scroll` — thin overflow scrollbar
|
|
14
|
+
// `stack` — rows collapse into labelled cards
|
|
15
|
+
// ==========================================================
|
|
16
|
+
|
|
17
|
+
.wrapper {
|
|
18
|
+
width: 100%;
|
|
19
|
+
background-color: $color-surface-elevated;
|
|
20
|
+
border: 1px solid $color-border;
|
|
21
|
+
border-radius: $evo-border-radius-lg;
|
|
22
|
+
font-family: $font-sans;
|
|
23
|
+
color: $color-text-primary;
|
|
24
|
+
// Clip rounded corners against the inner scroll container.
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.scroll {
|
|
29
|
+
width: 100%;
|
|
30
|
+
overflow-x: auto;
|
|
31
|
+
-webkit-overflow-scrolling: touch;
|
|
32
|
+
scrollbar-color: $color-border-strong transparent;
|
|
33
|
+
scrollbar-width: thin;
|
|
34
|
+
|
|
35
|
+
&::-webkit-scrollbar {
|
|
36
|
+
height: 8px;
|
|
37
|
+
width: 8px;
|
|
38
|
+
}
|
|
39
|
+
&::-webkit-scrollbar-thumb {
|
|
40
|
+
background: $color-border-strong;
|
|
41
|
+
border-radius: $radius-full;
|
|
42
|
+
}
|
|
43
|
+
&::-webkit-scrollbar-track {
|
|
44
|
+
background: transparent;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.table {
|
|
49
|
+
width: 100%;
|
|
50
|
+
border-collapse: separate;
|
|
51
|
+
border-spacing: 0;
|
|
52
|
+
font-size: $text-sm;
|
|
53
|
+
font-variant-numeric: tabular-nums;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.caption {
|
|
57
|
+
caption-side: top;
|
|
58
|
+
text-align: left;
|
|
59
|
+
padding: 0.75rem 1rem 0;
|
|
60
|
+
color: $color-text-secondary;
|
|
61
|
+
font-size: $text-xs;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ----- Header --------------------------------------------------
|
|
65
|
+
.thead {
|
|
66
|
+
background-color: $color-surface-sunken;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.th {
|
|
70
|
+
padding: 0.625rem 1rem;
|
|
71
|
+
text-align: left;
|
|
72
|
+
font-size: $text-xs;
|
|
73
|
+
font-weight: 600;
|
|
74
|
+
color: $color-text-secondary;
|
|
75
|
+
white-space: nowrap;
|
|
76
|
+
border-bottom: 1px solid $color-border;
|
|
77
|
+
vertical-align: middle;
|
|
78
|
+
letter-spacing: 0.01em;
|
|
79
|
+
user-select: none;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.sortBtn {
|
|
83
|
+
display: inline-flex;
|
|
84
|
+
align-items: center;
|
|
85
|
+
gap: 0.375rem;
|
|
86
|
+
background: transparent;
|
|
87
|
+
border: 0;
|
|
88
|
+
padding: 0;
|
|
89
|
+
margin: 0;
|
|
90
|
+
font: inherit;
|
|
91
|
+
color: inherit;
|
|
92
|
+
cursor: pointer;
|
|
93
|
+
border-radius: $radius-sm;
|
|
94
|
+
transition: color $transition-fast;
|
|
95
|
+
|
|
96
|
+
&:hover {
|
|
97
|
+
color: $color-text-primary;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
&:focus-visible {
|
|
101
|
+
outline: 2px solid $evo-primary-focus;
|
|
102
|
+
outline-offset: 2px;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.sortIcon {
|
|
107
|
+
display: inline-flex;
|
|
108
|
+
color: $color-text-muted;
|
|
109
|
+
flex-shrink: 0;
|
|
110
|
+
transition: color $transition-fast;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.sortActive {
|
|
114
|
+
color: $color-text-primary;
|
|
115
|
+
|
|
116
|
+
.sortIcon {
|
|
117
|
+
color: $evo-primary-color;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ----- Body ----------------------------------------------------
|
|
122
|
+
.tbody {
|
|
123
|
+
.tr {
|
|
124
|
+
transition: background-color $transition-fast;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.td {
|
|
129
|
+
padding: 0.75rem 1rem;
|
|
130
|
+
color: $color-text-primary;
|
|
131
|
+
vertical-align: middle;
|
|
132
|
+
border-bottom: 1px solid $color-border-subtle;
|
|
133
|
+
text-align: left;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Drop the last row border so it tucks cleanly into the rounded wrapper.
|
|
137
|
+
.tbody .tr:last-child .td {
|
|
138
|
+
border-bottom: 0;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ----- Alignment ----------------------------------------------
|
|
142
|
+
.align-left {
|
|
143
|
+
text-align: left;
|
|
144
|
+
}
|
|
145
|
+
.align-center {
|
|
146
|
+
text-align: center;
|
|
147
|
+
}
|
|
148
|
+
.align-right {
|
|
149
|
+
text-align: right;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Sort buttons are inline-flex — `text-align` doesn't reach them.
|
|
153
|
+
.align-center .sortBtn {
|
|
154
|
+
width: 100%;
|
|
155
|
+
justify-content: center;
|
|
156
|
+
}
|
|
157
|
+
.align-right .sortBtn {
|
|
158
|
+
width: 100%;
|
|
159
|
+
justify-content: flex-end;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ----- Density -------------------------------------------------
|
|
163
|
+
.size-sm {
|
|
164
|
+
.table {
|
|
165
|
+
font-size: $text-xs;
|
|
166
|
+
}
|
|
167
|
+
.th {
|
|
168
|
+
padding: 0.375rem 0.75rem;
|
|
169
|
+
}
|
|
170
|
+
.td {
|
|
171
|
+
padding: 0.5rem 0.75rem;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.size-md {
|
|
176
|
+
.table {
|
|
177
|
+
font-size: $text-sm;
|
|
178
|
+
}
|
|
179
|
+
.th {
|
|
180
|
+
padding: 0.625rem 1rem;
|
|
181
|
+
}
|
|
182
|
+
.td {
|
|
183
|
+
padding: 0.75rem 1rem;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.size-lg {
|
|
188
|
+
.table {
|
|
189
|
+
font-size: $text-base;
|
|
190
|
+
}
|
|
191
|
+
.th {
|
|
192
|
+
padding: 0.875rem 1.25rem;
|
|
193
|
+
}
|
|
194
|
+
.td {
|
|
195
|
+
padding: 1rem 1.25rem;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ----- Modifiers ----------------------------------------------
|
|
200
|
+
.hoverable .tbody .tr:hover {
|
|
201
|
+
background-color: $color-surface-hover;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.striped .tbody .tr:nth-child(even) {
|
|
205
|
+
background-color: $color-surface-sunken;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Hover wins over stripe.
|
|
209
|
+
.striped.hoverable .tbody .tr:nth-child(even):hover {
|
|
210
|
+
background-color: $color-surface-hover;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.bordered {
|
|
214
|
+
.th,
|
|
215
|
+
.td {
|
|
216
|
+
&:not(:last-child) {
|
|
217
|
+
border-right: 1px solid $color-border-subtle;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.stickyHeader {
|
|
223
|
+
.scroll {
|
|
224
|
+
max-height: 70vh;
|
|
225
|
+
overflow-y: auto;
|
|
226
|
+
}
|
|
227
|
+
.thead .th {
|
|
228
|
+
position: sticky;
|
|
229
|
+
top: 0;
|
|
230
|
+
z-index: 2;
|
|
231
|
+
background-color: $color-surface-sunken;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.clickable .tbody .tr {
|
|
236
|
+
cursor: pointer;
|
|
237
|
+
|
|
238
|
+
&:active {
|
|
239
|
+
background-color: $color-surface-active;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ----- Empty + Skeleton ---------------------------------------
|
|
244
|
+
.empty {
|
|
245
|
+
padding: 3rem 1.5rem;
|
|
246
|
+
text-align: center;
|
|
247
|
+
color: $color-text-muted;
|
|
248
|
+
font-size: $text-sm;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.emptyText {
|
|
252
|
+
display: inline-block;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.skeleton {
|
|
256
|
+
display: block;
|
|
257
|
+
height: 0.75rem;
|
|
258
|
+
width: 70%;
|
|
259
|
+
border-radius: $radius-sm;
|
|
260
|
+
background: linear-gradient(
|
|
261
|
+
90deg,
|
|
262
|
+
$color-skeleton-base 0%,
|
|
263
|
+
$color-skeleton-highlight 50%,
|
|
264
|
+
$color-skeleton-base 100%
|
|
265
|
+
);
|
|
266
|
+
background-size: 200% 100%;
|
|
267
|
+
animation: evoTableShimmer 1.4s ease-in-out infinite;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
@keyframes evoTableShimmer {
|
|
271
|
+
0% {
|
|
272
|
+
background-position: 200% 0;
|
|
273
|
+
}
|
|
274
|
+
100% {
|
|
275
|
+
background-position: -200% 0;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
@media (prefers-reduced-motion: reduce) {
|
|
280
|
+
.skeleton {
|
|
281
|
+
animation: none;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// ----- Responsive: stack mode ---------------------------------
|
|
286
|
+
// Below ~640px, transform rows into vertical "cards" where each
|
|
287
|
+
// cell becomes a labelled row. The visual header is removed
|
|
288
|
+
// (kept in DOM, hidden visually, for screen readers).
|
|
289
|
+
.responsiveStack {
|
|
290
|
+
@media (max-width: 640px) {
|
|
291
|
+
border: 0;
|
|
292
|
+
background: transparent;
|
|
293
|
+
overflow: visible;
|
|
294
|
+
|
|
295
|
+
.scroll {
|
|
296
|
+
overflow: visible;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.table,
|
|
300
|
+
.tbody,
|
|
301
|
+
.tr {
|
|
302
|
+
display: block;
|
|
303
|
+
width: 100%;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.thead {
|
|
307
|
+
// Screen-reader-only — keeps semantics while removing visuals.
|
|
308
|
+
position: absolute;
|
|
309
|
+
width: 1px;
|
|
310
|
+
height: 1px;
|
|
311
|
+
padding: 0;
|
|
312
|
+
margin: -1px;
|
|
313
|
+
overflow: hidden;
|
|
314
|
+
clip: rect(0, 0, 0, 0);
|
|
315
|
+
white-space: nowrap;
|
|
316
|
+
border: 0;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.tbody .tr {
|
|
320
|
+
background-color: $color-surface-elevated;
|
|
321
|
+
border: 1px solid $color-border;
|
|
322
|
+
border-radius: $evo-border-radius-lg;
|
|
323
|
+
padding: 0.25rem 0;
|
|
324
|
+
margin-bottom: 0.75rem;
|
|
325
|
+
|
|
326
|
+
&:last-child {
|
|
327
|
+
margin-bottom: 0;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Empty-state row should look like a single full-width card, not
|
|
331
|
+
// a normal data row with internal padding.
|
|
332
|
+
&.emptyRow {
|
|
333
|
+
padding: 0;
|
|
334
|
+
margin-bottom: 0;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.td {
|
|
339
|
+
display: flex;
|
|
340
|
+
align-items: center;
|
|
341
|
+
justify-content: space-between;
|
|
342
|
+
gap: 1rem;
|
|
343
|
+
padding: 0.625rem 1rem;
|
|
344
|
+
border-bottom: 1px dashed $color-border-subtle;
|
|
345
|
+
text-align: right;
|
|
346
|
+
|
|
347
|
+
&:last-child {
|
|
348
|
+
border-bottom: 0;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
&::before {
|
|
352
|
+
content: attr(data-label);
|
|
353
|
+
font-size: $text-xs;
|
|
354
|
+
font-weight: 600;
|
|
355
|
+
color: $color-text-secondary;
|
|
356
|
+
letter-spacing: 0.02em;
|
|
357
|
+
text-align: left;
|
|
358
|
+
flex-shrink: 0;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Vertical dividers don't apply in stack mode.
|
|
363
|
+
&.bordered .td:not(:last-child) {
|
|
364
|
+
border-right: 0;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Reset stripe/hover on the card layout — each row is its own card.
|
|
368
|
+
&.striped .tbody .tr:nth-child(even),
|
|
369
|
+
&.hoverable .tbody .tr:hover {
|
|
370
|
+
background-color: $color-surface-elevated;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// In stack mode the empty cell is the only td in its row.
|
|
374
|
+
// Reset it back to a block so the message stays centred.
|
|
375
|
+
.empty {
|
|
376
|
+
display: block;
|
|
377
|
+
text-align: center;
|
|
378
|
+
padding: 2.5rem 1rem;
|
|
379
|
+
border-bottom: 0;
|
|
380
|
+
|
|
381
|
+
&::before {
|
|
382
|
+
content: none;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|