@lobehub/ui 5.63.0 → 5.63.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.
@@ -15,7 +15,22 @@ const ownRows = [
15
15
  ].map((section) => `& > ${p}-container > ${p}-${section} > table > * > tr`).join(", ");
16
16
  const ownCells = (cell) => ownRows.split(", ").map((row) => `${row} > ${cell}`).join(", ");
17
17
  const styles = createStaticStyles(({ css, cssVar }) => {
18
- const border = `1px solid ${cssVar.colorBorderSecondary}`;
18
+ const borderColor = `var(--lobe-fill-border, ${cssVar.colorFill})`;
19
+ const border = `1px solid ${borderColor}`;
20
+ const surface = (light) => `var(--lobe-table-surface, ${light})`;
21
+ const cellBg = `var(--lobe-table-cell, ${cssVar.colorBgContainer})`;
22
+ const fill = "var(--lobe-table-fill, transparent)";
23
+ const hoverBg = cssVar.colorFillTertiary;
24
+ const selectedBg = `color-mix(in srgb, ${cssVar.colorPrimary} 6%, transparent)`;
25
+ const selectedHoverBg = `color-mix(in srgb, ${cssVar.colorPrimary} 10%, transparent)`;
26
+ const frost = `
27
+ -webkit-backdrop-filter: blur(16px);
28
+ backdrop-filter: blur(16px);
29
+ `;
30
+ const variantVars = `
31
+ --lobe-table-cell: var(--lobe-table-cell-bg, ${cssVar.colorBgContainer});
32
+ --lobe-table-fill: var(--lobe-table-surface, transparent);
33
+ `;
19
34
  const fixShadowBase = `
20
35
  pointer-events: none;
21
36
  content: '';
@@ -29,16 +44,18 @@ const styles = createStaticStyles(({ css, cssVar }) => {
29
44
  return {
30
45
  outlined: css`
31
46
  &${p}-outlined {
32
- /* The square root must not paint behind the rounded frame: the container
33
- (clipped to its radius) carries the colorBgContainer body instead. */
47
+ ${variantVars}
48
+ /* The square root must not paint behind the rounded frame: the clipped container
49
+ is the ONE layer carrying the body (light colorBgContainer, dark
50
+ colorFillQuaternary). Title / footer are siblings, so they paint it once too. */
34
51
  background: transparent;
35
52
 
36
53
  & > ${p}-container {
37
- background: ${cssVar.colorBgContainer};
54
+ background: ${surface(cssVar.colorBgContainer)};
38
55
  }
39
56
 
40
57
  & > ${p}-title, & > ${p}-footer {
41
- background: ${cssVar.colorBgContainer};
58
+ background: ${surface(cssVar.colorBgContainer)};
42
59
  }
43
60
 
44
61
  & > ${p}-title {
@@ -48,13 +65,18 @@ const styles = createStaticStyles(({ css, cssVar }) => {
48
65
  border-start-end-radius: ${cssVar.borderRadiusLG};
49
66
  }
50
67
 
51
- /* The container draws the top and both side edges; the last row draws the bottom.
68
+ /* The container draws the full frame (incl. bottom). Last-row borders used to stand
69
+ in for the bottom edge, but with scroll.y / virtual the last row sits inside the
70
+ body viewport - overflow:clip + radius then eats that line at the rounded corners.
52
71
  No column dividers (grouped headers included): rows are split horizontally only. */
53
72
  & > ${p}-container {
54
73
  overflow: clip;
55
- border-block-start: ${border};
56
- border-inline: ${border};
74
+ border: ${border};
57
75
  border-radius: ${cssVar.borderRadiusLG};
76
+
77
+ /* Same lift as the dashboard Surface card (both modes). Outer shadow on the framed
78
+ container is not clipped by its own overflow. */
79
+ box-shadow: rgb(0 0 0 / 4%) 0 1px 2px 0;
58
80
  }
59
81
 
60
82
  & > ${p}-title + ${p}-container {
@@ -63,6 +85,7 @@ const styles = createStaticStyles(({ css, cssVar }) => {
63
85
  }
64
86
 
65
87
  &:has(> ${p}-footer) > ${p}-container {
88
+ border-block-end: 0;
66
89
  border-end-start-radius: 0;
67
90
  border-end-end-radius: 0;
68
91
  }
@@ -78,17 +101,66 @@ const styles = createStaticStyles(({ css, cssVar }) => {
78
101
  shadow underneath, or group headers look double-thick. */
79
102
  & > ${p}-container > * > table > thead > tr > th {
80
103
  border-block-end: ${border};
104
+
105
+ /* Extra FillQuaternary layer on top of the container fill. */
106
+ background: ${cellBg};
107
+ box-shadow: inset 0 999px 0 ${cssVar.colorFillQuaternary};
108
+ }
109
+
110
+ /* Fixed cells: see-through (container fill shows) + backdrop blur only. */
111
+ & ${p}-tbody > tr > td${p}-cell-fix, & ${p}-tbody-virtual ${p}-cell${p}-cell-fix {
112
+ background: transparent;
113
+ box-shadow: none;
114
+ }
115
+
116
+ /* Header: container fill + one Quaternary wash (box-shadow), like other th. */
117
+ & ${p}-thead > tr > th${p}-cell-fix, & ${p}-thead > tr > td${p}-cell-fix {
118
+ background: transparent;
81
119
  box-shadow: inset 0 999px 0 ${cssVar.colorFillQuaternary};
82
120
  }
83
121
  }
122
+ `,
123
+ frostRail: css`
124
+ pointer-events: none;
125
+
126
+ position: absolute;
127
+ z-index: 1;
128
+ inset-block-start: 0;
129
+ inset-inline-start: 0;
130
+
131
+ display: flex;
132
+ `,
133
+ frostStart: css`
134
+ position: sticky;
135
+ inset-inline-start: 0;
136
+ flex: none;
137
+ height: 100%;
138
+ ${frost}
139
+ `,
140
+ frostEnd: css`
141
+ position: sticky;
142
+ inset-inline-end: 0;
143
+
144
+ flex: none;
145
+
146
+ height: 100%;
147
+ margin-inline-start: auto;
148
+ ${frost}
84
149
  `,
85
150
  filled: css`
86
151
  &${p}-filled {
152
+ ${variantVars}
153
+ /* Filled owns its fill in both modes (Block filled = colorFillTertiary; dark uses the
154
+ Quaternary surface) and its opaque base is the page behind it, not colorBgContainer. */
155
+ --lobe-table-fill: var(--lobe-table-surface, ${cssVar.colorFillTertiary});
156
+
157
+ /* Root stays clear (square box, would bleed past the rounded corners); the clipped
158
+ container is the ONE fill layer: light FillTertiary, dark colorFillQuaternary. */
87
159
  background: transparent;
88
160
 
89
161
  & > ${p}-title, & > ${p}-footer {
90
162
  border-radius: ${cssVar.borderRadiusLG};
91
- background: ${cssVar.colorFillQuaternary};
163
+ background: ${fill};
92
164
  }
93
165
 
94
166
  & > ${p}-title {
@@ -104,7 +176,7 @@ const styles = createStaticStyles(({ css, cssVar }) => {
104
176
  & > ${p}-container {
105
177
  overflow: clip;
106
178
  border-radius: ${cssVar.borderRadiusLG};
107
- background: ${cssVar.colorFillTertiary};
179
+ background: ${fill};
108
180
  }
109
181
 
110
182
  & > ${p}-title + ${p}-container {
@@ -117,43 +189,40 @@ const styles = createStaticStyles(({ css, cssVar }) => {
117
189
  border-end-end-radius: 0;
118
190
  }
119
191
 
120
- /* Header band: only the FillQuaternary wash over the container fill (stacking a
121
- second FillTertiary made dark mode too bright). */
192
+ /* Header band: one extra FillQuaternary wash over the container fill. */
122
193
  & ${p}-thead > tr > th,
123
194
  & ${p}-thead > tr > td {
124
195
  background: transparent;
125
196
  box-shadow:
126
- inset 0 -1px 0 ${cssVar.colorBorderSecondary},
197
+ inset 0 -1px 0 ${borderColor},
127
198
  inset 0 999px 0 ${cssVar.colorFillQuaternary};
128
199
  }
129
200
 
130
- /* Row dividers stay on (base colorBorderSecondary rule); only the fill is the container's. */
201
+ /* Row dividers stay on (base border rule); body is clear over the container fill. */
131
202
  & ${p}-tbody > tr > td,
132
203
  & ${p}-tbody > tr > th,
133
204
  & ${p}-tbody-virtual ${p}-cell {
134
205
  background: transparent;
135
206
  }
136
207
 
137
- /* Fixed cells must be opaque: colorBgContainer painted with the same fill(s), the
138
- closest opaque match to the translucent surface around them. */
208
+ /* Fixed cells: see-through + blur; header keeps the same divider + wash as every th. */
139
209
  & ${p}-thead > tr > th${p}-cell-fix, & ${p}-thead > tr > td${p}-cell-fix {
140
- background: ${cssVar.colorBgContainer};
210
+ background: transparent;
141
211
  box-shadow:
142
- inset 0 -1px 0 ${cssVar.colorBorderSecondary},
143
- inset 0 999px 0 ${cssVar.colorFillQuaternary},
144
- inset 0 999px 0 ${cssVar.colorFillTertiary};
212
+ inset 0 -1px 0 ${borderColor},
213
+ inset 0 999px 0 ${cssVar.colorFillQuaternary};
145
214
  }
146
215
 
147
216
  & ${p}-tbody > tr > td${p}-cell-fix {
148
- background: ${cssVar.colorBgContainer};
149
- box-shadow: inset 0 999px 0 ${cssVar.colorFillTertiary};
217
+ background: transparent;
218
+ box-shadow: none;
150
219
  }
151
220
  }
152
221
  `,
153
222
  /**
154
223
  * Borderless: everything but the header is see-through, so the table sits on whatever
155
224
  * surface hosts it. Hover / selected rows are translucent fills. Fixed (sticky) cells
156
- * stay opaque in colorBgContainer so scrolled content never shows underneath them.
225
+ * are see-through with a frosted backdrop so scrolled content stays obscured.
157
226
  */
158
227
  borderless: css`
159
228
  && {
@@ -169,14 +238,14 @@ const styles = createStaticStyles(({ css, cssVar }) => {
169
238
  }
170
239
 
171
240
  && ${p}-tbody > tr > td${p}-cell-row-hover, && ${p}-tbody-virtual ${p}-row:hover > ${p}-cell {
172
- background: color-mix(in srgb, ${cssVar.colorText} 3%, transparent);
241
+ background: ${hoverBg};
173
242
  }
174
243
 
175
244
  && ${p}-tbody > tr${p}-row-selected > td {
176
- background: color-mix(in srgb, ${cssVar.colorPrimary} 6%, transparent);
245
+ background: ${selectedBg};
177
246
 
178
247
  &${p}-cell-row-hover {
179
- background: color-mix(in srgb, ${cssVar.colorPrimary} 10%, transparent);
248
+ background: ${selectedHoverBg};
180
249
  }
181
250
  }
182
251
 
@@ -191,18 +260,18 @@ const styles = createStaticStyles(({ css, cssVar }) => {
191
260
  &&
192
261
  ${p}-tbody-virtual
193
262
  ${p}-cell${p}-cell-fix {
194
- background: ${cssVar.colorBgContainer};
263
+ background: transparent;
195
264
  }
196
265
 
197
266
  && ${p}-tbody > tr > td${p}-cell-fix${p}-cell-row-hover {
198
- background: color-mix(in srgb, ${cssVar.colorBgContainer}, ${cssVar.colorText} 3%);
267
+ background: ${hoverBg};
199
268
  }
200
269
 
201
270
  && ${p}-tbody > tr${p}-row-selected > td${p}-cell-fix {
202
- background: color-mix(in srgb, ${cssVar.colorBgContainer}, ${cssVar.colorPrimary} 6%);
271
+ background: ${selectedBg};
203
272
 
204
273
  &${p}-cell-row-hover {
205
- background: color-mix(in srgb, ${cssVar.colorBgContainer}, ${cssVar.colorPrimary} 10%);
274
+ background: ${selectedHoverBg};
206
275
  }
207
276
  }
208
277
  `,
@@ -339,8 +408,9 @@ const styles = createStaticStyles(({ css, cssVar }) => {
339
408
  vertical-align: middle;
340
409
  `,
341
410
  hoverable: css`
342
- & ${p}-tbody > tr > ${p}-cell-row-hover, & ${p}-tbody-virtual ${p}-row:hover > ${p}-cell {
343
- background: color-mix(in srgb, ${cssVar.colorBgContainer}, ${cssVar.colorText} 3%);
411
+ /* &&& outranks the variant cell rules (filled clear cells, transparent fixed cells). */
412
+ &&& ${p}-tbody > tr > ${p}-cell-row-hover, &&& ${p}-tbody-virtual ${p}-row:hover > ${p}-cell {
413
+ background: ${hoverBg};
344
414
  }
345
415
  `,
346
416
  loading: css`
@@ -385,7 +455,7 @@ const styles = createStaticStyles(({ css, cssVar }) => {
385
455
 
386
456
  width: 100%;
387
457
  min-width: 0;
388
- border-block-end: 1px solid ${cssVar.colorBorderSecondary};
458
+ border-block-end: 1px solid ${borderColor};
389
459
 
390
460
  &:last-child {
391
461
  border-block-end: 0;
@@ -450,14 +520,23 @@ const styles = createStaticStyles(({ css, cssVar }) => {
450
520
  sizeLarge: css`
451
521
  ${PADDING_BLOCK}: 16px;
452
522
  ${PADDING_INLINE}: 16px;
523
+
524
+ /* Same as VIRTUAL_ROW_HEIGHT in Table.tsx (padding * 2 + 22px line + 1px divider). */
525
+ --lobe-table-virtual-row-height: calc(16px * 2 + 23px);
453
526
  `,
454
527
  sizeMedium: css`
455
528
  ${PADDING_BLOCK}: 12px;
456
529
  ${PADDING_INLINE}: 16px;
530
+
531
+ /* Same as VIRTUAL_ROW_HEIGHT in Table.tsx (padding * 2 + 22px line + 1px divider). */
532
+ --lobe-table-virtual-row-height: calc(12px * 2 + 23px);
457
533
  `,
458
534
  sizeSmall: css`
459
535
  ${PADDING_BLOCK}: 8px;
460
536
  ${PADDING_INLINE}: 12px;
537
+
538
+ /* Same as VIRTUAL_ROW_HEIGHT in Table.tsx (padding * 2 + 22px line + 1px divider). */
539
+ --lobe-table-virtual-row-height: calc(8px * 2 + 23px);
461
540
  `,
462
541
  sortButton: css`
463
542
  display: inline-flex;
@@ -484,6 +563,10 @@ const styles = createStaticStyles(({ css, cssVar }) => {
484
563
  position: relative;
485
564
  `,
486
565
  table: css`
566
+ /* Reset per root so nested / borderless tables never inherit a parent's variant vars. */
567
+ --lobe-table-cell: ${cssVar.colorBgContainer};
568
+ --lobe-table-fill: transparent;
569
+
487
570
  font-size: 14px;
488
571
  color: ${cssVar.colorText};
489
572
  background: ${cssVar.colorBgContainer};
@@ -501,9 +584,39 @@ const styles = createStaticStyles(({ css, cssVar }) => {
501
584
  & tfoot > tr > th,
502
585
  & tfoot > tr > td {
503
586
  position: relative;
587
+
504
588
  padding-block: var(${PADDING_BLOCK});
505
589
  padding-inline: var(${PADDING_INLINE});
590
+
506
591
  overflow-wrap: break-word;
592
+
593
+ /* The global \`* { vertical-align: baseline }\` reset drops the UA's middle for cells. */
594
+ vertical-align: middle;
595
+ }
596
+
597
+ /* Row-merged body cells (rowSpan > 1, table and virtual body alike) get vertical
598
+ dividers so the block reads apart from the neighbour rows' lines. Drawn on ::before
599
+ (::after is the fixed-column scroll shadow) so cell box-shadows stay untouched. The
600
+ first / last column skip the edge the frame or table edge already provides. */
601
+ & ${p}-tbody > tr > td[rowspan]:not([rowspan='0'], [rowspan='1'])::before,
602
+ & ${p}-tbody-virtual ${p}-cell[rowspan]:not([rowspan='0'], [rowspan='1'])::before {
603
+ pointer-events: none;
604
+ content: '';
605
+
606
+ position: absolute;
607
+ inset: 0;
608
+
609
+ border-inline: ${border};
610
+ }
611
+
612
+ & ${p}-tbody > tr > td[rowspan]:first-child::before,
613
+ & ${p}-tbody-virtual ${p}-cell[rowspan]:first-child::before {
614
+ border-inline-start: 0;
615
+ }
616
+
617
+ & ${p}-tbody > tr > td[rowspan]:last-child::before,
618
+ & ${p}-tbody-virtual ${p}-cell[rowspan]:last-child::before {
619
+ border-inline-end: 0;
507
620
  }
508
621
 
509
622
  & ${p}-thead > tr > th,
@@ -513,9 +626,10 @@ const styles = createStaticStyles(({ css, cssVar }) => {
513
626
  color: ${cssVar.colorTextSecondary};
514
627
  text-align: start;
515
628
 
516
- background: ${cssVar.colorBgContainer};
629
+ /* Clear in dark (outlined) so the container fill shows; Quaternary is the extra header layer. */
630
+ background: ${cellBg};
517
631
  box-shadow:
518
- inset 0 -1px 0 ${cssVar.colorBorderSecondary},
632
+ inset 0 -1px 0 ${borderColor},
519
633
  inset 0 999px 0 ${cssVar.colorFillQuaternary};
520
634
 
521
635
  &[colspan]:not([colspan='1']) {
@@ -532,13 +646,26 @@ const styles = createStaticStyles(({ css, cssVar }) => {
532
646
  font-variant-numeric: tabular-nums;
533
647
  text-align: start;
534
648
 
535
- background: ${cssVar.colorBgContainer};
649
+ /* Clear in dark (outlined) so the container fill shows through. */
650
+ background: ${cellBg};
536
651
 
537
652
  transition: background-color ${cssVar.motionDurationMid};
538
653
  }
539
654
 
540
- &:not(${p}-outlined) ${p}-tbody > tr:last-child > td,
541
- &:not(${p}-outlined) ${p}-tbody > tr:last-child > th {
655
+ /* Filled / outlined drop the last body divider: filled because its fill is the edge,
656
+ outlined because the container now draws the frame bottom (avoids a double line, and
657
+ keeps the outline when scroll.y / virtual would otherwise scroll the last-row edge
658
+ away). Borderless keeps it as the closing rule under the rows. */
659
+ &${p}-filled ${p}-tbody > tr:last-child > td,
660
+ &${p}-filled ${p}-tbody > tr:last-child > th,
661
+ &${p}-outlined ${p}-tbody > tr:last-child > td,
662
+ &${p}-outlined ${p}-tbody > tr:last-child > th {
663
+ border-block-end: 0;
664
+ }
665
+
666
+ /* Borderless with a summary: tfoot draws its own top rule, so skip the last-row one. */
667
+ &${p}-borderless table:has(> tfoot) > ${p}-tbody > tr:last-child > td,
668
+ &${p}-borderless table:has(> tfoot) > ${p}-tbody > tr:last-child > th {
542
669
  border-block-end: 0;
543
670
  }
544
671
 
@@ -637,7 +764,7 @@ const styles = createStaticStyles(({ css, cssVar }) => {
637
764
  }
638
765
 
639
766
  & ${p}-cell-fix {
640
- background: ${cssVar.colorBgContainer};
767
+ background: transparent;
641
768
 
642
769
  &::after {
643
770
  ${fixShadowBase}
@@ -664,41 +791,16 @@ const styles = createStaticStyles(({ css, cssVar }) => {
664
791
  & ${p}-sticky-holder {
665
792
  position: sticky;
666
793
  z-index: calc(var(--columns-count, 1) * 2 + ${Z_FIXED} + 1);
667
- background: ${cssVar.colorBgContainer};
794
+ background: transparent;
795
+
796
+ /* The whole sticky header is one element, so it blurs as one continuous block. */
797
+ ${frost}
668
798
  }
669
799
 
670
800
  & ${p}-sticky-scroll {
671
801
  position: sticky;
672
802
  z-index: calc(var(--columns-count, 1) * 2 + ${Z_FIXED} + 1);
673
803
  inset-block-end: 0;
674
-
675
- display: flex;
676
- align-items: center;
677
-
678
- height: 8px !important;
679
- border-block-start: ${border};
680
-
681
- opacity: 0.65;
682
- background: ${cssVar.colorFillQuaternary};
683
-
684
- &-bar {
685
- position: absolute;
686
- inset-block-end: 0;
687
-
688
- height: 8px;
689
- border-radius: 100px;
690
-
691
- background-color: ${cssVar.colorFill};
692
-
693
- transition:
694
- all ${cssVar.motionDurationSlow},
695
- transform 0s;
696
-
697
- &:hover,
698
- &-active {
699
- background-color: ${cssVar.colorFillSecondary};
700
- }
701
- }
702
804
  }
703
805
 
704
806
  /* ============================ Selection =========================== */
@@ -718,11 +820,12 @@ const styles = createStaticStyles(({ css, cssVar }) => {
718
820
  }
719
821
  }
720
822
 
721
- & ${p}-tbody > tr${p}-row-selected > td {
722
- background: color-mix(in srgb, ${cssVar.colorBgContainer}, ${cssVar.colorPrimary} 6%);
823
+ /* The table css carries no hoverable class, so use a fourth & to outrank hover too. */
824
+ &&&& ${p}-tbody > tr${p}-row-selected > td {
825
+ background: ${selectedBg};
723
826
 
724
827
  &${p}-cell-row-hover {
725
- background: color-mix(in srgb, ${cssVar.colorBgContainer}, ${cssVar.colorPrimary} 10%);
828
+ background: ${selectedHoverBg};
726
829
  }
727
830
  }
728
831
 
@@ -808,6 +911,7 @@ const styles = createStaticStyles(({ css, cssVar }) => {
808
911
  border-block: 0;
809
912
  border-inline-end: 0;
810
913
  border-radius: 0;
914
+ box-shadow: none;
811
915
  }
812
916
 
813
917
  & > ${p}-title + ${p}-container {
@@ -828,7 +932,9 @@ const styles = createStaticStyles(({ css, cssVar }) => {
828
932
  & ${p}-summary {
829
933
  position: relative;
830
934
  z-index: ${Z_FIXED};
831
- background: ${cssVar.colorBgContainer};
935
+
936
+ /* See-through; a sticky summary is a sticky holder and gets its frost there. */
937
+ background: transparent;
832
938
 
833
939
  & > tr > th,
834
940
  & > tr > td {
@@ -837,7 +943,7 @@ const styles = createStaticStyles(({ css, cssVar }) => {
837
943
  }
838
944
 
839
945
  & div${p}-summary {
840
- box-shadow: 0 -1px 0 ${cssVar.colorBorderSecondary};
946
+ box-shadow: 0 -1px 0 ${borderColor};
841
947
  }
842
948
 
843
949
  /* A fixed summary under \`sticky\` is a sticky holder too; keep it sticky (antd orders sticky last). */
@@ -864,6 +970,14 @@ const styles = createStaticStyles(({ css, cssVar }) => {
864
970
  box-sizing: border-box;
865
971
  width: 100%;
866
972
 
973
+ /* Virtual rows are locked to the listItemHeight estimate (an integer). Measured
974
+ heights then equal the estimate, so a rowSpan cell (height = summed row sizes)
975
+ ends exactly on the neighbour rows' divider instead of drifting by sub-pixel
976
+ rounding or unmeasured-row estimates. */
977
+ &:not(${p}-row-extra, ${p}-expanded-row) {
978
+ height: var(--lobe-table-virtual-row-height);
979
+ }
980
+
867
981
  & > ${p}-cell {
868
982
  align-content: center;
869
983
  }
@@ -871,18 +985,10 @@ const styles = createStaticStyles(({ css, cssVar }) => {
871
985
 
872
986
  & ${p}-cell {
873
987
  border-block-end: ${border};
874
- background: ${cssVar.colorBgContainer};
988
+ background: ${cellBg};
875
989
  transition: background-color ${cssVar.motionDurationMid};
876
990
  }
877
991
 
878
- & ${p}-tbody-virtual-scrollbar {
879
- cursor: pointer;
880
-
881
- &:hover {
882
- background-color: ${cssVar.colorFillQuaternary};
883
- }
884
- }
885
-
886
992
  & ${p}-expanded-row ${p}-expanded-row-cell${p}-expanded-row-cell-fixed {
887
993
  position: sticky;
888
994
  inset-inline-start: 0;