@redseed/redseed-ui-tailwindcss 7.33.1 → 7.35.0
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/components/card_horizontal.css +201 -0
- package/components/table.css +19 -0
- package/components.css +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/* CardHorizontal: responsive layout.
|
|
2
|
+
Mobile (outer element width < 512px): stacked — image header above body (like a normal card).
|
|
3
|
+
Desktop (outer element width >= 512px): horizontal rail — fixed-width thumbnail left, body right.
|
|
4
|
+
Image renders at rail width × NATURAL height, pinned top-left.
|
|
5
|
+
Non-square sources (landscape 16:9, portrait 9:16) render without crop or letterbox.
|
|
6
|
+
No black background.
|
|
7
|
+
|
|
8
|
+
Breakpoint strategy: CSS container queries (container-type: inline-size on the card root).
|
|
9
|
+
The layout responds to the ELEMENT width, not the viewport width — this ensures the
|
|
10
|
+
MobileViewport story (max-width:375px at desktop viewport) renders the stacked mobile
|
|
11
|
+
layout correctly, and in general makes the card layout-agnostic.
|
|
12
|
+
|
|
13
|
+
BREAKPOINT: --container-lg = 32rem = 512px outer width.
|
|
14
|
+
Container queries measure the CONTENT-BOX inline-size. With the default 1px border on
|
|
15
|
+
each side (box-sizing: border-box), content-box = outer-size − 2px. The CSS rule uses
|
|
16
|
+
calc(32rem - 2px) so a 512px-wide outer container (content-box 510px) triggers rail layout:
|
|
17
|
+
outer container width < 512px → content-box < 510px → stacked
|
|
18
|
+
outer container width >= 512px → content-box >= 510px → horizontal rail
|
|
19
|
+
(32rem references --container-lg from theme.css; non-bordered variant fires at 510px+)
|
|
20
|
+
NOTE: @container conditions cannot use var() — calc(32rem - 2px) must be updated
|
|
21
|
+
manually at every @container site in this file when the breakpoint changes.
|
|
22
|
+
|
|
23
|
+
"sm+" in the comments below means the ≥512px CONTAINER state (rail layout).
|
|
24
|
+
This is NOT Tailwind's `sm` viewport breakpoint (640px). The switch is driven by
|
|
25
|
+
the card's own inline-size container query, so it fires at 512px element width
|
|
26
|
+
regardless of the viewport size. A 375px-wide card in a 1920px viewport is "mobile".
|
|
27
|
+
|
|
28
|
+
Corner rounding strategy (sm+):
|
|
29
|
+
The grid content wrapper (.rsui-card__content) gets overflow:hidden + border-radius
|
|
30
|
+
matching the card outer corner. This single layer clips all four outer card corners:
|
|
31
|
+
- tl: always clipped (image top-left at card corner).
|
|
32
|
+
- bl: image's bl IS at card bottom when image drives grid height (square, portrait).
|
|
33
|
+
When body is taller (landscape/tall-body), image bl is interior — no clip there.
|
|
34
|
+
Result: bl-radius appears exactly when image reaches card bottom-left. ✓
|
|
35
|
+
- br: body column background is clipped at card br. Image br is at the 160px column
|
|
36
|
+
boundary (interior). When the image is shorter than the card (floating state), a
|
|
37
|
+
JS-driven --floating class applies border-bottom-right-radius directly to the image
|
|
38
|
+
so it shows a visible rounded corner at its own bottom-right edge.
|
|
39
|
+
The action-layer (focus ring) is a sibling of .rsui-card__content, not a child —
|
|
40
|
+
overflow:hidden on .rsui-card__content does NOT clip the focus ring. ✓
|
|
41
|
+
|
|
42
|
+
Portrait images let the card grow to the full natural height (align-self:start on the
|
|
43
|
+
thumbnail so the portrait image drives the grid row height rather than being clipped).
|
|
44
|
+
|
|
45
|
+
Design token --ch-thumbnail-size (160px) sets the desktop rail width and the
|
|
46
|
+
desktop card min-height. Override on .rsui-card-horizontal to change. */
|
|
47
|
+
|
|
48
|
+
.rsui-card-horizontal {
|
|
49
|
+
--ch-thumbnail-size: 160px;
|
|
50
|
+
/* Named container so @container queries below bind to this card, not an ancestor. */
|
|
51
|
+
@apply @container/card-horizontal;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* ─────────────────────────────────────────────────
|
|
55
|
+
Content wrapper: flex-col (mobile) → grid (sm+)
|
|
56
|
+
───────────────────────────────────────────────── */
|
|
57
|
+
|
|
58
|
+
/* Child selector (not descendant) prevents leaking into nested Cards in slots.
|
|
59
|
+
flex-none overrides rsui-card__content's flex-1 so the card is content-driven. */
|
|
60
|
+
.rsui-card-horizontal > .rsui-card__content {
|
|
61
|
+
/* Mobile: stack thumbnail above body */
|
|
62
|
+
@apply flex flex-col flex-none;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* sm+: switch to horizontal grid with fixed thumbnail column.
|
|
66
|
+
Fixed column eliminates the flex/aspect-ratio circular-dependency that
|
|
67
|
+
caused Chrome's intrinsic-sizing bug. min-height = rail width guarantees
|
|
68
|
+
a square slot when body content is short.
|
|
69
|
+
overflow:hidden + border-radius clips all four card outer corners (see file header). */
|
|
70
|
+
@container card-horizontal (min-width: calc(32rem - 2px)) /* --container-lg (32rem=512px) - 2px border */ {
|
|
71
|
+
.rsui-card-horizontal > .rsui-card__content {
|
|
72
|
+
@apply grid gap-0 overflow-hidden rounded-xl;
|
|
73
|
+
@apply grid-cols-[var(--ch-thumbnail-size)_1fr]; /* arbitrary col: token var → 160px rail + flexible body */
|
|
74
|
+
@apply min-h-(--ch-thumbnail-size); /* v4 var shorthand → min-height: var(--ch-thumbnail-size) */
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* ─────────────────────────────────────────────────
|
|
79
|
+
Thumbnail + image wrapper (rsui-image component in the slot)
|
|
80
|
+
───────────────────────────────────────────────── */
|
|
81
|
+
|
|
82
|
+
.rsui-card-horizontal__thumbnail {
|
|
83
|
+
/* Mobile: full-width 16:9 header at the top of the card */
|
|
84
|
+
@apply w-full overflow-hidden rounded-t-xl aspect-video;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Mobile: image fills the full 16:9 thumbnail container — no letterbox. */
|
|
88
|
+
.rsui-card-horizontal__thumbnail .rsui-image {
|
|
89
|
+
@apply relative overflow-hidden w-full h-full shrink-0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.rsui-card-horizontal__thumbnail .rsui-image picture {
|
|
93
|
+
/* Mobile: fills the 16:9 aspect-video container. sm+: natural height. */
|
|
94
|
+
@apply block w-full h-full;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.rsui-card-horizontal__thumbnail .rsui-image img {
|
|
98
|
+
/* Mobile: fill the 16:9 container with center-crop. sm+: natural ratio. */
|
|
99
|
+
@apply w-full h-full object-cover;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Raw <img> passed directly into the slot (no rsui-image wrapper) */
|
|
103
|
+
.rsui-card-horizontal__thumbnail > img {
|
|
104
|
+
@apply w-full h-full object-cover shrink-0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* Fallback empty state: icon centred inside the container */
|
|
108
|
+
.rsui-card-horizontal__thumbnail .rsui-image__empty {
|
|
109
|
+
@apply absolute inset-0 flex items-center justify-center;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* sm+: thumbnail switches to narrow fixed-width rail; image elements switch to natural-ratio layout.
|
|
113
|
+
All five selectors grouped here so rail-layout overrides are a single-site edit. */
|
|
114
|
+
@container card-horizontal (min-width: calc(32rem - 2px)) /* --container-lg (32rem=512px) - 2px border */ {
|
|
115
|
+
/* sm+: narrow fixed-width rail.
|
|
116
|
+
self-start lets a portrait image drive the grid row height (card grows).
|
|
117
|
+
rounded-tl-xl rounds the top-left corner (outer card corner).
|
|
118
|
+
bl rounding is omitted here — the grid content wrapper's overflow:hidden handles
|
|
119
|
+
the bl clip conditionally: only when the image actually reaches the card bottom.
|
|
120
|
+
flex + items-start pins the image to the top-left corner. */
|
|
121
|
+
.rsui-card-horizontal__thumbnail {
|
|
122
|
+
@apply w-auto aspect-auto self-start rounded-none rounded-tl-xl flex items-start;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* sm+: image renders at natural aspect ratio (rail-width × natural-height), anchored top-left.
|
|
126
|
+
h-auto lets the image shrink (landscape) or grow (portrait) to its intrinsic height.
|
|
127
|
+
min-height keeps the 160px structural height when no image src is provided, so the
|
|
128
|
+
rsui-image__empty placeholder (absolute inset-0) still fills the rail correctly.
|
|
129
|
+
items-start overrides the base rsui-image flex centering so the image is
|
|
130
|
+
pinned to the top of the rail, not centred — critical for images shorter than 160px. */
|
|
131
|
+
.rsui-card-horizontal__thumbnail .rsui-image {
|
|
132
|
+
@apply h-auto items-start; /* items-start: pin image top-flush; base rsui-image uses items-center */
|
|
133
|
+
@apply min-h-(--ch-thumbnail-size); /* v4 var shorthand → min-height: var(--ch-thumbnail-size) */
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.rsui-card-horizontal__thumbnail .rsui-image picture {
|
|
137
|
+
@apply h-auto;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.rsui-card-horizontal__thumbnail .rsui-image img {
|
|
141
|
+
/* Natural ratio: h-auto scales proportionally to the element width.
|
|
142
|
+
object-cover from the base rule is harmless here — the element box
|
|
143
|
+
is already at the image's natural aspect ratio so no cropping occurs. */
|
|
144
|
+
@apply h-auto;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.rsui-card-horizontal__thumbnail > img {
|
|
148
|
+
@apply h-auto; /* natural ratio at sm+ */
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* ─────────────────────────────────────────────────
|
|
153
|
+
Floating thumbnail (image shorter than the card)
|
|
154
|
+
Added by JS (ResizeObserver) when either:
|
|
155
|
+
• the rendered img is shorter than the 160px rail (landscape, empty state), or
|
|
156
|
+
• the body column pushes the grid row taller than the thumbnail (tall-body).
|
|
157
|
+
Applies border-bottom-right-radius to the image/container so the image shows a
|
|
158
|
+
visible rounded bottom-right corner at its floating bottom edge.
|
|
159
|
+
Scoped to sm+ because mobile uses overflow:hidden on the thumbnail itself.
|
|
160
|
+
───────────────────────────────────────────────── */
|
|
161
|
+
|
|
162
|
+
@container card-horizontal (min-width: calc(32rem - 2px)) /* --container-lg (32rem=512px) - 2px border */ {
|
|
163
|
+
/* Round all three image targets when floating: rsui-image container, its <img>, and raw direct <img>. */
|
|
164
|
+
.rsui-card-horizontal__thumbnail--floating .rsui-image,
|
|
165
|
+
.rsui-card-horizontal__thumbnail--floating .rsui-image img,
|
|
166
|
+
.rsui-card-horizontal__thumbnail--floating > img {
|
|
167
|
+
@apply rounded-br-xl;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* ─────────────────────────────────────────────────
|
|
172
|
+
Body
|
|
173
|
+
───────────────────────────────────────────────── */
|
|
174
|
+
|
|
175
|
+
.rsui-card-horizontal__body {
|
|
176
|
+
/* Mobile: body fills full width below the image (self-stretch default).
|
|
177
|
+
sm+: self-start so body drives the grid row height (not stretches to it). */
|
|
178
|
+
@apply flex flex-col gap-y-2 p-4 min-w-0;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
@container card-horizontal (min-width: calc(32rem - 2px)) /* --container-lg (32rem=512px) - 2px border */ {
|
|
182
|
+
.rsui-card-horizontal__body {
|
|
183
|
+
@apply self-start;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.rsui-card-horizontal__content {
|
|
188
|
+
@apply flex flex-col gap-y-1;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.rsui-card-horizontal__title {
|
|
192
|
+
@apply text-base font-semibold text-text-primary leading-snug;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.rsui-card-horizontal__description {
|
|
196
|
+
@apply text-sm text-text-secondary;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.rsui-card-horizontal__meta {
|
|
200
|
+
@apply flex flex-wrap items-center gap-x-3 gap-y-1;
|
|
201
|
+
}
|
package/components/table.css
CHANGED
|
@@ -38,6 +38,25 @@
|
|
|
38
38
|
@apply w-full overflow-x-auto;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/* Drag-to-scroll affordance (opt-in via the Table `dragScroll` prop).
|
|
42
|
+
Only applied when the container actually overflows. Grab beats the
|
|
43
|
+
clickable-row pointer so the drag affordance is visible; the pinned column
|
|
44
|
+
is the anchor, so it shows the default cursor instead. */
|
|
45
|
+
.rsui-table__container--draggable,
|
|
46
|
+
.rsui-table__container--draggable .rsui-tr--clickable {
|
|
47
|
+
@apply cursor-grab;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.rsui-table__container--dragging,
|
|
51
|
+
.rsui-table__container--dragging .rsui-tr--clickable {
|
|
52
|
+
@apply cursor-grabbing select-none;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.rsui-table__container--draggable .rsui-td--pinned,
|
|
56
|
+
.rsui-table__container--draggable .rsui-th--pinned {
|
|
57
|
+
@apply cursor-default;
|
|
58
|
+
}
|
|
59
|
+
|
|
41
60
|
.rsui-table__footer {
|
|
42
61
|
@apply w-full border-t border-border-primary overflow-hidden py-3 px-6;
|
|
43
62
|
}
|
package/components.css
CHANGED
|
@@ -20,6 +20,7 @@ Please be careful when adding new components and updating the order.
|
|
|
20
20
|
@import './components/card_group.css';
|
|
21
21
|
@import './components/card.css';
|
|
22
22
|
@import './components/card_header.css';
|
|
23
|
+
@import './components/card_horizontal.css';
|
|
23
24
|
@import './components/checkbox_card.css';
|
|
24
25
|
@import './components/column_picker.css';
|
|
25
26
|
@import './components/comments.css';
|