@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
@@ -2,9 +2,20 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
 
4
4
  /**
5
- * EventHubHero — the hub's opening block: an eyebrow, a big headline, an
6
- * intro line and a stats row on the left; an arbitrary slot (the poster
7
- * stack, in the source design) on the right. Stacks on mobile.
5
+ * EventHubHero — the hub's opening block. On desktop: an eyebrow, a big
6
+ * headline, an intro paragraph and a stats row on the left; an arbitrary slot
7
+ * (the poster stack, in the source design) on the right.
8
+ *
9
+ * BELOW `lg` IT IS A MASTHEAD, NOT A HERO. One headline line, the eyebrow
10
+ * demoted to a sub-line beneath it, no intro, and the figures as a swipeable
11
+ * rail of chips that bleeds to the screen edge. The first real content lands
12
+ * roughly 250px sooner than under the web-shaped hero — on a phone the page
13
+ * should show, not narrate. Same markup at every width; only the classes
14
+ * change, so the copy is authored once.
15
+ *
16
+ * A stat with `tone: "live"` is the one that is happening right now: its
17
+ * chip takes a `--success` border and value, the same live colour every
18
+ * events surface uses.
8
19
  *
9
20
  * All copy and stat values arrive pre-formatted — the DS holds no `Intl`
10
21
  * locale and does not format numbers.
@@ -12,6 +23,8 @@ import * as React from 'react';
12
23
  type EventHubHeroStat = {
13
24
  value: string;
14
25
  label: string;
26
+ /** `live` marks the figure that is happening right now. */
27
+ tone?: "default" | "live";
15
28
  };
16
29
  type EventHubHeroProps = {
17
30
  /** Small caps-style label above the title, e.g. "Updated today". */
@@ -19,11 +32,19 @@ type EventHubHeroProps = {
19
32
  title: string;
20
33
  intro: string;
21
34
  stats: EventHubHeroStat[];
35
+ /**
36
+ * Accessible name for the stats rail, e.g. "Key figures". When given, the
37
+ * rail is a named, focusable region so a keyboard can reach chips clipped
38
+ * by the phone's edge. Optional so existing consumers keep compiling — but
39
+ * pass it: without a name the rail cannot be focusable, and a phone reader
40
+ * on a keyboard cannot reach the last figures.
41
+ */
42
+ statsLabel?: string;
22
43
  /** The right-column slot — the poster stack in the source design. */
23
44
  aside?: React.ReactNode;
24
45
  className?: string;
25
46
  };
26
- declare function EventHubHero({ eyebrow, title, intro, stats, aside, className }: EventHubHeroProps): react_jsx_runtime.JSX.Element;
47
+ declare function EventHubHero({ eyebrow, title, intro, stats, statsLabel, aside, className, }: EventHubHeroProps): react_jsx_runtime.JSX.Element;
27
48
  type EventHubHeroSkeletonProps = {
28
49
  /** The right-column slot, e.g. a `PosterStack`-shaped placeholder. Mirrors `aside` on the real component. */
29
50
  aside?: React.ReactNode;
@@ -3,7 +3,15 @@ import { cn } from '../chunk-FEK5XGZW.js';
3
3
  import '../chunk-3GWWZKX7.js';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
6
- function EventHubHero({ eyebrow, title, intro, stats, aside, className }) {
6
+ function EventHubHero({
7
+ eyebrow,
8
+ title,
9
+ intro,
10
+ stats,
11
+ statsLabel,
12
+ aside,
13
+ className
14
+ }) {
7
15
  return /* @__PURE__ */ jsxs(
8
16
  "div",
9
17
  {
@@ -12,14 +20,69 @@ function EventHubHero({ eyebrow, title, intro, stats, aside, className }) {
12
20
  className
13
21
  ),
14
22
  children: [
15
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
16
- /* @__PURE__ */ jsx("p", { className: "text-[11.5px] font-extrabold tracking-[0.12em] text-muted-foreground", children: eyebrow }),
17
- /* @__PURE__ */ jsx("h1", { className: "text-[31px] font-black leading-[1.05] tracking-[-0.035em] text-foreground md:text-[42px] md:tracking-[-0.04em]", children: title }),
18
- /* @__PURE__ */ jsx("p", { className: "max-w-[520px] text-[14px] leading-[1.6] text-muted-foreground md:text-[15px] md:leading-[1.65]", children: intro }),
19
- /* @__PURE__ */ jsx("div", { className: "flex gap-[22px] pt-1.5 md:gap-[30px]", children: stats.map((stat) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
20
- /* @__PURE__ */ jsx("span", { className: "text-[24px] font-black leading-none tracking-[-0.03em] tabular-nums text-foreground md:text-[30px]", children: stat.value }),
21
- /* @__PURE__ */ jsx("span", { className: "mt-1 text-[11px] text-muted-foreground md:mt-[5px] md:text-[12.5px]", children: stat.label })
22
- ] }, stat.label)) })
23
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 lg:gap-4", children: [
24
+ /* @__PURE__ */ jsx(
25
+ "p",
26
+ {
27
+ className: cn(
28
+ "order-2 text-[13px] text-muted-foreground",
29
+ "lg:order-none lg:text-[11.5px] lg:font-extrabold lg:tracking-[0.12em]"
30
+ ),
31
+ children: eyebrow
32
+ }
33
+ ),
34
+ /* @__PURE__ */ jsx(
35
+ "h1",
36
+ {
37
+ className: cn(
38
+ "order-1 text-[26px] font-black leading-[1.1] tracking-[-0.035em] text-foreground",
39
+ "lg:order-none lg:text-[42px] lg:leading-[1.05] lg:tracking-[-0.04em]"
40
+ ),
41
+ children: title
42
+ }
43
+ ),
44
+ /* @__PURE__ */ jsx("p", { className: "hidden max-w-[520px] text-[15px] leading-[1.65] text-muted-foreground lg:order-none lg:block", children: intro }),
45
+ /* @__PURE__ */ jsx(
46
+ "div",
47
+ {
48
+ role: statsLabel ? "region" : void 0,
49
+ "aria-label": statsLabel,
50
+ tabIndex: statsLabel ? 0 : void 0,
51
+ className: cn(
52
+ "order-3 -mx-4 flex gap-2 overflow-x-auto px-4 pt-2 scrollbar-hide",
53
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
54
+ "lg:order-none lg:mx-0 lg:gap-[30px] lg:overflow-visible lg:px-0 lg:pt-1.5"
55
+ ),
56
+ children: stats.map((stat) => {
57
+ const isLive = stat.tone === "live";
58
+ return /* @__PURE__ */ jsxs(
59
+ "div",
60
+ {
61
+ className: cn(
62
+ "flex min-w-[106px] shrink-0 flex-col rounded-[14px] border bg-card px-[13px] py-2.5",
63
+ isLive ? "border-success/40" : "border-border",
64
+ "lg:min-w-0 lg:rounded-none lg:border-0 lg:bg-transparent lg:p-0"
65
+ ),
66
+ children: [
67
+ /* @__PURE__ */ jsx(
68
+ "span",
69
+ {
70
+ className: cn(
71
+ "text-[19px] font-black leading-none tracking-[-0.02em] tabular-nums",
72
+ isLive ? "text-success" : "text-foreground",
73
+ "lg:text-[30px] lg:tracking-[-0.03em]"
74
+ ),
75
+ children: stat.value
76
+ }
77
+ ),
78
+ /* @__PURE__ */ jsx("span", { className: "mt-0.5 text-[11px] text-muted-foreground lg:mt-[5px] lg:text-[12.5px]", children: stat.label })
79
+ ]
80
+ },
81
+ stat.label
82
+ );
83
+ })
84
+ }
85
+ )
23
86
  ] }),
24
87
  aside && /* @__PURE__ */ jsx("div", { className: "min-w-0", children: aside })
25
88
  ]
@@ -36,17 +99,24 @@ function EventHubHeroSkeleton({ aside, className }) {
36
99
  className
37
100
  ),
38
101
  children: [
39
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
40
- /* @__PURE__ */ jsx(Skeleton, { className: "h-[11.5px] w-28" }),
41
- /* @__PURE__ */ jsx(Skeleton, { className: "h-[31px] w-full max-w-[420px] md:h-[42px]" }),
42
- /* @__PURE__ */ jsxs("div", { className: "flex max-w-[520px] flex-col gap-1.5", children: [
43
- /* @__PURE__ */ jsx(Skeleton, { className: "h-[14px] w-full md:h-[15px]" }),
44
- /* @__PURE__ */ jsx(Skeleton, { className: "h-[14px] w-4/5 md:h-[15px]" })
102
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 lg:gap-4", children: [
103
+ /* @__PURE__ */ jsx(Skeleton, { className: "order-2 h-[13px] w-40 lg:order-none lg:h-[11.5px] lg:w-28" }),
104
+ /* @__PURE__ */ jsx(Skeleton, { className: "order-1 h-[26px] w-full max-w-[420px] lg:order-none lg:h-[42px]" }),
105
+ /* @__PURE__ */ jsxs("div", { className: "hidden max-w-[520px] flex-col gap-1.5 lg:flex", children: [
106
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[15px] w-full" }),
107
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[15px] w-4/5" })
45
108
  ] }),
46
- /* @__PURE__ */ jsx("div", { className: "flex gap-[22px] pt-1.5 md:gap-[30px]", children: Array.from({ length: 3 }, (_, index) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
47
- /* @__PURE__ */ jsx(Skeleton, { className: "h-[24px] w-10 md:h-[30px]" }),
48
- /* @__PURE__ */ jsx(Skeleton, { className: "mt-1 h-[11px] w-16 md:mt-[5px] md:h-[12.5px]" })
49
- ] }, index)) })
109
+ /* @__PURE__ */ jsx("div", { className: "order-3 -mx-4 flex gap-2 overflow-hidden px-4 pt-2 lg:order-none lg:mx-0 lg:gap-[30px] lg:px-0 lg:pt-1.5", children: Array.from({ length: 4 }, (_, index) => /* @__PURE__ */ jsxs(
110
+ "div",
111
+ {
112
+ className: "flex min-w-[106px] shrink-0 flex-col rounded-[14px] border border-border bg-card px-[13px] py-2.5 lg:min-w-0 lg:rounded-none lg:border-0 lg:bg-transparent lg:p-0",
113
+ children: [
114
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[19px] w-8 lg:h-[30px] lg:w-10" }),
115
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-0.5 h-[11px] w-16 lg:mt-[5px] lg:h-[12.5px]" })
116
+ ]
117
+ },
118
+ index
119
+ )) })
50
120
  ] }),
51
121
  aside && /* @__PURE__ */ jsx("div", { className: "min-w-0", children: aside })
52
122
  ]
@@ -1,6 +1,6 @@
1
1
  import { Separator } from '../chunk-WSRWFA6K.js';
2
- import { Tag } from '../chunk-ZDAHKI3A.js';
3
2
  import { resolveEventEntryFee } from '../chunk-DNSXMHYX.js';
3
+ import { Tag } from '../chunk-ZDAHKI3A.js';
4
4
  import { EventPosterFallback } from '../chunk-FDITZ2VM.js';
5
5
  import { Skeleton } from '../chunk-QXHMPJ35.js';
6
6
  import { buttonVariants } from '../chunk-H3BV4VAG.js';
@@ -21,11 +21,17 @@ import { EventPreview, EventListRowLabels, EventDateBadgeFormatters } from './ev
21
21
  * has the width for one and its row root is a container rather than a single
22
22
  * anchor. If a CTA comes back here, it has to be a real one, not a span.
23
23
  *
24
- * NOTE ON WEIGHT: nothing in this row is heavier than 600, and only the title
25
- * and the date badge reach it. Eight of these stack per screen, and at that
26
- * density hierarchy comes from size and ink tier, not from weight — a field of
27
- * bold text has no foreground. `Free` is the one exception (600 plus
28
- * `text-success`), because it is an inducement rather than an attribute.
24
+ * NOTE ON WEIGHT: the title and the fee are the only bold things in this row.
25
+ * Eight of these stack per screen, and at that density hierarchy comes from
26
+ * size and ink tier as much as weight — so everything below the title line is
27
+ * regular, muted, and small. The fee is bold because it is the row's one
28
+ * inducement, and it sits on the TITLE line, right-aligned, where a price is
29
+ * read against the thing it buys rather than lost among the meta.
30
+ *
31
+ * NOTE ON THE DATE BADGE: `hideDate` drops it. Inside a dated group — the list
32
+ * view's "Today · Monday 7 September" separators — every row's badge repeats
33
+ * the heading eight times per screen; the heading carries the date and the
34
+ * rows carry the time. The badge stays available for undated lists.
29
35
  *
30
36
  * Same contract as the rest: DS-owned view model, injected labels and
31
37
  * formatters, plain `<img>`, anchor whenever `href` is given.
@@ -67,16 +73,23 @@ type EventListRowProps = {
67
73
  * line. Same prop and same reason as `EventListRowWide` and `EventIndexRow`.
68
74
  */
69
75
  hideRule?: boolean;
76
+ /**
77
+ * Drops the leading date badge. Pass it when the rows sit under a dated
78
+ * heading that already names the day; the row then leads with its poster.
79
+ */
80
+ hideDate?: boolean;
70
81
  };
71
82
  declare const EventListRow: React$1.NamedExoticComponent<EventListRowProps>;
72
83
  type EventListRowSkeletonProps = {
73
84
  /** Matches `EventListRowProps["hideRule"]` — drop the top rule on the first row of a day group. */
74
85
  hideRule?: boolean;
86
+ /** Matches `EventListRowProps["hideDate"]`. */
87
+ hideDate?: boolean;
75
88
  /** Reserve the chip line. Matches the real row, where it collapses on events with no live status and no tags. */
76
89
  showTags?: boolean;
77
90
  className?: string;
78
91
  };
79
92
  /** Mirrors `<EventListRow>`'s geometry exactly so nothing shifts when data lands. */
80
- declare function EventListRowSkeleton({ hideRule, showTags, className, }: EventListRowSkeletonProps): react_jsx_runtime.JSX.Element;
93
+ declare function EventListRowSkeleton({ hideRule, hideDate, showTags, className, }: EventListRowSkeletonProps): react_jsx_runtime.JSX.Element;
81
94
 
82
95
  export { EventListRow, type EventListRowLinkProps, type EventListRowProps, EventListRowSkeleton, type EventListRowSkeletonProps };
@@ -1,7 +1,7 @@
1
1
  import { Separator } from '../chunk-WSRWFA6K.js';
2
2
  import { TagGroup } from '../chunk-6XMYEZVR.js';
3
- import { Tag } from '../chunk-ZDAHKI3A.js';
4
3
  import { resolveEventEntryFee } from '../chunk-DNSXMHYX.js';
4
+ import { Tag } from '../chunk-ZDAHKI3A.js';
5
5
  import { EventPosterFallback } from '../chunk-FDITZ2VM.js';
6
6
  import { Skeleton } from '../chunk-QXHMPJ35.js';
7
7
  import { cn } from '../chunk-FEK5XGZW.js';
@@ -27,7 +27,8 @@ var EventListRow = memo(function EventListRow2({
27
27
  priority,
28
28
  tags,
29
29
  fallback = /* @__PURE__ */ jsx(EventPosterFallback, {}),
30
- hideRule
30
+ hideRule,
31
+ hideDate
31
32
  }) {
32
33
  var _a;
33
34
  const [imgError, setImgError] = useState(false);
@@ -37,10 +38,13 @@ var EventListRow = memo(function EventListRow2({
37
38
  const priceText = fee.kind === "free" ? labels.free : fee.kind === "paid" ? formatters.price(fee.amountRon) : void 0;
38
39
  const body = /* @__PURE__ */ jsxs(Fragment, { children: [
39
40
  !hideRule && /* @__PURE__ */ jsx(Separator, { className: "absolute inset-x-0 top-0" }),
40
- /* @__PURE__ */ jsxs(
41
+ !hideDate && /* @__PURE__ */ jsxs(
41
42
  "div",
42
43
  {
43
- className: cn("w-[42px] shrink-0 rounded-[9px] py-1.5 text-center", isLive && "bg-success/10"),
44
+ className: cn(
45
+ "w-[42px] shrink-0 rounded-[9px] py-1.5 text-center",
46
+ isLive && "bg-success/10"
47
+ ),
44
48
  children: [
45
49
  /* @__PURE__ */ jsx(
46
50
  "div",
@@ -65,7 +69,7 @@ var EventListRow = memo(function EventListRow2({
65
69
  ]
66
70
  }
67
71
  ),
68
- /* @__PURE__ */ jsx("div", { className: "aspect-square w-[72px] shrink-0 overflow-hidden rounded-[9px] bg-muted", children: showPoster ? (
72
+ /* @__PURE__ */ jsx("div", { className: "aspect-[4/5] w-[58px] shrink-0 overflow-hidden rounded-[10px] bg-muted", children: showPoster ? (
69
73
  // eslint-disable-next-line @next/next/no-img-element
70
74
  /* @__PURE__ */ jsx(
71
75
  "img",
@@ -80,38 +84,64 @@ var EventListRow = memo(function EventListRow2({
80
84
  )
81
85
  ) : fallback }),
82
86
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
83
- /* @__PURE__ */ jsx("div", { className: "text-[15px] font-semibold leading-[1.3] tracking-[-0.01em]", children: event.title }),
84
- /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2 text-xs text-muted-foreground", children: [
85
- /* @__PURE__ */ jsx("span", { className: "shrink-0 tabular-nums text-foreground", children: formatters.time(event.starts_at) }),
86
- /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-1", children: [
87
- /* @__PURE__ */ jsx(MapPin, { className: "h-3 w-3 shrink-0", "aria-hidden": true }),
88
- /* @__PURE__ */ jsx("span", { className: "truncate", children: venue })
89
- ] }),
90
- isSoldOut ? /* @__PURE__ */ jsx(Tag, { size: "sm", variant: "quiet", className: "shrink-0 whitespace-nowrap", children: labels.soldOut }) : priceText && /* @__PURE__ */ jsx(
87
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2.5", children: [
88
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1 text-[14px] font-bold leading-[1.3] tracking-[-0.01em]", children: event.title }),
89
+ isSoldOut ? /* @__PURE__ */ jsx(
90
+ Tag,
91
+ {
92
+ size: "sm",
93
+ variant: "quiet",
94
+ className: "shrink-0 whitespace-nowrap",
95
+ children: labels.soldOut
96
+ }
97
+ ) : priceText && /* @__PURE__ */ jsx(
91
98
  "span",
92
99
  {
93
100
  className: cn(
94
- "shrink-0 tabular-nums",
95
- fee.kind === "free" && "font-semibold text-success"
101
+ "shrink-0 text-[13.5px] font-extrabold tabular-nums",
102
+ fee.kind === "free" ? "text-success" : "text-foreground"
96
103
  ),
97
104
  children: priceText
98
105
  }
99
106
  )
100
107
  ] }),
101
- (isLive || tags && tags.length > 0) && /* @__PURE__ */ jsxs(TagGroup, { className: "mt-1.5 h-[22px] overflow-hidden", children: [
102
- isLive && /* @__PURE__ */ jsxs(Tag, { size: "sm", variant: "success", className: "shrink-0 whitespace-nowrap", children: [
103
- /* @__PURE__ */ jsx(Radio, { className: "h-2.5 w-2.5", "aria-hidden": true }),
104
- labels.liveNow
108
+ /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-1.5 text-[11.5px] text-muted-foreground", children: [
109
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 font-mono tabular-nums", children: formatters.time(event.starts_at) }),
110
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-border", children: "\xB7" }),
111
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-1", children: [
112
+ /* @__PURE__ */ jsx(MapPin, { className: "h-3 w-3 shrink-0", "aria-hidden": true }),
113
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: venue })
105
114
  ] }),
106
- tags == null ? void 0 : tags.map((tag) => /* @__PURE__ */ jsx(Tag, { size: "sm", variant: "quiet", className: "shrink-0 whitespace-nowrap", children: tag }, tag))
107
- ] })
115
+ isLive && /* @__PURE__ */ jsxs(
116
+ Tag,
117
+ {
118
+ size: "sm",
119
+ variant: "success",
120
+ className: "shrink-0 whitespace-nowrap font-extrabold",
121
+ children: [
122
+ /* @__PURE__ */ jsx(Radio, { className: "h-2.5 w-2.5", "aria-hidden": true }),
123
+ labels.liveNow
124
+ ]
125
+ }
126
+ )
127
+ ] }),
128
+ tags && tags.length > 0 && /* @__PURE__ */ jsx(TagGroup, { className: "mt-1.5 h-[22px] overflow-hidden", children: tags.map((tag) => /* @__PURE__ */ jsx(
129
+ Tag,
130
+ {
131
+ size: "sm",
132
+ variant: "quiet",
133
+ className: "shrink-0 whitespace-nowrap",
134
+ children: tag
135
+ },
136
+ tag
137
+ )) })
108
138
  ] })
109
139
  ] });
110
140
  const rootClasses = cn(
111
- // `py-3`, not `py-3.5`: the chip line adds a third line back, and 8px of
112
- // padding pays for most of it. Rows with a one-line title and no chips are
113
- // still poster-driven and end up SHORTER than before.
114
- "relative flex w-full items-start gap-3 py-3 text-left",
141
+ // `py-[11px]`: the poster is 72px tall and a one-line title, meta and a
142
+ // chip line come to ~70px, so the row is poster-driven at ~94px about
143
+ // eight per screen, which is the list view's reason to exist.
144
+ "relative flex w-full items-start gap-3 py-[11px] text-left",
115
145
  isSoldOut && "opacity-60",
116
146
  (href || onClick) && "cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
117
147
  className
@@ -128,12 +158,21 @@ var EventListRow = memo(function EventListRow2({
128
158
  );
129
159
  }
130
160
  if (onClick) {
131
- return /* @__PURE__ */ jsx("button", { type: "button", className: rootClasses, onClick: (e) => onClick(event, e), children: body });
161
+ return /* @__PURE__ */ jsx(
162
+ "button",
163
+ {
164
+ type: "button",
165
+ className: rootClasses,
166
+ onClick: (e) => onClick(event, e),
167
+ children: body
168
+ }
169
+ );
132
170
  }
133
171
  return /* @__PURE__ */ jsx("div", { className: rootClasses, children: body });
134
172
  });
135
173
  function EventListRowSkeleton({
136
174
  hideRule,
175
+ hideDate,
137
176
  showTags = true,
138
177
  className
139
178
  }) {
@@ -141,24 +180,29 @@ function EventListRowSkeleton({
141
180
  "div",
142
181
  {
143
182
  "aria-hidden": "true",
144
- className: cn("relative flex w-full items-start gap-3 py-3 text-left", className),
183
+ className: cn(
184
+ "relative flex w-full items-start gap-3 py-[11px] text-left",
185
+ className
186
+ ),
145
187
  children: [
146
188
  !hideRule && /* @__PURE__ */ jsx(Separator, { className: "absolute inset-x-0 top-0" }),
147
- /* @__PURE__ */ jsxs("div", { className: "w-[42px] shrink-0 rounded-[9px] py-1.5 text-center", children: [
189
+ !hideDate && /* @__PURE__ */ jsxs("div", { className: "w-[42px] shrink-0 rounded-[9px] py-1.5 text-center", children: [
148
190
  /* @__PURE__ */ jsx(Skeleton, { className: "mx-auto h-4 w-5" }),
149
191
  /* @__PURE__ */ jsx(Skeleton, { className: "mx-auto mt-[3px] h-[10px] w-6" })
150
192
  ] }),
151
- /* @__PURE__ */ jsx(Skeleton, { className: "aspect-square w-[72px] shrink-0 rounded-[9px]" }),
193
+ /* @__PURE__ */ jsx(Skeleton, { className: "aspect-[4/5] w-[58px] shrink-0 rounded-[10px]" }),
152
194
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
153
- /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
154
- /* @__PURE__ */ jsx(Skeleton, { className: "h-[15px] w-full" }),
155
- /* @__PURE__ */ jsx(Skeleton, { className: "h-[15px] w-2/3" })
195
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2.5", children: [
196
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
197
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[14px] w-full" }),
198
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[14px] w-2/3" })
199
+ ] }),
200
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[13.5px] w-12 shrink-0" })
156
201
  ] }),
157
- /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2", children: [
202
+ /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-1.5", children: [
158
203
  /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-10" }),
159
204
  /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-3 shrink-0 rounded-full" }),
160
- /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" }),
161
- /* @__PURE__ */ jsx(Skeleton, { className: "ml-auto h-3 w-12" })
205
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" })
162
206
  ] }),
163
207
  showTags && /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex items-center gap-1.5", children: [
164
208
  /* @__PURE__ */ jsx(Skeleton, { className: "h-[22px] w-14 rounded-full" }),
@@ -4,65 +4,63 @@ import * as React from 'react';
4
4
  /**
5
5
  * HourBand — one hour on the timeline's axis, with that hour's events beside it.
6
6
  *
7
- * The design's mobile timeline is deliberately plain: a 52px gutter carrying a
8
- * hairline and an hour puck, and full-width cards to its right. Nothing else.
9
- * The cards inside carry no timestamp of their own this band IS the
10
- * timestamp, which is why `EventCard` has `hideWhen`.
7
+ * The mobile timeline is an app list, not a page: a 58px gutter carrying a
8
+ * filled hour chip with a hairline dropping from beneath it, and the hour's
9
+ * rows to the right, separated by hairlines of their own. The rows carry no
10
+ * timestamp — this band IS the timestamp, which is why `EventCard` has
11
+ * `hideWhen` and `EventCompactRow` has `hideTime`.
11
12
  *
12
- * The puck is the shared `TimelineHourPuck`, sitting ON the line with a
13
- * background fill punching through it so the hairline reads as continuous
14
- * behind the label. It used to be a second, hand-rolled copy of the desktop
15
- * band's puck, and the two had drifted apart this one borderless and
16
- * `rounded-md px-1.5`, the desktop one bordered and `rounded-[7px] px-[7px]`.
17
- * Sharing the object changes this gutter's pixels: the mobile puck now carries
18
- * a border, which is what makes it read as clipped onto the rail rather than
19
- * text floating over it, and matches the station on the desktop spine.
13
+ * The chip is the shared `TimelineHourPuck` in its `chip` variant, so the
14
+ * desktop spine's station and this gutter's label are one object with two
15
+ * looks rather than two objects that drift. The hairline starts BELOW the chip
16
+ * rather than running behind it: a chip is a label at the top of its hour, a
17
+ * station is a tick on a continuous rail, and the two read differently.
20
18
  *
21
- * `isLive` turns the puck green-bordered and reveals the NOW label beneath it,
22
- * which is why live bands need extra top padding on the content column the
23
- * label occupies space the cards would otherwise start in.
19
+ * `isLive` tints the chip and the hairline with `--success`; the live label is
20
+ * kept for screen readers (the chip variant hides it visually). The playhead
21
+ * the exact current time is a separate `TimelinePlayhead` rendered between
22
+ * bands by the caller, because an hour spans sixty minutes and "now" is one of
23
+ * them.
24
24
  *
25
- * ── Why the gap is 24px and not 12px ──────────────────────────────────────
26
- * THE PUCK IS WIDER THAN THE GUTTER IT SITS IN, and the gap is what absorbs
27
- * the difference. A 12-hour locale renders "09:00 AM" 8 monospace glyphs at
28
- * 12.5px (~60px) plus `px-[7px]` twice and a border twice, so ~76px of puck
29
- * centred on a 52px gutter, overflowing ~12px on each side. At the original
30
- * `gap-3` that right-hand overflow exactly consumed the gap and the puck's
31
- * edge landed ON the content column, which read as the hairline colliding
32
- * with the rows beside it.
33
- *
34
- * 24px leaves ~12px of real clearance at the widest label. Do not tighten it
35
- * back without re-deriving against a 12-hour locale: a 24-hour one ("09:00")
36
- * is ~30px narrower and hides the problem completely.
25
+ * ROWS ARE SEPARATED HERE, NOT IN THE ROW. `EventCompactRow` deliberately
26
+ * draws no divider (its container does see its docblock), so this band wraps
27
+ * each child and rules between them. The wrapper, not the child, carries the
28
+ * rule, so the row's own negative-margin hover wash is untouched. Children are
29
+ * read with `Children.toArray`, which drops `null`/`false` so a conditional
30
+ * first row never inherits a rule meant for a second; pass rows as siblings,
31
+ * not inside a fragment a fragment is one child and gets one wrapper.
37
32
  */
38
33
  type HourBandProps = {
39
34
  /** The hour, already formatted and localised — "20:00". */
40
35
  time: string;
41
36
  /** Marks this as the hour currently in progress. */
42
37
  isLive?: boolean;
43
- /** Shown under the puck when live, e.g. "NOW ON". Required to render it. */
38
+ /** Screen-reader text for the live hour, e.g. "Now on". Required to render it. */
44
39
  liveLabel?: string;
45
- /** The hour's events. */
40
+ /** The hour's events. Each direct child is one row or card. */
46
41
  children: React.ReactNode;
42
+ /**
43
+ * `rows` (default): compact rows, ruled between with a Separator. `cards`:
44
+ * poster cards, stacked with a 16px gap and no rules — a card is its own
45
+ * frame, and a hairline between two posters reads as a third object.
46
+ */
47
+ layout?: "rows" | "cards";
47
48
  className?: string;
48
49
  };
49
- declare function HourBand({ time, isLive, liveLabel, children, className }: HourBandProps): react_jsx_runtime.JSX.Element;
50
+ declare function HourBand({ time, isLive, liveLabel, children, layout, className, }: HourBandProps): react_jsx_runtime.JSX.Element;
50
51
  type HourBandSkeletonProps = {
51
- /** Cards to reserve space for. The design's loading frame shows two. */
52
+ /** Rows to reserve space for. */
52
53
  cardCount?: number;
53
54
  className?: string;
54
55
  };
55
56
  /**
56
- * The mobile timeline's loading state, mirroring `HourBand` exactly — same 52px
57
- * gutter, same hairline, same content gap — so nothing jumps when data lands.
58
- *
59
- * The puck is omitted rather than blocked out: the hour is not known until the
60
- * data arrives, and a grey lozenge on the axis reads as a real, unreadable
61
- * timestamp. The hairline alone still says "this is a time axis".
57
+ * The mobile timeline's loading state, mirroring `HourBand` exactly — same
58
+ * gutter, same hairline, same row rhythm — so nothing jumps when data lands.
62
59
  *
63
- * Card footprints come from the design's own loading frame: a 220px poster with
64
- * an 16px title bar and a 12px meta bar, then a 170px poster with a 15px title.
60
+ * The chip is blocked out at its real size rather than omitted: it is a fixed
61
+ * 58x24 lozenge, so a grey one reads as "a time goes here" without inventing
62
+ * a time. Row footprints mirror `EventCompactRowSkeleton`.
65
63
  */
66
- declare function HourBandSkeleton({ cardCount, className }: HourBandSkeletonProps): react_jsx_runtime.JSX.Element;
64
+ declare function HourBandSkeleton({ cardCount, className, }: HourBandSkeletonProps): react_jsx_runtime.JSX.Element;
67
65
 
68
66
  export { HourBand, type HourBandProps, HourBandSkeleton, type HourBandSkeletonProps };