@bearmenu/ui 0.8.7 → 0.8.9

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.
Files changed (179) hide show
  1. package/dist/{chunk-637L7XQ3.js → chunk-3TNPSN4D.js} +28 -9
  2. package/dist/chunk-62ES6N32.js +27 -0
  3. package/dist/chunk-AHL45DD2.js +145 -0
  4. package/dist/chunk-AXV5O2IZ.js +58 -0
  5. package/dist/chunk-IYDH5IU6.js +66 -0
  6. package/dist/chunk-OPVKL4VS.js +18 -0
  7. package/dist/chunk-Q6QH52LJ.js +38 -0
  8. package/dist/chunk-TH6W2PWG.js +213 -0
  9. package/dist/chunk-THOVPZNN.js +37 -0
  10. package/dist/chunk-YS6BHKZO.js +92 -0
  11. package/dist/components/badge.d.ts +1 -1
  12. package/dist/components/button.d.ts +1 -1
  13. package/dist/components/category-deck.js +10 -1
  14. package/dist/components/command.d.ts +7 -7
  15. package/dist/components/concept-compare.d.ts +73 -0
  16. package/dist/components/concept-compare.js +162 -0
  17. package/dist/components/coverflow.d.ts +11 -3
  18. package/dist/components/coverflow.js +34 -51
  19. package/dist/components/date-input.d.ts +1 -1
  20. package/dist/components/drift-rail.d.ts +24 -10
  21. package/dist/components/drift-rail.js +1 -1
  22. package/dist/components/event-card.d.ts +8 -0
  23. package/dist/components/event-card.js +64 -34
  24. package/dist/components/event-compact-row.d.ts +33 -6
  25. package/dist/components/event-compact-row.js +120 -39
  26. package/dist/components/event-day-header.js +3 -1
  27. package/dist/components/event-day-separator.d.ts +7 -1
  28. package/dist/components/event-day-separator.js +3 -2
  29. package/dist/components/event-detail-panel.d.ts +171 -25
  30. package/dist/components/event-detail-panel.js +471 -174
  31. package/dist/components/event-hub-hero.d.ts +25 -4
  32. package/dist/components/event-hub-hero.js +89 -19
  33. package/dist/components/event-list-row-wide.js +1 -1
  34. package/dist/components/event-list-row.d.ts +19 -6
  35. package/dist/components/event-list-row.js +79 -35
  36. package/dist/components/hour-band.d.ts +38 -40
  37. package/dist/components/hour-band.js +55 -27
  38. package/dist/components/hour-group.js +1 -1
  39. package/dist/components/hub-surface.d.ts +27 -0
  40. package/dist/components/hub-surface.js +20 -0
  41. package/dist/components/menu-family-card.d.ts +59 -0
  42. package/dist/components/menu-family-card.js +121 -0
  43. package/dist/components/menu-field.d.ts +57 -0
  44. package/dist/components/menu-field.js +3 -0
  45. package/dist/components/menu-hub-hero.d.ts +65 -0
  46. package/dist/components/menu-hub-hero.js +103 -0
  47. package/dist/components/menu-intent-tiles.d.ts +31 -0
  48. package/dist/components/menu-intent-tiles.js +50 -0
  49. package/dist/components/menu-item.d.ts +127 -0
  50. package/dist/components/menu-item.js +5 -0
  51. package/dist/components/menu-mocks.d.ts +55 -0
  52. package/dist/components/menu-mocks.js +379 -0
  53. package/dist/components/menu-types.d.ts +245 -0
  54. package/dist/components/menu-types.js +1 -0
  55. package/dist/components/motion-icon-set.js +15 -3
  56. package/dist/components/open-now-list.d.ts +40 -0
  57. package/dist/components/open-now-list.js +69 -0
  58. package/dist/components/place-types.d.ts +112 -1
  59. package/dist/components/poster-tape.js +1 -1
  60. package/dist/components/poster-wall.d.ts +3 -3
  61. package/dist/components/poster-wall.js +73 -17
  62. package/dist/components/ranked-venue-list.d.ts +49 -0
  63. package/dist/components/ranked-venue-list.js +87 -0
  64. package/dist/components/section-header.d.ts +16 -1
  65. package/dist/components/section-header.js +26 -7
  66. package/dist/components/signature-chip.d.ts +37 -0
  67. package/dist/components/signature-chip.js +4 -0
  68. package/dist/components/signature-line-list.d.ts +45 -0
  69. package/dist/components/signature-line-list.js +99 -0
  70. package/dist/components/snap-rail.d.ts +54 -0
  71. package/dist/components/snap-rail.js +109 -0
  72. package/dist/components/spinner.d.ts +2 -2
  73. package/dist/components/stat-banner.d.ts +47 -0
  74. package/dist/components/stat-banner.js +61 -0
  75. package/dist/components/text.d.ts +3 -3
  76. package/dist/components/timeline-band.d.ts +20 -2
  77. package/dist/components/timeline-band.js +1 -1
  78. package/dist/components/timeline-playhead.d.ts +26 -0
  79. package/dist/components/timeline-playhead.js +25 -0
  80. package/dist/components/venue-busyness-strip.d.ts +35 -0
  81. package/dist/components/venue-busyness-strip.js +37 -0
  82. package/dist/components/venue-grade-dimensions.d.ts +36 -0
  83. package/dist/components/venue-grade-dimensions.js +3 -0
  84. package/dist/components/venue-quotes.d.ts +32 -0
  85. package/dist/components/venue-quotes.js +3 -0
  86. package/dist/components/venue-signature-block.d.ts +39 -0
  87. package/dist/components/venue-signature-block.js +6 -0
  88. package/dist/components/venue-spotlight.d.ts +74 -0
  89. package/dist/components/venue-spotlight.js +138 -0
  90. package/dist/components/venue-wall.d.ts +41 -0
  91. package/dist/components/venue-wall.js +118 -0
  92. package/dist/components/weekday-theme-banner.d.ts +70 -0
  93. package/dist/components/weekday-theme-banner.js +127 -0
  94. package/dist/components/weekend-panel.d.ts +5 -4
  95. package/dist/components/weekend-panel.js +85 -71
  96. package/dist/hooks/use-drag-swipe.d.ts +44 -0
  97. package/dist/hooks/use-drag-swipe.js +2 -0
  98. package/dist/hooks/use-media-query.d.ts +17 -0
  99. package/dist/hooks/use-media-query.js +2 -0
  100. package/package.json +1 -1
  101. package/src/components/category-deck.tsx +19 -8
  102. package/src/components/colour-dictionary.stories.tsx +227 -0
  103. package/src/components/concept-compare.stories.tsx +104 -0
  104. package/src/components/concept-compare.tsx +276 -0
  105. package/src/components/coverflow.test.tsx +28 -1
  106. package/src/components/coverflow.tsx +37 -43
  107. package/src/components/drift-rail.tsx +167 -42
  108. package/src/components/event-card.tsx +55 -10
  109. package/src/components/event-compact-row.stories.tsx +30 -0
  110. package/src/components/event-compact-row.test.tsx +49 -0
  111. package/src/components/event-compact-row.tsx +162 -38
  112. package/src/components/event-day-header.tsx +3 -1
  113. package/src/components/event-day-separator.tsx +8 -1
  114. package/src/components/event-detail-panel.stories.tsx +205 -97
  115. package/src/components/event-detail-panel.test.tsx +181 -0
  116. package/src/components/event-detail-panel.tsx +703 -185
  117. package/src/components/event-hub-hero.stories.tsx +30 -0
  118. package/src/components/event-hub-hero.tsx +102 -30
  119. package/src/components/event-list-row.stories.tsx +34 -0
  120. package/src/components/event-list-row.test.tsx +53 -0
  121. package/src/components/event-list-row.tsx +135 -87
  122. package/src/components/hour-band.stories.tsx +28 -5
  123. package/src/components/hour-band.tsx +90 -70
  124. package/src/components/hub-surface.stories.tsx +68 -0
  125. package/src/components/hub-surface.tsx +40 -0
  126. package/src/components/menu-family-card.stories.tsx +112 -0
  127. package/src/components/menu-family-card.tsx +211 -0
  128. package/src/components/menu-field.stories.tsx +74 -0
  129. package/src/components/menu-field.tsx +199 -0
  130. package/src/components/menu-hub-hero.stories.tsx +92 -0
  131. package/src/components/menu-hub-hero.tsx +187 -0
  132. package/src/components/menu-intent-tiles.stories.tsx +54 -0
  133. package/src/components/menu-intent-tiles.tsx +76 -0
  134. package/src/components/menu-item.tsx +416 -0
  135. package/src/components/menu-mocks.ts +417 -0
  136. package/src/components/menu-types.ts +259 -0
  137. package/src/components/motion-icon-set.tsx +30 -3
  138. package/src/components/open-now-list.stories.tsx +76 -0
  139. package/src/components/open-now-list.tsx +127 -0
  140. package/src/components/place-types.ts +112 -0
  141. package/src/components/poster-wall.test.tsx +28 -0
  142. package/src/components/poster-wall.tsx +96 -23
  143. package/src/components/ranked-venue-list.stories.tsx +80 -0
  144. package/src/components/ranked-venue-list.tsx +177 -0
  145. package/src/components/section-header.stories.tsx +24 -0
  146. package/src/components/section-header.test.tsx +28 -0
  147. package/src/components/section-header.tsx +45 -7
  148. package/src/components/signature-chip.tsx +77 -0
  149. package/src/components/signature-line-list.stories.tsx +85 -0
  150. package/src/components/signature-line-list.tsx +136 -0
  151. package/src/components/snap-rail.stories.tsx +79 -0
  152. package/src/components/snap-rail.test.tsx +18 -0
  153. package/src/components/snap-rail.tsx +148 -0
  154. package/src/components/stat-banner.stories.tsx +100 -0
  155. package/src/components/stat-banner.tsx +117 -0
  156. package/src/components/timeline-band.tsx +52 -12
  157. package/src/components/timeline-playhead.stories.tsx +30 -0
  158. package/src/components/timeline-playhead.test.tsx +11 -0
  159. package/src/components/timeline-playhead.tsx +46 -0
  160. package/src/components/venue-busyness-strip.stories.tsx +66 -0
  161. package/src/components/venue-busyness-strip.tsx +64 -0
  162. package/src/components/venue-grade-dimensions.stories.tsx +83 -0
  163. package/src/components/venue-grade-dimensions.tsx +91 -0
  164. package/src/components/venue-quotes.stories.tsx +59 -0
  165. package/src/components/venue-quotes.tsx +64 -0
  166. package/src/components/venue-signature-block.stories.tsx +68 -0
  167. package/src/components/venue-signature-block.tsx +71 -0
  168. package/src/components/venue-spotlight.stories.tsx +141 -0
  169. package/src/components/venue-spotlight.tsx +236 -0
  170. package/src/components/venue-wall.stories.tsx +78 -0
  171. package/src/components/venue-wall.tsx +185 -0
  172. package/src/components/weekday-theme-banner.stories.tsx +113 -0
  173. package/src/components/weekday-theme-banner.tsx +231 -0
  174. package/src/components/weekend-panel.test.tsx +43 -0
  175. package/src/components/weekend-panel.tsx +142 -108
  176. package/src/hooks/use-drag-swipe.test.tsx +66 -0
  177. package/src/hooks/use-drag-swipe.ts +105 -0
  178. package/src/hooks/use-media-query.ts +31 -0
  179. package/dist/chunk-GPH6L4DX.js +0 -55
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { memo, useState } from "react";
4
+ import { Radio } from "lucide-react";
4
5
  import { cn } from "../lib/utils";
5
6
  import { EventPosterFallback } from "./event-poster-fallback";
6
7
  import { Skeleton } from "./skeleton";
@@ -25,10 +26,25 @@ import {
25
26
  *
26
27
  * THIS ROW DOES NOT DRAW DIVIDERS; ITS CONTAINER DOES. `<HourGroup>` already
27
28
  * draws the rule under the hour heading, so a row-level top separator here
28
- * doubled it directly beneath every hour. `<EventListRow>` and
29
- * `<EventListRowWide>` are different: they stack in a plain list with no
30
- * other rule around them, so their own top separator is the only one there —
31
- * do not carry this rule over to them.
29
+ * doubled it directly beneath every hour; `<HourBand>` rules between its rows
30
+ * with a wrapper. `<EventListRow>` and `<EventListRowWide>` are different:
31
+ * they stack in a plain list with no other rule around them, so their own top
32
+ * separator is the only one there — do not carry this rule over to them.
33
+ *
34
+ * STATE LIVES ON THE META LINE. `isLive` adds the on-air chip and `isEnded`
35
+ * the ended chip beside the time and venue, so a row's state is read in the
36
+ * same glance as its facts. Ended dims the POSTER and moves the title to
37
+ * `--muted-foreground` — never row-level opacity, which composites the text
38
+ * below AA.
39
+ *
40
+ * THE PRICE IS ON THE LAST ROW, right-aligned beside the tags, not on the
41
+ * title line. Two bold things on one line compete — the title and a price
42
+ * both in 700 read as one shout — and the title is the thing the reader is
43
+ * scanning for. `showPrice` renders it (free in `--success`, paid in
44
+ * `--foreground`); without it the row keeps its trailing free pill for the
45
+ * hub's venue block. This is ONE row for the timeline and the list view:
46
+ * the list used to have its own, and the reader met two anatomies for the
47
+ * same object.
32
48
  *
33
49
  * Same contract as the rest: DS-owned view model, injected labels/formatters,
34
50
  * plain `<img>`, anchor whenever `href` is given.
@@ -58,7 +74,7 @@ export type EventCompactRowProps = {
58
74
  * repeating it on each one is noise — the caller has something more
59
75
  * differentiating to say instead (the event's own description). The
60
76
  * timeline keeps the default: there the venue IS what tells rows apart
61
- * across the night. Mirrors `menu-item-row.tsx`'s prop of the same name and
77
+ * across the night. Mirrors `menu-item.tsx`'s prop of the same name and
62
78
  * intent.
63
79
  */
64
80
  subtitle?: string;
@@ -68,6 +84,18 @@ export type EventCompactRowProps = {
68
84
  * rather than truncate, so a chip's own text is never cut mid-word. Cap
69
85
  * the count at the call site — this row does not. */
70
86
  tags?: string[];
87
+ /** Currently running — adds the `labels.liveNow` chip to the meta line. */
88
+ isLive?: boolean;
89
+ /** Already over — dims the poster, mutes the title, adds the `endedLabel` chip. */
90
+ isEnded?: boolean;
91
+ /** Chip text for an ended event, e.g. "Ended". Required to render the chip. */
92
+ endedLabel?: string;
93
+ /**
94
+ * Prints the fee on the meta line — `labels.free` in `--success`, a paid
95
+ * amount via `formatters.price` — instead of the trailing free pill. An
96
+ * unknown fee prints nothing, same as every sibling row.
97
+ */
98
+ showPrice?: boolean;
71
99
  size?: "sm" | "default";
72
100
  href?: string;
73
101
  linkComponent?: React.ComponentType<EventCompactRowLinkProps>;
@@ -86,6 +114,10 @@ export const EventCompactRow = memo(function EventCompactRow({
86
114
  hideTime,
87
115
  subtitle,
88
116
  tags,
117
+ isLive,
118
+ isEnded,
119
+ endedLabel,
120
+ showPrice,
89
121
  size = "default",
90
122
  href,
91
123
  linkComponent: LinkComponent = DefaultLink,
@@ -101,10 +133,22 @@ export const EventCompactRow = memo(function EventCompactRow({
101
133
  const showPoster = !!event.poster_url && !imgError;
102
134
  const venue = event.place_name ?? event.location;
103
135
  const time = formatters.time(event.starts_at);
136
+ const priceText =
137
+ fee.kind === "free"
138
+ ? labels.free
139
+ : fee.kind === "paid"
140
+ ? formatters.price(fee.amountRon)
141
+ : undefined;
142
+ const showEnded = isEnded && !!endedLabel;
143
+ const separator = (
144
+ <span aria-hidden className="text-border">
145
+ ·
146
+ </span>
147
+ );
104
148
 
105
149
  const body = (
106
150
  <>
107
- {/* 64x80 AND PORTRAIT, not a 34px square, and both parts matter.
151
+ {/* 58px WIDE AND PORTRAIT, not a 34px square, and both parts matter.
108
152
  91% of the posters this renders are portrait and ~57% are Instagram's
109
153
  4:5 — so a square crop kept the middle band and threw away the top and
110
154
  bottom, which on a flyer is exactly where the act, the venue and the
@@ -115,8 +159,22 @@ export const EventCompactRow = memo(function EventCompactRow({
115
159
 
116
160
  One size for both `sm` and `default`: no consumer passes `sm` today,
117
161
  and the failure is identical on a phone, so there is no second number
118
- to justify. `size` still drives type scale and pill height. */}
119
- <div className="relative aspect-[4/5] w-16 shrink-0 overflow-hidden rounded-[9px] bg-muted">
162
+ to justify. `size` still drives type scale and pill height.
163
+
164
+ Ended dims the poster to ~45%, not the row: the text keeps full ink
165
+ and moves to the muted tier instead, which stays above AA.
166
+
167
+ 64px at every width — the phone row briefly went to 58 and it was
168
+ too small to read a flyer by. Only the type scale and the padding are
169
+ phone-scoped: a 14px bold title and 11px of vertical padding below
170
+ `lg`; from `lg` the 13px semibold title and 8px padding the desktop
171
+ timeline and the hub's venue block already had. */}
172
+ <div
173
+ className={cn(
174
+ "relative aspect-[4/5] w-16 shrink-0 overflow-hidden rounded-[10px] bg-muted",
175
+ isEnded && "opacity-45",
176
+ )}
177
+ >
120
178
  {showPoster ? (
121
179
  // eslint-disable-next-line @next/next/no-img-element
122
180
  <img
@@ -128,7 +186,7 @@ export const EventCompactRow = memo(function EventCompactRow({
128
186
  onError={() => setImgError(true)}
129
187
  />
130
188
  ) : (
131
- // A bare `bg-muted` rectangle was survivable at 34px. At 64x80 beside
189
+ // A bare `bg-muted` rectangle was survivable at 34px. At 58x72 beside
132
190
  // real posters it reads as a broken image rather than an absent one —
133
191
  // so this row finally joins every sibling in the family in having a
134
192
  // designed fallback.
@@ -146,15 +204,28 @@ export const EventCompactRow = memo(function EventCompactRow({
146
204
  fire. */}
147
205
  <div
148
206
  className={cn(
149
- "font-semibold leading-[1.35]",
207
+ "leading-[1.3]",
150
208
  "transition-colors duration-150 motion-reduce:transition-none",
151
- isSm ? "text-[13.5px]" : "text-[13px]",
152
- (href || onClick) && "group-hover:text-primary"
209
+ isSm
210
+ ? "text-[14.5px] lg:text-[13.5px]"
211
+ : "text-[14px] lg:text-[13px]",
212
+ isEnded
213
+ ? "font-semibold text-muted-foreground"
214
+ : "font-bold text-foreground lg:font-semibold",
215
+ (href || onClick) && "group-hover:text-primary",
153
216
  )}
154
217
  >
155
218
  {event.title}
156
219
  </div>
157
- <div className="truncate text-[11.5px] text-muted-foreground">
220
+ {/* The meta line wraps rather than truncates once it carries chips:
221
+ a state chip pushed off the end would be the one thing the reader
222
+ needed. Venue is the only free-text part and it is what may wrap. */}
223
+ <div
224
+ className={cn(
225
+ "mt-1 flex items-center gap-1.5 text-[11.5px] text-muted-foreground",
226
+ isLive || showEnded ? "flex-wrap" : "truncate",
227
+ )}
228
+ >
158
229
  {subtitle ? (
159
230
  subtitle
160
231
  ) : (
@@ -162,29 +233,68 @@ export const EventCompactRow = memo(function EventCompactRow({
162
233
  {!hideTime && time && (
163
234
  <>
164
235
  <span className="font-mono tabular-nums">{time}</span>
165
- <span aria-hidden> · </span>
236
+ {separator}
166
237
  </>
167
238
  )}
168
- {venue}
239
+ <span className="min-w-0 truncate">{venue}</span>
169
240
  </>
170
241
  )}
242
+ {isLive && (
243
+ <Tag
244
+ size="sm"
245
+ variant="success"
246
+ className="shrink-0 whitespace-nowrap font-extrabold"
247
+ >
248
+ <Radio className="h-2.5 w-2.5" aria-hidden />
249
+ {labels.liveNow}
250
+ </Tag>
251
+ )}
252
+ {showEnded && (
253
+ <Tag
254
+ size="sm"
255
+ variant="default"
256
+ className="shrink-0 whitespace-nowrap font-extrabold"
257
+ >
258
+ {endedLabel}
259
+ </Tag>
260
+ )}
171
261
  </div>
172
- {tags && tags.length > 0 && (
173
- <TagGroup className="mt-1">
174
- {tags.map((tag) => (
175
- <Tag key={tag} size="sm">
176
- {tag}
177
- </Tag>
178
- ))}
179
- </TagGroup>
262
+ {/* The last row: tags on the left, the fee on the right. Either half
263
+ may be absent; the row exists when at least one is there. */}
264
+ {((tags && tags.length > 0) || (showPrice && priceText)) && (
265
+ <div className="mt-1.5 flex items-center gap-2">
266
+ {tags && tags.length > 0 ? (
267
+ <TagGroup className="min-w-0 flex-1">
268
+ {tags.map((tag) => (
269
+ <Tag key={tag} size="sm" variant="quiet">
270
+ {tag}
271
+ </Tag>
272
+ ))}
273
+ </TagGroup>
274
+ ) : (
275
+ <span className="flex-1" />
276
+ )}
277
+ {showPrice && priceText && (
278
+ <span
279
+ className={cn(
280
+ "shrink-0 text-[13px] tabular-nums",
281
+ fee.kind === "free"
282
+ ? "font-semibold text-success"
283
+ : "font-bold text-foreground",
284
+ )}
285
+ >
286
+ {priceText}
287
+ </span>
288
+ )}
289
+ </div>
180
290
  )}
181
291
  </div>
182
292
 
183
- {fee.kind === "free" && (
293
+ {!showPrice && fee.kind === "free" && (
184
294
  <span
185
295
  className={cn(
186
296
  "inline-flex shrink-0 items-center rounded-full border border-success/40 px-2 font-semibold text-success",
187
- isSm ? "h-[22px] text-[10.5px]" : "h-6 text-[11px]"
297
+ isSm ? "h-[22px] text-[10.5px]" : "h-6 text-[11px]",
188
298
  )}
189
299
  >
190
300
  {labels.free}
@@ -193,9 +303,9 @@ export const EventCompactRow = memo(function EventCompactRow({
193
303
  </>
194
304
  );
195
305
 
196
- // `items-start`, not `items-center`: an 80px poster is taller than a one-line
197
- // title over its sub-line, so centring floated the text in empty space.
198
- // `EventListRow` already made this call at its own 72px poster.
306
+ // `items-start`, not `items-center`: a 72px-tall poster is taller than a
307
+ // one-line title over its sub-line, so centring floated the text in empty
308
+ // space. `EventListRow` makes the same call.
199
309
  //
200
310
  // THE HOVER WASH IS `bg-foreground/5`, AND THE TOKEN CHOICE IS LOAD-BEARING.
201
311
  // This row renders on two different planes: the timeline puts it straight on
@@ -211,11 +321,11 @@ export const EventCompactRow = memo(function EventCompactRow({
211
321
  // same shape `EventIndexRow` uses. No transform: this is a zero-gap stacked
212
322
  // list, so a lift would overlap its neighbours rather than read as elevation.
213
323
  const rootClasses = cn(
214
- "group relative -mx-2.5 flex w-full items-start gap-[11px] rounded-lg px-2.5 py-2 text-left",
324
+ "group relative -mx-2.5 flex w-full items-start gap-3 rounded-lg px-2.5 py-[11px] text-left lg:gap-[11px] lg:py-2",
215
325
  "transition-colors duration-150 motion-reduce:transition-none",
216
326
  (href || onClick) &&
217
327
  "cursor-pointer hover:bg-foreground/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
218
- className
328
+ className,
219
329
  );
220
330
 
221
331
  if (href) {
@@ -223,7 +333,9 @@ export const EventCompactRow = memo(function EventCompactRow({
223
333
  <LinkComponent
224
334
  href={href}
225
335
  className={rootClasses}
226
- onClick={onClick ? (mouseEvent) => onClick(event, mouseEvent) : undefined}
336
+ onClick={
337
+ onClick ? (mouseEvent) => onClick(event, mouseEvent) : undefined
338
+ }
227
339
  >
228
340
  {body}
229
341
  </LinkComponent>
@@ -232,7 +344,11 @@ export const EventCompactRow = memo(function EventCompactRow({
232
344
 
233
345
  if (onClick) {
234
346
  return (
235
- <button type="button" className={rootClasses} onClick={(e) => onClick(event, e)}>
347
+ <button
348
+ type="button"
349
+ className={rootClasses}
350
+ onClick={(e) => onClick(event, e)}
351
+ >
236
352
  {body}
237
353
  </button>
238
354
  );
@@ -248,22 +364,30 @@ export type EventCompactRowSkeletonProps = {
248
364
  };
249
365
 
250
366
  /** Mirrors `<EventCompactRow>`'s geometry exactly so nothing shifts when data lands. */
251
- export function EventCompactRowSkeleton({ size = "default", className }: EventCompactRowSkeletonProps) {
367
+ export function EventCompactRowSkeleton({
368
+ size = "default",
369
+ className,
370
+ }: EventCompactRowSkeletonProps) {
252
371
  const isSm = size === "sm";
253
372
 
254
373
  return (
255
374
  <div
256
375
  aria-hidden="true"
257
376
  className={cn(
258
- "relative -mx-2.5 flex w-full items-start gap-[11px] rounded-lg px-2.5 py-2 text-left",
259
- className
377
+ "relative -mx-2.5 flex w-full items-start gap-3 rounded-lg px-2.5 py-[11px] text-left lg:gap-[11px] lg:py-2",
378
+ className,
260
379
  )}
261
380
  >
262
- <Skeleton className="aspect-[4/5] w-16 shrink-0 rounded-[9px]" />
381
+ <Skeleton className="aspect-[4/5] w-16 shrink-0 rounded-[10px]" />
263
382
 
264
383
  <div className="min-w-0 flex-1">
265
- <Skeleton className={cn(isSm ? "h-[13.5px]" : "h-[13px]", "w-2/5")} />
266
- <Skeleton className="mt-0.5 h-[11.5px] w-1/3" />
384
+ <Skeleton
385
+ className={cn(
386
+ isSm ? "h-[14.5px] lg:h-[13.5px]" : "h-[14px] lg:h-[13px]",
387
+ "w-3/5",
388
+ )}
389
+ />
390
+ <Skeleton className="mt-1 h-[11.5px] w-1/3" />
267
391
  </div>
268
392
  </div>
269
393
  );
@@ -76,7 +76,9 @@ export function EventDayHeader({
76
76
  <div
77
77
  className={cn(
78
78
  "font-black leading-[0.82] tracking-[-0.05em] tabular-nums",
79
- large ? "text-[58px]" : "text-[40px]"
79
+ // `sm` is the phone scale: 30px, the design's app day head. 40px
80
+ // was a page-scale number that took a third of a 390px row.
81
+ large ? "text-[58px]" : "text-[30px] leading-[0.86]"
80
82
  )}
81
83
  >
82
84
  {dayNumber}
@@ -28,6 +28,12 @@ import { Skeleton } from "./skeleton";
28
28
  */
29
29
 
30
30
  export type EventDaySeparatorProps = {
31
+ /**
32
+ * `always` (default) draws the trailing rule at every width. `lg` drops it
33
+ * below `lg`, where the list is an app sheet whose day heads are bold
34
+ * labels alone — the rows below rule themselves — and keeps it from `lg`.
35
+ */
36
+ rule?: "always" | "lg";
31
37
  label: string;
32
38
  count?: string;
33
39
  size?: "sm" | "default";
@@ -42,6 +48,7 @@ export function EventDaySeparator({
42
48
  size = "default",
43
49
  as: Tag = "h2",
44
50
  className,
51
+ rule = "always",
45
52
  }: EventDaySeparatorProps) {
46
53
  return (
47
54
  <div
@@ -61,7 +68,7 @@ export function EventDaySeparator({
61
68
  </span>
62
69
  )}
63
70
 
64
- <Separator className="flex-1" />
71
+ <Separator className={cn("flex-1", rule === "lg" && "hidden lg:block")} />
65
72
  </div>
66
73
  );
67
74
  }