@xeplr/ui-table 1.0.0 → 1.0.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.
@@ -1,10 +1,19 @@
1
+ /* Uses @xeplr/ui-account's --xeplr-* theme tokens when available (apply
2
+ .xeplr-theme-light/-dark on an ancestor — see xeplr-ui-account/src/designs/
3
+ theme.css); falls back to this file's original dark palette otherwise.
4
+ (Previously this had a `prefers-color-scheme: light` media block PLUS a
5
+ trailing hardcoded-dark "gold accent" override block that always won the
6
+ cascade regardless of the media query or the app's own theme class — both
7
+ removed in favor of one token-driven system that actually respects
8
+ whatever theme the app explicitly sets.) */
9
+
1
10
  /* ── Container ── */
2
11
  .xeplr-table-container {
3
12
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
4
13
  font-size: 14px;
5
- color: #e0e0e0;
6
- background: #1a1a2e;
7
- border: 1px solid #2a2a4a;
14
+ color: var(--xeplr-text-primary, #e0e0e0);
15
+ background: var(--xeplr-bg-tertiary, #1a1a2e);
16
+ border: 1px solid var(--xeplr-border-primary, #2a2a4a);
8
17
  border-radius: 8px;
9
18
  overflow: hidden;
10
19
  }
@@ -12,25 +21,28 @@
12
21
  /* ── Toolbar ── */
13
22
  .xeplr-table-toolbar {
14
23
  display: flex;
24
+ /* Centred so arbitrary host content in the leading slot sits on the same
25
+ line as the buttons instead of stretching to the row's full height. */
26
+ align-items: center;
15
27
  gap: 8px;
16
28
  padding: 8px 12px;
17
- border-bottom: 1px solid #2a2a4a;
18
- background: #16162a;
29
+ border-bottom: 1px solid var(--xeplr-border-primary, #2a2a4a);
30
+ background: var(--xeplr-bg-secondary, #16162a);
19
31
  }
20
32
 
21
33
  .xeplr-table-toolbar-btn {
22
34
  padding: 4px 12px;
23
- border: 1px solid #3a3a5a;
35
+ border: 1px solid var(--xeplr-border-secondary, #3a3a5a);
24
36
  border-radius: 4px;
25
37
  background: transparent;
26
- color: #a0a0c0;
38
+ color: var(--xeplr-text-secondary, #a0a0c0);
27
39
  cursor: pointer;
28
40
  font-size: 12px;
29
41
  }
30
42
 
31
43
  .xeplr-table-toolbar-btn:hover {
32
- background: #2a2a4a;
33
- color: #e0e0e0;
44
+ background: var(--xeplr-bg-hover, #2a2a4a);
45
+ color: var(--xeplr-text-primary, #e0e0e0);
34
46
  }
35
47
 
36
48
  /* ── Scroll wrapper ── */
@@ -45,14 +57,147 @@
45
57
  table-layout: auto;
46
58
  }
47
59
 
60
+ /* ── Content sizing (columnSizing="content") ──
61
+ Everything here is scoped to .xeplr-table-sized, so the default fill-the-
62
+ container behaviour is untouched for tables that don't opt in.
63
+
64
+ `fixed` is what makes the measured widths binding — under `auto` the
65
+ browser re-negotiates them against the content and the colgroup becomes a
66
+ suggestion. Wrapping is the trade for that: a column short of its natural
67
+ width has to put the overflow somewhere, and wrapped text stays readable
68
+ where a truncated cell just hides data. `anywhere` is the last resort for a
69
+ single unbreakable token wider than its whole column. */
70
+ .xeplr-table-sized {
71
+ table-layout: fixed;
72
+ }
73
+
74
+ .xeplr-table-sized .xeplr-table-th {
75
+ white-space: normal;
76
+ }
77
+
78
+ .xeplr-table-sized .xeplr-table-td,
79
+ .xeplr-table-sized .xeplr-table-header-label {
80
+ overflow-wrap: anywhere;
81
+ }
82
+
83
+ /* ── Styled tables (cellStyle) ──
84
+ Separated borders, on purpose. Under the default `collapse`, adjacent cells
85
+ share one border and CSS picks the winner by width, then style — so a thin
86
+ border set on one cell next to a thicker neighbour never appears at all.
87
+ Per-side control would be dishonest: you'd set it, see nothing, and
88
+ reasonably call it broken.
89
+
90
+ `separate` with zero spacing renders identically to today for the default
91
+ borders (only bottoms are set, and horizontal neighbours don't share those),
92
+ but every border a user sets now actually draws. The trade is that two
93
+ adjacent cells each carrying a border on the SAME shared edge will show 2px
94
+ where collapse would have merged to 1px — style one side rather than all
95
+ four and it doesn't arise. */
96
+ .xeplr-table-styled {
97
+ border-collapse: separate;
98
+ border-spacing: 0;
99
+ }
100
+
101
+ /* ── Cell zoom (cellZoom) ──
102
+ Sized in em so it scales off whatever font the cell itself is using: a
103
+ compact theme's 11px cell zooms proportionally, rather than to some fixed
104
+ size that would be a huge jump from one table and barely a change in
105
+ another.
106
+
107
+ No cursor change on a zoomable cell, deliberately: a magnifier cursor
108
+ obscures the very text you're trying to aim at, which is backwards for a
109
+ reading aid. The plain arrow stays, so you can point precisely. */
110
+ .xeplr-table-cell-zoom {
111
+ position: fixed;
112
+ z-index: 300;
113
+ max-width: min(560px, 90vw);
114
+ max-height: 60vh;
115
+ overflow: auto;
116
+ padding: 12px 16px;
117
+ border-radius: 10px;
118
+ background: var(--xeplr-bg-secondary, #16162a);
119
+ border: 1px solid var(--xeplr-border-primary, #2a2a4a);
120
+ box-shadow: 0 12px 32px -8px rgba(0, 0, 0, .45);
121
+ /* Selectable on purpose — reading it is the point, and copying it out is
122
+ the next thing anyone wants to do. */
123
+ user-select: text;
124
+ }
125
+
126
+ .xeplr-table-cell-zoom:focus {
127
+ outline: none;
128
+ }
129
+
130
+ .xeplr-table-cell-zoom-label {
131
+ font-size: .75em;
132
+ text-transform: uppercase;
133
+ letter-spacing: .05em;
134
+ opacity: .6;
135
+ margin-bottom: 6px;
136
+ }
137
+
138
+ .xeplr-table-cell-zoom-value {
139
+ font-size: 1.9em;
140
+ line-height: 1.35;
141
+ overflow-wrap: anywhere;
142
+ }
143
+
48
144
  /* ── Header ── */
49
145
  .xeplr-table-th {
50
146
  padding: 0;
51
- background: #16162a;
52
- border-bottom: 2px solid #2a2a4a;
147
+ background: var(--xeplr-bg-secondary, #16162a);
148
+ border-bottom: 2px solid var(--xeplr-border-primary, #2a2a4a);
149
+ /* Thin by default between every header cell — a grouped table (a pivoted
150
+ date over several measures) reads as one solid block without SOME line
151
+ between its own columns, not just at the group's outer edge. */
152
+ border-right: 1px solid var(--xeplr-border-secondary, #2a2a4a);
53
153
  text-align: left;
54
154
  font-weight: 600;
55
155
  white-space: nowrap;
156
+ color: var(--xeplr-text-secondary, inherit);
157
+ }
158
+
159
+ /* A darkened version of the SAME light-gray line already drawn everywhere
160
+ else in this table (--xeplr-border-secondary), not a separate color —
161
+ the group boundary is meant to read as "more of this table's own grid,"
162
+ not as a different, unrelated UI element sitting on top of it. */
163
+ .xeplr-table-th-group,
164
+ .xeplr-table-th-group-start,
165
+ .xeplr-table-th-group-end,
166
+ .xeplr-table-td-group-start,
167
+ .xeplr-table-td-group-end {
168
+ --xeplr-table-group-border: #f1eaea;
169
+ }
170
+
171
+ /* The spanning cell itself (the date, not the measures under it) — centered
172
+ over what it covers, the way a merged cell reads in Excel. Top border
173
+ closes the frame's roof. */
174
+ .xeplr-table-th-group .xeplr-table-header-cell {
175
+ justify-content: center;
176
+ }
177
+ .xeplr-table-th-group {
178
+ text-align: center;
179
+ border-top: 2px solid var(--xeplr-table-group-border);
180
+ }
181
+
182
+ /* Every header cell in a row that ISN'T the last one gets the divider under
183
+ it — a real group (the date) AND a plain column beside it (Category Name)
184
+ alike — so the line drawn under "2025-05-01" runs the full width of the
185
+ header instead of stopping wherever a non-grouped column happens to sit. */
186
+ .xeplr-table-th-row-divider {
187
+ border-bottom: 1px solid var(--xeplr-border-secondary, #ccc);
188
+ }
189
+
190
+ /* The frame's sides — one continuous line from the group's own header cell,
191
+ down through the measure-label row, down through every data row, so the
192
+ whole block reads as one unit instead of columns that happen to sit next
193
+ to each other. */
194
+ .xeplr-table-th-group-start,
195
+ .xeplr-table-td-group-start {
196
+ border-left: 2px solid var(--xeplr-table-group-border);
197
+ }
198
+ .xeplr-table-th-group-end,
199
+ .xeplr-table-td-group-end {
200
+ border-right: 2px solid var(--xeplr-table-group-border);
56
201
  }
57
202
 
58
203
  .xeplr-table-header-cell {
@@ -72,28 +217,28 @@
72
217
  }
73
218
 
74
219
  .xeplr-table-header-label.sortable:hover {
75
- color: #7c7cff;
220
+ color: var(--xeplr-accent, #7c7cff);
76
221
  }
77
222
 
78
223
  .xeplr-table-sort-icon {
79
224
  font-size: 10px;
80
- color: #7c7cff;
225
+ color: var(--xeplr-accent, #7c7cff);
81
226
  }
82
227
 
83
228
  /* ── Body ── */
84
229
  .xeplr-table-td {
85
230
  padding: 8px 12px;
86
- border-bottom: 1px solid #2a2a4a;
231
+ border-bottom: 1px solid var(--xeplr-border-secondary, #2a2a4a);
87
232
  }
88
233
 
89
234
  .xeplr-table-row:hover {
90
- background: #1e1e3a;
235
+ background: var(--xeplr-bg-hover, #1e1e3a);
91
236
  }
92
237
 
93
238
  .xeplr-table-empty {
94
239
  padding: 24px;
95
240
  text-align: center;
96
- color: #666;
241
+ color: var(--xeplr-text-muted, #666);
97
242
  }
98
243
 
99
244
  /* ── Filter trigger ── */
@@ -112,32 +257,35 @@
112
257
  border: none;
113
258
  border-radius: 4px;
114
259
  background: transparent;
115
- color: #555;
260
+ color: var(--xeplr-text-muted, #555);
116
261
  cursor: pointer;
117
262
  }
118
263
 
119
264
  .xeplr-table-filter-trigger:hover {
120
- background: #2a2a4a;
121
- color: #a0a0c0;
265
+ background: var(--xeplr-bg-hover, #2a2a4a);
266
+ color: var(--xeplr-text-secondary, #a0a0c0);
122
267
  }
123
268
 
124
269
  .xeplr-table-filter-trigger.xeplr-table-filter-active {
125
- color: #7c7cff;
126
- background: #2a2a5a;
270
+ color: var(--xeplr-accent, #7c7cff);
271
+ background: var(--xeplr-bg-active, #2a2a5a);
127
272
  }
128
273
 
129
274
  /* ── Filter panel ── */
275
+ /* PORTALLED — see FilterWrapper. `top`/`left` are set inline from the
276
+ trigger's rect; everything here is appearance only. It sits on document.body
277
+ so no table's `overflow: auto` can clip it. */
130
278
  .xeplr-table-filter-panel {
131
- position: absolute;
132
- top: 100%;
133
- right: 0;
134
- z-index: 100;
279
+ position: fixed;
280
+ z-index: 3000;
135
281
  min-width: 220px;
136
282
  max-width: 300px;
137
- background: #1e1e38;
138
- border: 1px solid #3a3a5a;
283
+ max-height: 60vh;
284
+ overflow: auto;
285
+ background: var(--xeplr-bg-tertiary, #1e1e38);
286
+ border: 1px solid var(--xeplr-border-primary, #3a3a5a);
139
287
  border-radius: 6px;
140
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
288
+ box-shadow: var(--xeplr-shadow-lg, 0 8px 24px rgba(0, 0, 0, 0.4));
141
289
  padding: 8px;
142
290
  margin-top: 4px;
143
291
  }
@@ -148,27 +296,27 @@
148
296
  gap: 6px;
149
297
  margin-top: 8px;
150
298
  padding-top: 8px;
151
- border-top: 1px solid #2a2a4a;
299
+ border-top: 1px solid var(--xeplr-border-secondary, #2a2a4a);
152
300
  }
153
301
 
154
302
  .xeplr-table-filter-clear-btn,
155
303
  .xeplr-table-filter-close-btn {
156
304
  padding: 4px 10px;
157
- border: 1px solid #3a3a5a;
305
+ border: 1px solid var(--xeplr-border-secondary, #3a3a5a);
158
306
  border-radius: 4px;
159
307
  background: transparent;
160
- color: #a0a0c0;
308
+ color: var(--xeplr-text-secondary, #a0a0c0);
161
309
  cursor: pointer;
162
310
  font-size: 12px;
163
311
  }
164
312
 
165
313
  .xeplr-table-filter-close-btn {
166
- background: #3a3a6a;
167
- color: #e0e0e0;
314
+ background: var(--xeplr-accent-muted, #3a3a6a);
315
+ color: var(--xeplr-text-primary, #e0e0e0);
168
316
  }
169
317
 
170
- .xeplr-table-filter-clear-btn:hover { background: #2a2a4a; }
171
- .xeplr-table-filter-close-btn:hover { background: #4a4a7a; }
318
+ .xeplr-table-filter-clear-btn:hover { background: var(--xeplr-bg-hover, #2a2a4a); }
319
+ .xeplr-table-filter-close-btn:hover { background: var(--xeplr-accent-hover, #4a4a7a); }
172
320
 
173
321
  /* ── Shared filter elements ── */
174
322
  .xeplr-table-filter-search,
@@ -177,10 +325,10 @@
177
325
  width: 100%;
178
326
  padding: 6px 8px;
179
327
  margin-bottom: 6px;
180
- border: 1px solid #3a3a5a;
328
+ border: 1px solid var(--xeplr-input-border, #3a3a5a);
181
329
  border-radius: 4px;
182
- background: #141428;
183
- color: #e0e0e0;
330
+ background: var(--xeplr-input-bg, #141428);
331
+ color: var(--xeplr-input-text, #e0e0e0);
184
332
  font-size: 13px;
185
333
  box-sizing: border-box;
186
334
  }
@@ -189,7 +337,7 @@
189
337
  .xeplr-table-filter-input:focus,
190
338
  .xeplr-table-filter-operator:focus {
191
339
  outline: none;
192
- border-color: #7c7cff;
340
+ border-color: var(--xeplr-accent, #7c7cff);
193
341
  }
194
342
 
195
343
  /* ── String filter ── */
@@ -202,16 +350,16 @@
202
350
  .xeplr-table-filter-bulk button {
203
351
  flex: 1;
204
352
  padding: 3px 0;
205
- border: 1px solid #3a3a5a;
353
+ border: 1px solid var(--xeplr-border-secondary, #3a3a5a);
206
354
  border-radius: 3px;
207
355
  background: transparent;
208
- color: #a0a0c0;
356
+ color: var(--xeplr-text-secondary, #a0a0c0);
209
357
  cursor: pointer;
210
358
  font-size: 11px;
211
359
  }
212
360
 
213
361
  .xeplr-table-filter-bulk button:hover {
214
- background: #2a2a4a;
362
+ background: var(--xeplr-bg-hover, #2a2a4a);
215
363
  }
216
364
 
217
365
  .xeplr-table-filter-list {
@@ -231,13 +379,13 @@
231
379
  }
232
380
 
233
381
  .xeplr-table-filter-option:hover {
234
- background: #2a2a4a;
382
+ background: var(--xeplr-bg-hover, #2a2a4a);
235
383
  }
236
384
 
237
385
  .xeplr-table-filter-empty {
238
386
  padding: 8px;
239
387
  text-align: center;
240
- color: #666;
388
+ color: var(--xeplr-text-muted, #666);
241
389
  font-size: 12px;
242
390
  }
243
391
 
@@ -251,22 +399,22 @@
251
399
  .xeplr-table-filter-null-controls button {
252
400
  flex: 1;
253
401
  padding: 4px 0;
254
- border: 1px solid #3a3a5a;
402
+ border: 1px solid var(--xeplr-border-secondary, #3a3a5a);
255
403
  border-radius: 3px;
256
404
  background: transparent;
257
- color: #a0a0c0;
405
+ color: var(--xeplr-text-secondary, #a0a0c0);
258
406
  cursor: pointer;
259
407
  font-size: 11px;
260
408
  }
261
409
 
262
410
  .xeplr-table-filter-null-controls button:hover {
263
- background: #2a2a4a;
411
+ background: var(--xeplr-bg-hover, #2a2a4a);
264
412
  }
265
413
 
266
414
  .xeplr-table-filter-null-controls button.active {
267
- background: #3a3a6a;
268
- color: #7c7cff;
269
- border-color: #7c7cff;
415
+ background: var(--xeplr-accent-muted, #3a3a6a);
416
+ color: var(--xeplr-accent, #7c7cff);
417
+ border-color: var(--xeplr-accent, #7c7cff);
270
418
  }
271
419
 
272
420
  /* ── Boolean filter ── */
@@ -278,22 +426,22 @@
278
426
  .xeplr-table-bool-btn {
279
427
  flex: 1;
280
428
  padding: 6px 0;
281
- border: 1px solid #3a3a5a;
429
+ border: 1px solid var(--xeplr-border-secondary, #3a3a5a);
282
430
  border-radius: 4px;
283
431
  background: transparent;
284
- color: #a0a0c0;
432
+ color: var(--xeplr-text-secondary, #a0a0c0);
285
433
  cursor: pointer;
286
434
  font-size: 13px;
287
435
  }
288
436
 
289
437
  .xeplr-table-bool-btn:hover {
290
- background: #2a2a4a;
438
+ background: var(--xeplr-bg-hover, #2a2a4a);
291
439
  }
292
440
 
293
441
  .xeplr-table-bool-btn.active {
294
- background: #3a3a6a;
295
- color: #7c7cff;
296
- border-color: #7c7cff;
442
+ background: var(--xeplr-accent-muted, #3a3a6a);
443
+ color: var(--xeplr-accent, #7c7cff);
444
+ border-color: var(--xeplr-accent, #7c7cff);
297
445
  }
298
446
 
299
447
  /* ── Pagination ── */
@@ -302,23 +450,23 @@
302
450
  align-items: center;
303
451
  gap: 8px;
304
452
  padding: 8px 12px;
305
- border-top: 1px solid #2a2a4a;
306
- background: #16162a;
453
+ border-top: 1px solid var(--xeplr-border-primary, #2a2a4a);
454
+ background: var(--xeplr-bg-secondary, #16162a);
307
455
  font-size: 13px;
308
456
  }
309
457
 
310
458
  .xeplr-table-pagination button {
311
459
  padding: 4px 8px;
312
- border: 1px solid #3a3a5a;
460
+ border: 1px solid var(--xeplr-border-secondary, #3a3a5a);
313
461
  border-radius: 4px;
314
462
  background: transparent;
315
- color: #a0a0c0;
463
+ color: var(--xeplr-text-secondary, #a0a0c0);
316
464
  cursor: pointer;
317
465
  }
318
466
 
319
467
  .xeplr-table-pagination button:hover:not(:disabled) {
320
- background: #2a2a4a;
321
- color: #e0e0e0;
468
+ background: var(--xeplr-bg-hover, #2a2a4a);
469
+ color: var(--xeplr-text-primary, #e0e0e0);
322
470
  }
323
471
 
324
472
  .xeplr-table-pagination button:disabled {
@@ -327,20 +475,20 @@
327
475
  }
328
476
 
329
477
  .xeplr-table-page-info {
330
- color: #a0a0c0;
478
+ color: var(--xeplr-text-secondary, #a0a0c0);
331
479
  }
332
480
 
333
481
  .xeplr-table-page-size {
334
482
  padding: 3px 6px;
335
- border: 1px solid #3a3a5a;
483
+ border: 1px solid var(--xeplr-input-border, #3a3a5a);
336
484
  border-radius: 4px;
337
- background: #141428;
338
- color: #e0e0e0;
485
+ background: var(--xeplr-input-bg, #141428);
486
+ color: var(--xeplr-input-text, #e0e0e0);
339
487
  font-size: 12px;
340
488
  }
341
489
 
342
490
  .xeplr-table-row-count {
343
- color: #666;
491
+ color: var(--xeplr-text-muted, #666);
344
492
  margin-left: auto;
345
493
  }
346
494
 
@@ -354,7 +502,7 @@
354
502
  }
355
503
 
356
504
  .xeplr-table-filter-list::-webkit-scrollbar-thumb {
357
- background: #3a3a5a;
505
+ background: var(--xeplr-border-secondary, #3a3a5a);
358
506
  border-radius: 3px;
359
507
  }
360
508
 
@@ -376,26 +524,26 @@
376
524
  border: none;
377
525
  border-radius: 4px;
378
526
  background: transparent;
379
- color: #666;
527
+ color: var(--xeplr-text-muted, #666);
380
528
  cursor: pointer;
381
529
  font-size: 12px;
382
530
  transition: transform 0.15s;
383
531
  }
384
532
 
385
533
  .xeplr-table-expand-btn:hover {
386
- background: #2a2a4a;
387
- color: #a0a0c0;
534
+ background: var(--xeplr-bg-hover, #2a2a4a);
535
+ color: var(--xeplr-text-secondary, #a0a0c0);
388
536
  }
389
537
 
390
538
  .xeplr-table-expand-btn.expanded {
391
539
  transform: rotate(90deg);
392
- color: #7c7cff;
540
+ color: var(--xeplr-accent, #7c7cff);
393
541
  }
394
542
 
395
543
  /* ── Expanded child row ── */
396
544
  .xeplr-table-row-expanded > td {
397
545
  padding: 0;
398
- background: #141428;
546
+ background: var(--xeplr-bg-secondary, #141428);
399
547
  }
400
548
 
401
549
  .xeplr-table-td-expanded {
@@ -404,7 +552,7 @@
404
552
 
405
553
  .xeplr-table-child-container {
406
554
  padding: 12px 16px 12px 48px;
407
- border-bottom: 2px solid #2a2a4a;
555
+ border-bottom: 2px solid var(--xeplr-border-primary, #2a2a4a);
408
556
  }
409
557
 
410
558
  .xeplr-table-child-header {
@@ -417,7 +565,7 @@
417
565
  .xeplr-table-child-title {
418
566
  font-size: 13px;
419
567
  font-weight: 600;
420
- color: #a0a0c0;
568
+ color: var(--xeplr-text-secondary, #a0a0c0);
421
569
  text-transform: uppercase;
422
570
  letter-spacing: 0.5px;
423
571
  }
@@ -428,7 +576,7 @@
428
576
  }
429
577
 
430
578
  .xeplr-table-child {
431
- border: 1px solid #2a2a4a;
579
+ border: 1px solid var(--xeplr-border-primary, #2a2a4a);
432
580
  border-radius: 6px;
433
581
  overflow: hidden;
434
582
  }
@@ -439,23 +587,23 @@
439
587
  }
440
588
 
441
589
  .xeplr-table-toolbar-btn-add {
442
- color: #7c7cff;
443
- border-color: #7c7cff;
590
+ color: var(--xeplr-accent, #7c7cff);
591
+ border-color: var(--xeplr-accent, #7c7cff);
444
592
  }
445
593
 
446
594
  .xeplr-table-toolbar-btn-add:hover {
447
- background: #2a2a5a;
448
- color: #9d9dff;
595
+ background: var(--xeplr-bg-active, #2a2a5a);
596
+ color: var(--xeplr-accent-hover, #9d9dff);
449
597
  }
450
598
 
451
599
  .xeplr-table-toolbar-btn-delete {
452
- color: #ff6b6b;
453
- border-color: #ff6b6b;
600
+ color: var(--xeplr-danger, #ff6b6b);
601
+ border-color: var(--xeplr-danger, #ff6b6b);
454
602
  }
455
603
 
456
604
  .xeplr-table-toolbar-btn-delete:hover {
457
- background: #3a1a1a;
458
- color: #ff8a8a;
605
+ background: var(--xeplr-danger-bg, #3a1a1a);
606
+ color: var(--xeplr-danger, #ff8a8a);
459
607
  }
460
608
 
461
609
  .xeplr-table-toolbar-btn-delete:disabled {
@@ -471,13 +619,13 @@
471
619
  }
472
620
 
473
621
  .xeplr-table-toolbar-btn-commit {
474
- color: #66bb6a;
475
- border-color: #66bb6a;
622
+ color: var(--xeplr-success, #66bb6a);
623
+ border-color: var(--xeplr-success, #66bb6a);
476
624
  }
477
625
 
478
626
  .xeplr-table-toolbar-btn-commit:hover {
479
- background: #1a3a1a;
480
- color: #81c784;
627
+ background: var(--xeplr-success-bg, #1a3a1a);
628
+ color: var(--xeplr-success, #81c784);
481
629
  }
482
630
 
483
631
  .xeplr-table-toolbar-btn-commit:disabled {
@@ -486,13 +634,13 @@
486
634
  }
487
635
 
488
636
  .xeplr-table-toolbar-btn-discard {
489
- color: #ff9800;
490
- border-color: #ff9800;
637
+ color: var(--xeplr-warning, #ff9800);
638
+ border-color: var(--xeplr-warning, #ff9800);
491
639
  }
492
640
 
493
641
  .xeplr-table-toolbar-btn-discard:hover {
494
- background: #3a2a0a;
495
- color: #ffb74d;
642
+ background: var(--xeplr-warning-bg, #3a2a0a);
643
+ color: var(--xeplr-warning, #ffb74d);
496
644
  }
497
645
 
498
646
  .xeplr-table-toolbar-btn-discard:disabled {
@@ -502,11 +650,11 @@
502
650
 
503
651
  /* ── Row status indicators ── */
504
652
  .xeplr-table-row-new {
505
- border-left: 3px solid #66bb6a;
653
+ border-left: 3px solid var(--xeplr-success, #66bb6a);
506
654
  }
507
655
 
508
656
  .xeplr-table-row-edited {
509
- border-left: 3px solid #ffc107;
657
+ border-left: 3px solid var(--xeplr-warning, #ffc107);
510
658
  }
511
659
 
512
660
  /* ── Checkbox column ── */
@@ -520,11 +668,11 @@
520
668
  width: 16px;
521
669
  height: 16px;
522
670
  cursor: pointer;
523
- accent-color: #7c7cff;
671
+ accent-color: var(--xeplr-accent, #7c7cff);
524
672
  }
525
673
 
526
674
  .xeplr-table-row-selected {
527
- background: #1e1e3a;
675
+ background: var(--xeplr-bg-active, #1e1e3a);
528
676
  }
529
677
 
530
678
  /* ── Actions column ── */
@@ -553,19 +701,44 @@
553
701
  border: 1px solid transparent;
554
702
  border-radius: 4px;
555
703
  background: transparent;
556
- color: #666;
704
+ color: var(--xeplr-text-muted, #666);
557
705
  cursor: pointer;
558
706
  }
559
707
 
560
708
  .xeplr-table-action-btn:hover {
561
- border-color: #3a3a5a;
562
- background: #2a2a4a;
709
+ border-color: var(--xeplr-border-secondary, #3a3a5a);
710
+ background: var(--xeplr-bg-hover, #2a2a4a);
711
+ }
712
+
713
+ .xeplr-table-action-view:hover { color: var(--xeplr-accent, #7c7cff); }
714
+ .xeplr-table-action-copy:hover { color: var(--xeplr-text-secondary, #a0a0c0); }
715
+ .xeplr-table-action-edit:hover { color: var(--xeplr-warning, #ffc107); }
716
+ .xeplr-table-action-delete:hover { color: var(--xeplr-danger, #ff6b6b); }
717
+
718
+ .xeplr-table-action-btn:disabled {
719
+ opacity: 0.5;
720
+ cursor: not-allowed;
721
+ }
722
+
723
+ /* ── Custom row actions (props.rowActions) — text-label buttons, e.g. Rollback/Delete ── */
724
+ .xeplr-table-action-label {
725
+ width: auto;
726
+ height: auto;
727
+ padding: 4px 10px;
728
+ font-size: 12px;
729
+ font-weight: 600;
730
+ white-space: nowrap;
563
731
  }
564
732
 
565
- .xeplr-table-action-view:hover { color: #7c7cff; }
566
- .xeplr-table-action-copy:hover { color: #a0a0c0; }
567
- .xeplr-table-action-edit:hover { color: #ffc107; }
568
- .xeplr-table-action-delete:hover { color: #ff6b6b; }
733
+ .xeplr-table-action-danger {
734
+ border-color: var(--xeplr-danger, #ff6b6b);
735
+ color: var(--xeplr-danger, #ff6b6b);
736
+ }
737
+
738
+ .xeplr-table-action-danger:hover:not(:disabled) {
739
+ background: var(--xeplr-danger-bg, #3a1a1a);
740
+ color: var(--xeplr-danger, #ff8a8a);
741
+ }
569
742
 
570
743
  /* ── Modal overlay ── */
571
744
  .xeplr-table-modal-overlay {
@@ -578,7 +751,7 @@
578
751
  display: flex;
579
752
  align-items: center;
580
753
  justify-content: center;
581
- background: rgba(0, 0, 0, 0.6);
754
+ background: var(--xeplr-bg-overlay, rgba(0, 0, 0, 0.6));
582
755
  }
583
756
 
584
757
  .xeplr-table-modal {
@@ -587,10 +760,10 @@
587
760
  max-height: 85vh;
588
761
  display: flex;
589
762
  flex-direction: column;
590
- background: #1e1e38;
591
- border: 1px solid #3a3a5a;
763
+ background: var(--xeplr-bg-tertiary, #1e1e38);
764
+ border: 1px solid var(--xeplr-border-primary, #3a3a5a);
592
765
  border-radius: 10px;
593
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
766
+ box-shadow: var(--xeplr-shadow-lg, 0 12px 40px rgba(0, 0, 0, 0.5));
594
767
  }
595
768
 
596
769
  .xeplr-table-modal-header {
@@ -598,13 +771,13 @@
598
771
  align-items: center;
599
772
  justify-content: space-between;
600
773
  padding: 14px 20px;
601
- border-bottom: 1px solid #2a2a4a;
774
+ border-bottom: 1px solid var(--xeplr-border-secondary, #2a2a4a);
602
775
  }
603
776
 
604
777
  .xeplr-table-modal-title {
605
778
  font-size: 16px;
606
779
  font-weight: 600;
607
- color: #e0e0e0;
780
+ color: var(--xeplr-text-primary, #e0e0e0);
608
781
  }
609
782
 
610
783
  .xeplr-table-modal-close {
@@ -617,13 +790,13 @@
617
790
  border: none;
618
791
  border-radius: 4px;
619
792
  background: transparent;
620
- color: #666;
793
+ color: var(--xeplr-text-muted, #666);
621
794
  cursor: pointer;
622
795
  }
623
796
 
624
797
  .xeplr-table-modal-close:hover {
625
- background: #2a2a4a;
626
- color: #e0e0e0;
798
+ background: var(--xeplr-bg-hover, #2a2a4a);
799
+ color: var(--xeplr-text-primary, #e0e0e0);
627
800
  }
628
801
 
629
802
  .xeplr-table-modal-body {
@@ -641,7 +814,7 @@
641
814
  margin-bottom: 4px;
642
815
  font-size: 12px;
643
816
  font-weight: 600;
644
- color: #a0a0c0;
817
+ color: var(--xeplr-text-secondary, #a0a0c0);
645
818
  text-transform: uppercase;
646
819
  letter-spacing: 0.5px;
647
820
  }
@@ -652,8 +825,8 @@
652
825
  padding: 1px 5px;
653
826
  font-size: 9px;
654
827
  font-weight: 700;
655
- color: #7c7cff;
656
- border: 1px solid #7c7cff;
828
+ color: var(--xeplr-accent, #7c7cff);
829
+ border: 1px solid var(--xeplr-accent, #7c7cff);
657
830
  border-radius: 3px;
658
831
  vertical-align: middle;
659
832
  text-transform: uppercase;
@@ -662,17 +835,17 @@
662
835
  .xeplr-table-modal-input {
663
836
  width: 100%;
664
837
  padding: 8px 10px;
665
- border: 1px solid #3a3a5a;
838
+ border: 1px solid var(--xeplr-input-border, #3a3a5a);
666
839
  border-radius: 5px;
667
- background: #141428;
668
- color: #e0e0e0;
840
+ background: var(--xeplr-input-bg, #141428);
841
+ color: var(--xeplr-input-text, #e0e0e0);
669
842
  font-size: 14px;
670
843
  box-sizing: border-box;
671
844
  }
672
845
 
673
846
  .xeplr-table-modal-input:focus {
674
847
  outline: none;
675
- border-color: #7c7cff;
848
+ border-color: var(--xeplr-accent, #7c7cff);
676
849
  }
677
850
 
678
851
  .xeplr-table-modal-input:disabled {
@@ -683,7 +856,7 @@
683
856
  .xeplr-table-modal-checkbox {
684
857
  width: 18px;
685
858
  height: 18px;
686
- accent-color: #7c7cff;
859
+ accent-color: var(--xeplr-accent, #7c7cff);
687
860
  }
688
861
 
689
862
  .xeplr-table-modal-footer {
@@ -692,33 +865,33 @@
692
865
  justify-content: flex-end;
693
866
  padding-top: 16px;
694
867
  margin-top: 4px;
695
- border-top: 1px solid #2a2a4a;
868
+ border-top: 1px solid var(--xeplr-border-secondary, #2a2a4a);
696
869
  }
697
870
 
698
871
  .xeplr-table-modal-btn {
699
872
  padding: 8px 18px;
700
- border: 1px solid #3a3a5a;
873
+ border: 1px solid var(--xeplr-border-secondary, #3a3a5a);
701
874
  border-radius: 5px;
702
875
  background: transparent;
703
- color: #a0a0c0;
876
+ color: var(--xeplr-text-secondary, #a0a0c0);
704
877
  cursor: pointer;
705
878
  font-size: 13px;
706
879
  font-weight: 500;
707
880
  }
708
881
 
709
882
  .xeplr-table-modal-btn:hover {
710
- background: #2a2a4a;
711
- color: #e0e0e0;
883
+ background: var(--xeplr-bg-hover, #2a2a4a);
884
+ color: var(--xeplr-text-primary, #e0e0e0);
712
885
  }
713
886
 
714
887
  .xeplr-table-modal-btn-primary {
715
- background: #7c7cff;
716
- color: #fff;
717
- border-color: #7c7cff;
888
+ background: var(--xeplr-accent, #7c7cff);
889
+ color: var(--xeplr-accent-text, #fff);
890
+ border-color: var(--xeplr-accent, #7c7cff);
718
891
  }
719
892
 
720
893
  .xeplr-table-modal-btn-primary:hover {
721
- background: #6a6aee;
894
+ background: var(--xeplr-accent-hover, #6a6aee);
722
895
  }
723
896
 
724
897
  .xeplr-table-modal-btn-primary:disabled {
@@ -732,7 +905,7 @@
732
905
  }
733
906
 
734
907
  .xeplr-table-row-clickable:hover {
735
- background: #1e1e3a;
908
+ background: var(--xeplr-bg-hover, #1e1e3a);
736
909
  }
737
910
 
738
911
  /* ── Detail popup ── */
@@ -742,10 +915,10 @@
742
915
  max-height: 90vh;
743
916
  display: flex;
744
917
  flex-direction: column;
745
- background: #1e1e38;
746
- border: 1px solid #3a3a5a;
918
+ background: var(--xeplr-bg-tertiary, #1e1e38);
919
+ border: 1px solid var(--xeplr-border-primary, #3a3a5a);
747
920
  border-radius: 10px;
748
- box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6);
921
+ box-shadow: var(--xeplr-shadow-lg, 0 16px 48px rgba(0, 0, 0, 0.6));
749
922
  }
750
923
 
751
924
  .xeplr-table-detail-body {
@@ -770,14 +943,14 @@
770
943
  .xeplr-table-detail-label {
771
944
  font-size: 11px;
772
945
  font-weight: 600;
773
- color: #666;
946
+ color: var(--xeplr-text-muted, #666);
774
947
  text-transform: uppercase;
775
948
  letter-spacing: 0.5px;
776
949
  }
777
950
 
778
951
  .xeplr-table-detail-value {
779
952
  font-size: 14px;
780
- color: #e0e0e0;
953
+ color: var(--xeplr-text-primary, #e0e0e0);
781
954
  padding: 6px 0;
782
955
  }
783
956
 
@@ -786,128 +959,101 @@
786
959
  gap: 8px;
787
960
  margin-bottom: 20px;
788
961
  padding-bottom: 16px;
789
- border-bottom: 1px solid #2a2a4a;
962
+ border-bottom: 1px solid var(--xeplr-border-secondary, #2a2a4a);
790
963
  }
791
964
 
792
965
  .xeplr-table-detail-children {
793
966
  margin-top: 8px;
794
967
  }
795
968
 
796
- /* ── Light theme ── */
797
- @media (prefers-color-scheme: light) {
798
- .xeplr-table-container {
799
- color: #333;
800
- background: #fff;
801
- border-color: #e0e0e0;
802
- }
803
-
804
- .xeplr-table-toolbar,
805
- .xeplr-table-th,
806
- .xeplr-table-pagination {
807
- background: #f8f8fa;
808
- }
809
-
810
- .xeplr-table-toolbar { border-bottom-color: #e0e0e0; }
811
- .xeplr-table-th { border-bottom-color: #d0d0d0; }
812
- .xeplr-table-td { border-bottom-color: #eee; }
813
- .xeplr-table-pagination { border-top-color: #e0e0e0; }
814
- .xeplr-table-row:hover { background: #f5f5ff; }
815
-
816
- .xeplr-table-toolbar-btn,
817
- .xeplr-table-filter-clear-btn,
818
- .xeplr-table-pagination button,
819
- .xeplr-table-filter-bulk button,
820
- .xeplr-table-filter-null-controls button,
821
- .xeplr-table-bool-btn {
822
- border-color: #d0d0d0;
823
- color: #666;
824
- }
825
-
826
- .xeplr-table-filter-close-btn {
827
- background: #e8e8f0;
828
- color: #333;
829
- }
830
-
831
- .xeplr-table-filter-panel {
832
- background: #fff;
833
- border-color: #d0d0d0;
834
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
835
- }
836
-
837
- .xeplr-table-filter-search,
838
- .xeplr-table-filter-input,
839
- .xeplr-table-filter-operator,
840
- .xeplr-table-page-size {
841
- background: #f8f8fa;
842
- border-color: #d0d0d0;
843
- color: #333;
844
- }
845
-
846
- .xeplr-table-filter-trigger { color: #bbb; }
847
- .xeplr-table-filter-trigger:hover { background: #f0f0f0; color: #666; }
848
- .xeplr-table-filter-trigger.xeplr-table-filter-active { color: #5555dd; background: #ededff; }
849
-
850
- .xeplr-table-header-label.sortable:hover { color: #5555dd; }
851
- .xeplr-table-sort-icon { color: #5555dd; }
852
-
853
- .xeplr-table-bool-btn.active,
854
- .xeplr-table-filter-null-controls button.active {
855
- background: #ededff;
856
- color: #5555dd;
857
- border-color: #5555dd;
858
- }
859
-
860
- /* Detail popup */
861
- .xeplr-table-detail { background: #fff; border-color: #d0d0d0; box-shadow: 0 16px 48px rgba(0,0,0,0.15); }
862
- .xeplr-table-detail-label { color: #999; }
863
- .xeplr-table-detail-value { color: #333; }
864
- .xeplr-table-detail-actions { border-bottom-color: #e0e0e0; }
865
- .xeplr-table-row-clickable:hover { background: #f5f5ff; }
866
-
867
- /* Expand / child table */
868
- .xeplr-table-expand-btn:hover { background: #f0f0f0; color: #666; }
869
- .xeplr-table-expand-btn.expanded { color: #5555dd; }
870
- .xeplr-table-row-expanded > td { background: #f8f8fa; }
871
- .xeplr-table-child-container { border-bottom-color: #e0e0e0; }
872
- .xeplr-table-child-title { color: #666; }
873
- .xeplr-table-child { border-color: #e0e0e0; }
874
-
875
- /* Commit / discard */
876
- .xeplr-table-toolbar-btn-commit { color: #2e7d32; border-color: #2e7d32; }
877
- .xeplr-table-toolbar-btn-commit:hover { background: #e8f5e9; }
878
- .xeplr-table-toolbar-btn-discard { color: #e65100; border-color: #e65100; }
879
- .xeplr-table-toolbar-btn-discard:hover { background: #fff3e0; }
880
- .xeplr-table-row-new { border-left-color: #2e7d32; }
881
- .xeplr-table-row-edited { border-left-color: #f57f17; }
882
-
883
- /* Actions */
884
- .xeplr-table-toolbar-btn-add { color: #5555dd; border-color: #5555dd; }
885
- .xeplr-table-toolbar-btn-add:hover { background: #ededff; }
886
- .xeplr-table-toolbar-btn-delete { color: #d32f2f; border-color: #d32f2f; }
887
- .xeplr-table-toolbar-btn-delete:hover { background: #ffebee; }
888
-
889
- .xeplr-table-checkbox { accent-color: #5555dd; }
890
- .xeplr-table-row-selected { background: #f5f5ff; }
891
-
892
- .xeplr-table-action-btn:hover { border-color: #d0d0d0; background: #f5f5f5; }
893
- .xeplr-table-action-view:hover { color: #5555dd; }
894
- .xeplr-table-action-edit:hover { color: #f57f17; }
895
- .xeplr-table-action-delete:hover { color: #d32f2f; }
896
-
897
- /* Modal */
898
- .xeplr-table-modal { background: #fff; border-color: #d0d0d0; box-shadow: 0 12px 40px rgba(0,0,0,0.15); }
899
- .xeplr-table-modal-overlay { background: rgba(0,0,0,0.3); }
900
- .xeplr-table-modal-header { border-bottom-color: #e0e0e0; }
901
- .xeplr-table-modal-title { color: #333; }
902
- .xeplr-table-modal-close:hover { background: #f0f0f0; color: #333; }
903
- .xeplr-table-modal-label { color: #666; }
904
- .xeplr-table-modal-id-badge { color: #5555dd; border-color: #5555dd; }
905
- .xeplr-table-modal-input { background: #f8f8fa; border-color: #d0d0d0; color: #333; }
906
- .xeplr-table-modal-input:focus { border-color: #5555dd; }
907
- .xeplr-table-modal-footer { border-top-color: #e0e0e0; }
908
- .xeplr-table-modal-btn { border-color: #d0d0d0; color: #666; }
909
- .xeplr-table-modal-btn:hover { background: #f0f0f0; color: #333; }
910
- .xeplr-table-modal-btn-primary { background: #5555dd; color: #fff; border-color: #5555dd; }
911
- .xeplr-table-modal-btn-primary:hover { background: #4444cc; }
912
- .xeplr-table-modal-checkbox { accent-color: #5555dd; }
969
+ /* ─────────────────────────────────────────────────────────────────
970
+ * Cell renderers (config-driven). Used when a column declares
971
+ * `render: { type: '...' }` instead of a custom cell function.
972
+ * ───────────────────────────────────────────────────────────────── */
973
+
974
+ /* avatarName ── avatar + bold name + optional subtitle */
975
+ .xeplr-r-avatarname {
976
+ display: flex; gap: 10px; align-items: center;
977
+ }
978
+ .xeplr-r-avatarname-sm .xeplr-r-avatar { width: 24px; height: 24px; font-size: 10px; }
979
+ .xeplr-r-avatar {
980
+ width: 32px; height: 32px; border-radius: 50%;
981
+ display: grid; place-items: center;
982
+ color: #1a1408; font-weight: 700; font-size: 11px;
983
+ flex-shrink: 0;
984
+ }
985
+ .xeplr-r-avatarname-text { min-width: 0; }
986
+ .xeplr-r-avatarname-name { font-weight: 600; color: var(--xeplr-text-primary, #e6e9f5); }
987
+ .xeplr-r-avatarname-sub { font-size: 12px; color: var(--xeplr-text-secondary, #8a93b8); margin-top: 2px; }
988
+
989
+ /* tags ── pill list. gold/blue are deliberate multi-color category variants,
990
+ not light/dark concerns — left as fixed accent colors on purpose. */
991
+ .xeplr-r-tags { display: flex; flex-wrap: wrap; gap: 4px; }
992
+ .xeplr-r-tag {
993
+ display: inline-block;
994
+ padding: 2px 9px;
995
+ border-radius: 999px;
996
+ font-size: 11px;
997
+ font-weight: 500;
998
+ border: 1px solid;
999
+ }
1000
+ .xeplr-r-tag-gold { background: rgba(212, 175, 55, 0.14); border-color: rgba(212, 175, 55, 0.35); color: #e9c156; }
1001
+ .xeplr-r-tag-muted { background: var(--xeplr-tag-bg, #1c2340); border-color: var(--xeplr-tag-border, #2a3458); color: var(--xeplr-tag-text, #8a93b8); }
1002
+ .xeplr-r-tag-blue { background: rgba(91, 141, 239, 0.14); border-color: rgba(91, 141, 239, 0.35); color: #88aef5; }
1003
+ .xeplr-r-tag-more { color: var(--xeplr-text-secondary, #8a93b8); font-size: 11px; align-self: center; }
1004
+
1005
+ /* currency */
1006
+ .xeplr-r-currency { display: inline-flex; align-items: baseline; gap: 2px; }
1007
+ .xeplr-r-currency-bold { font-weight: 700; color: var(--xeplr-text-primary, #e6e9f5); }
1008
+ .xeplr-r-currency-sym { color: var(--xeplr-text-secondary, #8a93b8); font-size: 0.92em; }
1009
+ .xeplr-r-currency-sym-after { margin-left: 3px; }
1010
+
1011
+ /* memberChips ── avatar+name chips with overflow */
1012
+ .xeplr-r-chips { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
1013
+ .xeplr-r-chip {
1014
+ display: inline-flex; align-items: center; gap: 6px;
1015
+ background: var(--xeplr-tag-bg, #1c2340); border: 1px solid var(--xeplr-tag-border, #2a3458);
1016
+ border-radius: 999px;
1017
+ padding: 3px 10px 3px 4px;
1018
+ font-size: 12px;
1019
+ color: var(--xeplr-tag-text, #c8cbe8);
1020
+ }
1021
+ .xeplr-r-chip-avatar {
1022
+ width: 22px; height: 22px; border-radius: 50%;
1023
+ display: grid; place-items: center;
1024
+ color: #1a1408; font-weight: 700; font-size: 10px;
1025
+ }
1026
+ .xeplr-r-chip-more { color: var(--xeplr-text-secondary, #8a93b8); font-size: 11px; }
1027
+
1028
+ /* twoLine */
1029
+ .xeplr-r-twoline-primary { font-weight: 600; color: var(--xeplr-text-primary, #e6e9f5); }
1030
+ .xeplr-r-twoline-sub { font-size: 12px; color: var(--xeplr-text-secondary, #8a93b8); margin-top: 2px; }
1031
+
1032
+ /* statusBadge */
1033
+ .xeplr-r-badge {
1034
+ display: inline-block;
1035
+ padding: 2px 10px;
1036
+ border-radius: 999px;
1037
+ font-size: 11px;
1038
+ font-weight: 600;
1039
+ border: 1px solid;
1040
+ }
1041
+
1042
+ /* dateDisplay */
1043
+ .xeplr-r-date { color: var(--xeplr-text-secondary, #c8cbe8); font-variant-numeric: tabular-nums; }
1044
+
1045
+ /* link — deliberate gold brand color, not a light/dark concern */
1046
+ .xeplr-r-link { color: #d4af37; cursor: pointer; }
1047
+ .xeplr-r-link:hover { color: #e9c156; text-decoration: underline; }
1048
+
1049
+ .xeplr-r-avatar-img { object-fit: cover; }
1050
+ .xeplr-r-chip-avatar-img { object-fit: cover; }
1051
+
1052
+ /* ── Host-marked columns (columnClassName) ──
1053
+ Nothing here styles a specific mark — the class is the host's and so is its
1054
+ meaning. This only makes the header label clickable when the host has taken
1055
+ the click, so the cursor says so before anybody guesses. */
1056
+ .xeplr-table-header-label.clickable {
1057
+ cursor: pointer;
1058
+ user-select: none;
913
1059
  }