@redseed/redseed-ui-tailwindcss 7.34.0 → 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.
@@ -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.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';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redseed/redseed-ui-tailwindcss",
3
- "version": "7.34.0",
3
+ "version": "7.35.0",
4
4
  "description": "RedSeed UI Tailwindcss",
5
5
  "main": "index.js",
6
6
  "style": "index.css",