@bearmenu/ui 0.8.3 → 0.8.6

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 (194) hide show
  1. package/dist/chunk-2WDJR6K7.js +76 -0
  2. package/dist/chunk-637L7XQ3.js +85 -0
  3. package/dist/chunk-6XMYEZVR.js +26 -0
  4. package/dist/chunk-DNSXMHYX.js +8 -0
  5. package/dist/chunk-FDITZ2VM.js +16 -0
  6. package/dist/chunk-GPH6L4DX.js +55 -0
  7. package/dist/{chunk-N2KNBPAQ.js → chunk-QXHMPJ35.js} +1 -0
  8. package/dist/chunk-TT3WFS6S.js +379 -0
  9. package/dist/chunk-UXWAOISG.js +170 -0
  10. package/dist/{chunk-UZ3PCIE5.js → chunk-XWMRABZW.js} +2 -2
  11. package/dist/{chunk-VBA45GLP.js → chunk-ZDAHKI3A.js} +12 -2
  12. package/dist/components/alert.d.ts +2 -2
  13. package/dist/components/badge.d.ts +1 -1
  14. package/dist/components/button.d.ts +1 -1
  15. package/dist/components/card.d.ts +2 -2
  16. package/dist/components/card.js +4 -127
  17. package/dist/components/category-deck.d.ts +50 -0
  18. package/dist/components/category-deck.js +128 -0
  19. package/dist/components/command.d.ts +15 -15
  20. package/dist/components/concept-card.d.ts +43 -0
  21. package/dist/components/concept-card.js +81 -0
  22. package/dist/components/coverflow.d.ts +123 -0
  23. package/dist/components/coverflow.js +300 -0
  24. package/dist/components/date-input.d.ts +1 -1
  25. package/dist/components/day-rail-chip.d.ts +82 -0
  26. package/dist/components/day-rail-chip.js +105 -0
  27. package/dist/components/drift-rail.d.ts +28 -0
  28. package/dist/components/drift-rail.js +3 -0
  29. package/dist/components/event-card.d.ts +97 -0
  30. package/dist/components/event-card.js +161 -0
  31. package/dist/components/event-compact-row.d.ts +72 -0
  32. package/dist/components/event-compact-row.js +133 -0
  33. package/dist/components/event-day-header.d.ts +65 -0
  34. package/dist/components/event-day-header.js +95 -0
  35. package/dist/components/event-day-separator.d.ts +46 -0
  36. package/dist/components/event-day-separator.js +50 -0
  37. package/dist/components/event-detail-panel.d.ts +80 -0
  38. package/dist/components/event-detail-panel.js +251 -0
  39. package/dist/components/event-hub-hero.d.ts +34 -0
  40. package/dist/components/event-hub-hero.js +57 -0
  41. package/dist/components/event-index-row.d.ts +68 -0
  42. package/dist/components/event-index-row.js +84 -0
  43. package/dist/components/event-list-row-wide.d.ts +101 -0
  44. package/dist/components/event-list-row-wide.js +218 -0
  45. package/dist/components/event-list-row.d.ts +82 -0
  46. package/dist/components/event-list-row.js +173 -0
  47. package/dist/components/event-poster-fallback.d.ts +20 -0
  48. package/dist/components/event-poster-fallback.js +3 -0
  49. package/dist/components/event-types.d.ts +118 -0
  50. package/dist/components/event-types.js +2 -0
  51. package/dist/components/events-empty-state.d.ts +44 -0
  52. package/dist/components/events-empty-state.js +73 -0
  53. package/dist/components/facet-group.d.ts +93 -0
  54. package/dist/components/facet-group.js +222 -0
  55. package/dist/components/featured-rail-item.d.ts +42 -0
  56. package/dist/components/featured-rail-item.js +88 -0
  57. package/dist/components/hour-band.d.ts +68 -0
  58. package/dist/components/hour-band.js +53 -0
  59. package/dist/components/hour-group.d.ts +67 -0
  60. package/dist/components/hour-group.js +59 -0
  61. package/dist/components/icon.d.ts +18 -0
  62. package/dist/components/icon.js +31 -0
  63. package/dist/components/item.d.ts +2 -2
  64. package/dist/components/motion-icon-controls.d.ts +26 -0
  65. package/dist/components/motion-icon-controls.js +4 -0
  66. package/dist/components/motion-icon-set.d.ts +27 -0
  67. package/dist/components/motion-icon-set.js +139 -0
  68. package/dist/components/motion-icon.d.ts +44 -0
  69. package/dist/components/motion-icon.js +3 -0
  70. package/dist/components/multi-select-combobox.js +1 -1
  71. package/dist/components/place-about-tab.js +3 -3
  72. package/dist/components/place-details-mobile.js +3 -3
  73. package/dist/components/poster-stack.d.ts +30 -0
  74. package/dist/components/poster-stack.js +104 -0
  75. package/dist/components/poster-tape.d.ts +36 -0
  76. package/dist/components/poster-tape.js +64 -0
  77. package/dist/components/poster-wall.d.ts +25 -0
  78. package/dist/components/poster-wall.js +183 -0
  79. package/dist/components/quiet-stretch.d.ts +43 -0
  80. package/dist/components/quiet-stretch.js +54 -0
  81. package/dist/components/section-header.d.ts +53 -0
  82. package/dist/components/section-header.js +63 -0
  83. package/dist/components/segmented-nav.d.ts +62 -0
  84. package/dist/components/segmented-nav.js +54 -0
  85. package/dist/components/skeleton-card.js +1 -1
  86. package/dist/components/skeleton.d.ts +17 -0
  87. package/dist/components/skeleton.js +1 -1
  88. package/dist/components/spinner.d.ts +2 -2
  89. package/dist/components/tag-group.js +3 -26
  90. package/dist/components/tag.d.ts +2 -2
  91. package/dist/components/tag.js +1 -1
  92. package/dist/components/text.d.ts +3 -3
  93. package/dist/components/timeline-band.d.ts +46 -0
  94. package/dist/components/timeline-band.js +5 -0
  95. package/dist/components/venue-events-block.d.ts +143 -0
  96. package/dist/components/venue-events-block.js +222 -0
  97. package/dist/components/weekend-panel.d.ts +44 -0
  98. package/dist/components/weekend-panel.js +231 -0
  99. package/dist/lib/icon-registry.d.ts +58 -0
  100. package/dist/lib/icon-registry.js +39 -0
  101. package/package.json +2 -1
  102. package/src/components/accordion.stories.tsx +1 -1
  103. package/src/components/card.tsx +44 -1
  104. package/src/components/category-deck.stories.tsx +96 -0
  105. package/src/components/category-deck.tsx +227 -0
  106. package/src/components/combobox.stories.tsx +1 -1
  107. package/src/components/concept-card.stories.tsx +80 -0
  108. package/src/components/concept-card.tsx +143 -0
  109. package/src/components/coverflow.stories.tsx +240 -0
  110. package/src/components/coverflow.test.tsx +193 -0
  111. package/src/components/coverflow.tsx +550 -0
  112. package/src/components/currency-input.stories.tsx +3 -3
  113. package/src/components/day-rail-chip.stories.tsx +145 -0
  114. package/src/components/day-rail-chip.tsx +201 -0
  115. package/src/components/drift-rail.stories.tsx +92 -0
  116. package/src/components/drift-rail.tsx +86 -0
  117. package/src/components/empty-state.stories.tsx +3 -3
  118. package/src/components/event-card.stories.tsx +248 -0
  119. package/src/components/event-card.test.tsx +177 -0
  120. package/src/components/event-card.tsx +321 -0
  121. package/src/components/event-compact-row.stories.tsx +221 -0
  122. package/src/components/event-compact-row.tsx +268 -0
  123. package/src/components/event-day-header.stories.tsx +124 -0
  124. package/src/components/event-day-header.tsx +180 -0
  125. package/src/components/event-day-separator.stories.tsx +70 -0
  126. package/src/components/event-day-separator.tsx +95 -0
  127. package/src/components/event-detail-panel.stories.tsx +191 -0
  128. package/src/components/event-detail-panel.tsx +360 -0
  129. package/src/components/event-hub-hero.stories.tsx +66 -0
  130. package/src/components/event-hub-hero.tsx +110 -0
  131. package/src/components/event-index-row.stories.tsx +116 -0
  132. package/src/components/event-index-row.tsx +181 -0
  133. package/src/components/event-list-row-wide.stories.tsx +204 -0
  134. package/src/components/event-list-row-wide.tsx +386 -0
  135. package/src/components/event-list-row.stories.tsx +159 -0
  136. package/src/components/event-list-row.tsx +335 -0
  137. package/src/components/event-poster-fallback.stories.tsx +52 -0
  138. package/src/components/event-poster-fallback.tsx +31 -0
  139. package/src/components/event-types.ts +133 -0
  140. package/src/components/events-empty-state.stories.tsx +59 -0
  141. package/src/components/events-empty-state.tsx +131 -0
  142. package/src/components/facet-group.stories.tsx +247 -0
  143. package/src/components/facet-group.test.tsx +225 -0
  144. package/src/components/facet-group.tsx +352 -0
  145. package/src/components/featured-rail-item.stories.tsx +86 -0
  146. package/src/components/featured-rail-item.tsx +153 -0
  147. package/src/components/form.stories.tsx +1 -1
  148. package/src/components/hour-band.stories.tsx +159 -0
  149. package/src/components/hour-band.tsx +126 -0
  150. package/src/components/hour-group.stories.tsx +100 -0
  151. package/src/components/hour-group.tsx +124 -0
  152. package/src/components/icon.tsx +57 -0
  153. package/src/components/input-otp.stories.tsx +1 -1
  154. package/src/components/markdown-renderer.stories.tsx +1 -1
  155. package/src/components/motion-icon-controls.test.tsx +78 -0
  156. package/src/components/motion-icon-controls.tsx +552 -0
  157. package/src/components/motion-icon-set.stories.tsx +185 -0
  158. package/src/components/motion-icon-set.tsx +219 -0
  159. package/src/components/motion-icon.test.tsx +159 -0
  160. package/src/components/motion-icon.tsx +163 -0
  161. package/src/components/multi-select-combobox.stories.tsx +1 -1
  162. package/src/components/phone-frame.stories.tsx +1 -1
  163. package/src/components/poster-stack.stories.tsx +68 -0
  164. package/src/components/poster-stack.tsx +155 -0
  165. package/src/components/poster-tape.stories.tsx +70 -0
  166. package/src/components/poster-tape.tsx +122 -0
  167. package/src/components/poster-wall.stories.tsx +95 -0
  168. package/src/components/poster-wall.tsx +220 -0
  169. package/src/components/quiet-stretch.stories.tsx +62 -0
  170. package/src/components/quiet-stretch.tsx +115 -0
  171. package/src/components/rating.stories.tsx +3 -3
  172. package/src/components/searchable-select.stories.tsx +1 -1
  173. package/src/components/section-header.stories.tsx +70 -0
  174. package/src/components/section-header.tsx +134 -0
  175. package/src/components/segmented-nav.stories.tsx +118 -0
  176. package/src/components/segmented-nav.tsx +113 -0
  177. package/src/components/selection-bar.stories.tsx +1 -1
  178. package/src/components/skeleton-card.stories.tsx +3 -3
  179. package/src/components/skeleton.tsx +18 -0
  180. package/src/components/sliding-panels.stories.tsx +1 -1
  181. package/src/components/stepper.stories.tsx +1 -1
  182. package/src/components/sticky-container.stories.tsx +3 -3
  183. package/src/components/tag.tsx +11 -1
  184. package/src/components/timeline-band.stories.tsx +206 -0
  185. package/src/components/timeline-band.tsx +207 -0
  186. package/src/components/toggle-group.stories.tsx +1 -1
  187. package/src/components/tooltip.stories.tsx +2 -2
  188. package/src/components/venue-events-block.stories.tsx +216 -0
  189. package/src/components/venue-events-block.tsx +408 -0
  190. package/src/components/weekend-panel.stories.tsx +92 -0
  191. package/src/components/weekend-panel.tsx +322 -0
  192. package/src/globals.css +19 -0
  193. package/src/lib/icon-registry.ts +139 -0
  194. package/src/test/setup.ts +5 -1
@@ -0,0 +1,68 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode, ComponentType } from 'react';
3
+
4
+ /**
5
+ * EventIndexRow — the row of an exhaustive, crawlable event index.
6
+ *
7
+ * NOT `<EventListRowWide>`: that row belongs to the list VIEW, and it carries
8
+ * a price column and a Reserve chip because the list view is where you act.
9
+ * This row makes no claim to be operable — it is a catalogue entry. Its only
10
+ * affordances are two real links: the title (stretched over the whole row via
11
+ * `after:absolute after:inset-0`) and the venue (escaping that overlay with
12
+ * `relative z-10`, the same nested-link pattern `<EventListRowWide>` uses for
13
+ * `menuHref`). That venue link is why this could not be a variant of
14
+ * `<EventCompactRow>` or `<EventListRow>`: both wrap their entire body in one
15
+ * anchor, so a second link inside would be a nested `<a>` — invalid HTML that
16
+ * browsers unnest, breaking both links.
17
+ *
18
+ * NO `"use client"`, AND THAT IS LOAD-BEARING. This row's surface is a
19
+ * server-only prerendered page carrying ~50 of them, and every sibling row in
20
+ * this family is a client component for one reason: `useState` to catch
21
+ * `<img onError>`. Here the fallback is layered BEHIND the poster instead, so
22
+ * a failed image reveals the designed gradient with no JS at all. The
23
+ * consequence to accept: an image that returns 200 but decodes to garbage
24
+ * shows an empty box rather than the fallback.
25
+ *
26
+ * THE DESCRIPTION IS NEVER TRUNCATED IN THE MARKUP — it is clamped with CSS
27
+ * (`line-clamp`), so the full text stays in the DOM. Callers must pass the
28
+ * whole string. On this surface that is the entire point: the text is the
29
+ * page's body copy, and a row that cut it at N characters would be deleting
30
+ * the thing the section exists to carry.
31
+ *
32
+ * ROW RULES: this row draws its own top rule, same as `<EventListRow>` and
33
+ * `<EventListRowWide>`. Pass `hideRule` on the first row under a heading that
34
+ * already ends in one (`<EventDaySeparator>` does), or you get two rules a few
35
+ * pixels apart.
36
+ */
37
+ type EventIndexRowLinkProps = {
38
+ href: string;
39
+ className?: string;
40
+ children: ReactNode;
41
+ };
42
+ type EventIndexRowProps = {
43
+ /** Rendered inside `as` and allowed to WRAP — a document-outline heading is never truncated. */
44
+ title: string;
45
+ /** Heading level for `title`. Defaults to `h3`, one below the group headings. */
46
+ as?: "h2" | "h3" | "h4";
47
+ href: string;
48
+ /** Leading emphasised fact on the meta line — caller-composed date + time, e.g. "26 iulie, 20:00–23:00". */
49
+ when: string;
50
+ venue?: string;
51
+ /** Makes the venue a real second link. Omit for a venue with no place page. */
52
+ venueHref?: string;
53
+ /** Plain text, never a chip: "intrare liberă" / "bilet 40 lei". */
54
+ fee?: string;
55
+ /** Display labels. `EventPreview.tags` is taxonomy coordinates the DS cannot translate, so the caller resolves and caps them. */
56
+ tags?: string[];
57
+ /** FULL text. Clamped to 3 lines (mobile) / 2 (md+) in CSS only. */
58
+ description?: string;
59
+ posterUrl?: string;
60
+ fallback?: ReactNode;
61
+ /** Suppresses the top rule. Use on the first row under a heading that draws its own. */
62
+ hideRule?: boolean;
63
+ linkComponent?: ComponentType<EventIndexRowLinkProps>;
64
+ className?: string;
65
+ };
66
+ declare function EventIndexRow({ title, as: Heading, href, when, venue, venueHref, fee, tags, description, posterUrl, fallback, hideRule, linkComponent: LinkComponent, className, }: EventIndexRowProps): react_jsx_runtime.JSX.Element;
67
+
68
+ export { EventIndexRow, type EventIndexRowLinkProps, type EventIndexRowProps };
@@ -0,0 +1,84 @@
1
+ import { Separator } from '../chunk-WSRWFA6K.js';
2
+ import { TagGroup } from '../chunk-6XMYEZVR.js';
3
+ import { Tag } from '../chunk-ZDAHKI3A.js';
4
+ import { EventPosterFallback } from '../chunk-FDITZ2VM.js';
5
+ import { cn } from '../chunk-FEK5XGZW.js';
6
+ import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
7
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
+
9
+ function DefaultLink(_a) {
10
+ var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
11
+ return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
12
+ }
13
+ function EventIndexRow({
14
+ title,
15
+ as: Heading = "h3",
16
+ href,
17
+ when,
18
+ venue,
19
+ venueHref,
20
+ fee,
21
+ tags,
22
+ description,
23
+ posterUrl,
24
+ fallback = /* @__PURE__ */ jsx(EventPosterFallback, {}),
25
+ hideRule,
26
+ linkComponent: LinkComponent = DefaultLink,
27
+ className
28
+ }) {
29
+ const dot = /* @__PURE__ */ jsx("span", { className: "px-1 text-border", "aria-hidden": true, children: "\xB7" });
30
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
31
+ !hideRule && /* @__PURE__ */ jsx(Separator, { className: "absolute inset-x-0 top-0" }),
32
+ /* @__PURE__ */ jsxs("div", { className: "relative -mx-3 flex gap-3 rounded-lg px-3 py-4 transition-colors duration-150 hover:bg-card/60 motion-reduce:transition-none md:gap-4 md:py-5", children: [
33
+ /* @__PURE__ */ jsxs("div", { className: "relative aspect-square w-[72px] shrink-0 overflow-hidden rounded-[9px] bg-muted md:w-[104px]", children: [
34
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0", children: fallback }),
35
+ posterUrl && // eslint-disable-next-line @next/next/no-img-element
36
+ /* @__PURE__ */ jsx(
37
+ "img",
38
+ {
39
+ src: posterUrl,
40
+ alt: "",
41
+ loading: "lazy",
42
+ decoding: "async",
43
+ className: "absolute inset-0 h-full w-full object-cover"
44
+ }
45
+ )
46
+ ] }),
47
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
48
+ /* @__PURE__ */ jsx(Heading, { className: "text-[15px] font-bold leading-snug tracking-[-0.01em] text-foreground md:text-[16.5px]", children: /* @__PURE__ */ jsx(
49
+ LinkComponent,
50
+ {
51
+ href,
52
+ className: "rounded-sm transition-colors duration-150 after:absolute after:inset-0 hover:text-primary motion-reduce:transition-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
53
+ children: title
54
+ }
55
+ ) }),
56
+ /* @__PURE__ */ jsxs("p", { className: "mt-1 text-[12px] leading-5 text-muted-foreground md:text-[12.5px]", children: [
57
+ /* @__PURE__ */ jsx("span", { className: "font-semibold tabular-nums text-foreground", children: when }),
58
+ venue && /* @__PURE__ */ jsxs(Fragment, { children: [
59
+ dot,
60
+ venueHref ? /* @__PURE__ */ jsx(
61
+ LinkComponent,
62
+ {
63
+ href: venueHref,
64
+ className: "relative z-10 rounded-sm font-semibold text-foreground/85 underline decoration-border underline-offset-2 transition-colors duration-150 hover:text-primary hover:decoration-primary motion-reduce:transition-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
65
+ children: venue
66
+ }
67
+ ) : /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground/85", children: venue })
68
+ ] }),
69
+ fee && /* @__PURE__ */ jsxs(Fragment, { children: [
70
+ dot,
71
+ fee
72
+ ] })
73
+ ] }),
74
+ tags && tags.length > 0 && // `outline`, not the default: default `Tag` is `bg-muted`, and this
75
+ // row's surface is a `bg-muted/50` band — a 0.019-L delta in light
76
+ // mode, which is invisible. `outline` reads on both.
77
+ /* @__PURE__ */ jsx(TagGroup, { className: "mt-2", children: tags.map((tag) => /* @__PURE__ */ jsx(Tag, { size: "sm", variant: "outline", children: tag }, tag)) }),
78
+ description && /* @__PURE__ */ jsx("p", { className: "mt-2 line-clamp-3 max-w-[620px] text-[13px] leading-[1.6] text-muted-foreground md:line-clamp-2 md:text-[13.5px] md:leading-[1.55]", children: description })
79
+ ] })
80
+ ] })
81
+ ] });
82
+ }
83
+
84
+ export { EventIndexRow };
@@ -0,0 +1,101 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React$1 from 'react';
3
+ import { ReactNode } from 'react';
4
+ import { EventPreview, EventListRowLabels, EventDateBadgeFormatters } from './event-types.js';
5
+
6
+ /**
7
+ * EventListRowWide — the desktop counterpart to `<EventListRow>`.
8
+ *
9
+ * Denser than `<EventCard>`, richer than the mobile `<EventListRow>`: desktop
10
+ * has the width to spare for a description and a dedicated action column, so
11
+ * this adds both rather than just scaling up the mobile row's type sizes.
12
+ *
13
+ * NESTED-LINK PATTERN, not the mobile row's single anchor: the row root is a
14
+ * plain, non-interactive container. The event TITLE is the primary link and
15
+ * gets a stretched overlay (`after:absolute after:inset-0`) so the whole row
16
+ * stays one big click target; "See the menu" (when `menuHref` is supplied) is
17
+ * a second, real link, `relative` with a higher `z-index` than the overlay so
18
+ * it wins the click in its own area — nesting it inside the title's anchor
19
+ * would be invalid HTML, which is why this uses two siblings instead. The
20
+ * title's `onClick` still fires for the caller (e.g. to `preventDefault()`
21
+ * into a detail sheet); modifier/middle-clicks still fall through to the
22
+ * anchor since nothing calls `preventDefault()` here.
23
+ *
24
+ * `event-list-row.tsx` (the mobile row) keeps the single-anchor shape and has
25
+ * no action column at all — the two were reconciled in favour of a real
26
+ * action here and none there, since a nested inert CTA inside a single-anchor
27
+ * row is a control that only looks like one. See that file's header.
28
+ *
29
+ * WEIGHT: the family tops out at 600, and after that pass the `Button` in this
30
+ * row's action column is the only 700-class element left in it — correct,
31
+ * since it is the only real action. Density sets weight, width sets size:
32
+ * both row titles are 600, and 15px vs 16.5px is what separates them.
33
+ *
34
+ * Same contract as the rest of the family: DS-owned view model, injected
35
+ * labels and formatters, plain `<img>`, anchor whenever `href` is given.
36
+ */
37
+ type EventListRowWideLinkProps = {
38
+ href: string;
39
+ className?: string;
40
+ children: React.ReactNode;
41
+ onClick?: (mouseEvent: React.MouseEvent) => void;
42
+ };
43
+ /**
44
+ * Extends the mobile row's labels with the strings only the wide row needs —
45
+ * the action column included, since this is the only row in the family that
46
+ * has one.
47
+ */
48
+ type EventListRowWideLabels = EventListRowLabels & {
49
+ /** Primary row action, e.g. "Reserve". */
50
+ reserve: string;
51
+ /** Row action for a sold-out event. */
52
+ notifyMe: string;
53
+ /** Secondary link in the action column, e.g. "See the menu". */
54
+ seeMenu: string;
55
+ };
56
+ type EventListRowWideProps = {
57
+ event: EventPreview;
58
+ labels: EventListRowWideLabels;
59
+ formatters: EventDateBadgeFormatters;
60
+ /** Currently running — tints the date badge and shows the on-air chip. */
61
+ isLive?: boolean;
62
+ /** Sold out or otherwise closed — dims the row and swaps the CTA. */
63
+ isSoldOut?: boolean;
64
+ /**
65
+ * Caller-resolved tag display labels, rendered as chips after the venue.
66
+ * The DS holds no taxonomy display names, so resolving AND capping them is
67
+ * the caller's job — three is what the desktop meta line carries. Same
68
+ * contract as `EventListRowProps.tags`; this replaced a `tagsText` prose
69
+ * string, which was the only place in the family tags were not chips.
70
+ */
71
+ tags?: string[];
72
+ href?: string;
73
+ /** Destination for the "See the menu" affordance. Omit to not render it at all. */
74
+ menuHref?: string;
75
+ linkComponent?: React.ComponentType<EventListRowWideLinkProps>;
76
+ onClick?: (event: EventPreview, mouseEvent: React.MouseEvent) => void;
77
+ className?: string;
78
+ priority?: boolean;
79
+ /** Rendered instead of the thumbnail when it's absent or failed to load. Defaults to `<EventPosterFallback />`. */
80
+ fallback?: ReactNode;
81
+ /**
82
+ * Drops this row's top rule. Pass it on the FIRST row under a day heading:
83
+ * the heading already ends the block above it, so the row's own rule lands
84
+ * immediately beneath it and draws two dividers a few pixels apart. The gap
85
+ * is the separator there — whitespace does the same job without the second
86
+ * line. Same prop and same reason as `EventIndexRow`.
87
+ */
88
+ hideRule?: boolean;
89
+ };
90
+ declare const EventListRowWide: React$1.NamedExoticComponent<EventListRowWideProps>;
91
+ type EventListRowWideSkeletonProps = {
92
+ /** Matches `EventListRowWideProps` shape: show the description block by default, drop it for `NoDescription`-style rows. */
93
+ showDescription?: boolean;
94
+ /** Matches `EventListRowWideProps["hideRule"]` — drop the top rule on the first row of a day group. */
95
+ hideRule?: boolean;
96
+ className?: string;
97
+ };
98
+ /** Mirrors `<EventListRowWide>`'s geometry exactly so nothing shifts when data lands. */
99
+ declare function EventListRowWideSkeleton({ showDescription, hideRule, className, }: EventListRowWideSkeletonProps): react_jsx_runtime.JSX.Element;
100
+
101
+ export { EventListRowWide, type EventListRowWideLabels, type EventListRowWideLinkProps, type EventListRowWideProps, EventListRowWideSkeleton, type EventListRowWideSkeletonProps };
@@ -0,0 +1,218 @@
1
+ import { Separator } from '../chunk-WSRWFA6K.js';
2
+ import { Tag } from '../chunk-ZDAHKI3A.js';
3
+ import { resolveEventEntryFee } from '../chunk-DNSXMHYX.js';
4
+ import { EventPosterFallback } from '../chunk-FDITZ2VM.js';
5
+ import { Skeleton } from '../chunk-QXHMPJ35.js';
6
+ import { buttonVariants } from '../chunk-H3BV4VAG.js';
7
+ import '../chunk-R47NEOSI.js';
8
+ import { cn } from '../chunk-FEK5XGZW.js';
9
+ import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
10
+ import { memo, useState } from 'react';
11
+ import { Radio, MapPin } from 'lucide-react';
12
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
13
+
14
+ function DefaultLink(_a) {
15
+ var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
16
+ return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
17
+ }
18
+ var EventListRowWide = memo(function EventListRowWide2({
19
+ event,
20
+ labels,
21
+ formatters,
22
+ isLive,
23
+ isSoldOut,
24
+ tags,
25
+ href,
26
+ menuHref,
27
+ linkComponent: LinkComponent = DefaultLink,
28
+ onClick,
29
+ className,
30
+ priority,
31
+ fallback = /* @__PURE__ */ jsx(EventPosterFallback, {}),
32
+ hideRule
33
+ }) {
34
+ var _a, _b;
35
+ const [imgError, setImgError] = useState(false);
36
+ const fee = resolveEventEntryFee(event);
37
+ const showPoster = !!event.poster_url && !imgError;
38
+ const venue = (_a = event.place_name) != null ? _a : event.location;
39
+ const description = (_b = event.description) != null ? _b : event.short_description;
40
+ const priceText = fee.kind === "free" ? labels.free : fee.kind === "paid" ? formatters.price(fee.amountRon) : void 0;
41
+ const body = /* @__PURE__ */ jsxs(Fragment, { children: [
42
+ !hideRule && /* @__PURE__ */ jsx(Separator, { className: "absolute inset-x-0 top-0" }),
43
+ /* @__PURE__ */ jsxs(
44
+ "div",
45
+ {
46
+ className: cn("w-[52px] shrink-0 rounded-[10px] py-[7px] text-center", isLive && "bg-success/10"),
47
+ children: [
48
+ /* @__PURE__ */ jsx(
49
+ "div",
50
+ {
51
+ className: cn(
52
+ "text-[19px] font-semibold leading-none tracking-[-0.02em] tabular-nums",
53
+ isLive ? "text-success" : "text-foreground"
54
+ ),
55
+ children: formatters.dayNumber(event.starts_at)
56
+ }
57
+ ),
58
+ /* @__PURE__ */ jsx(
59
+ "div",
60
+ {
61
+ className: cn(
62
+ "mt-[3px] text-[10.5px] font-semibold tracking-[0.06em]",
63
+ isLive ? "text-success" : "text-muted-foreground"
64
+ ),
65
+ children: formatters.monthShort(event.starts_at)
66
+ }
67
+ )
68
+ ]
69
+ }
70
+ ),
71
+ /* @__PURE__ */ jsx("div", { className: "aspect-square w-[104px] shrink-0 overflow-hidden rounded-[10px] bg-muted", children: showPoster ? (
72
+ // eslint-disable-next-line @next/next/no-img-element
73
+ /* @__PURE__ */ jsx(
74
+ "img",
75
+ {
76
+ src: event.poster_url,
77
+ alt: "",
78
+ loading: priority ? "eager" : "lazy",
79
+ decoding: "async",
80
+ className: "h-full w-full object-cover",
81
+ onError: () => setImgError(true)
82
+ }
83
+ )
84
+ ) : fallback }),
85
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
86
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
87
+ href ? /* @__PURE__ */ jsx(
88
+ LinkComponent,
89
+ {
90
+ href,
91
+ className: "rounded-sm text-[16.5px] font-semibold tracking-[-0.01em] after:absolute after:inset-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
92
+ onClick: onClick ? (mouseEvent) => onClick(event, mouseEvent) : void 0,
93
+ children: event.title
94
+ }
95
+ ) : onClick ? /* @__PURE__ */ jsx(
96
+ "button",
97
+ {
98
+ type: "button",
99
+ className: "relative cursor-pointer rounded-sm bg-transparent p-0 text-left text-[16.5px] font-semibold tracking-[-0.01em] after:absolute after:inset-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
100
+ onClick: (mouseEvent) => onClick(event, mouseEvent),
101
+ children: event.title
102
+ }
103
+ ) : /* @__PURE__ */ jsx("span", { className: "text-[16.5px] font-semibold tracking-[-0.01em]", children: event.title }),
104
+ isLive && /* @__PURE__ */ jsxs(Tag, { size: "sm", variant: "success", className: "shrink-0 whitespace-nowrap", children: [
105
+ /* @__PURE__ */ jsx(Radio, { className: "h-2.5 w-2.5", "aria-hidden": true }),
106
+ labels.liveNow
107
+ ] }),
108
+ isSoldOut && /* @__PURE__ */ jsx(Tag, { size: "sm", variant: "quiet", className: "shrink-0 whitespace-nowrap", children: labels.soldOut })
109
+ ] }),
110
+ /* @__PURE__ */ jsxs("div", { className: "mt-[5px] flex items-center gap-2 text-[12.5px] text-muted-foreground", children: [
111
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 tabular-nums text-foreground", children: formatters.time(event.starts_at) }),
112
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-1", children: [
113
+ /* @__PURE__ */ jsx(MapPin, { className: "h-3 w-3 shrink-0", "aria-hidden": true }),
114
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: venue })
115
+ ] }),
116
+ tags == null ? void 0 : tags.map((tag) => /* @__PURE__ */ jsx(Tag, { size: "sm", variant: "quiet", className: "shrink-0 whitespace-nowrap", children: tag }, tag))
117
+ ] }),
118
+ description && /* @__PURE__ */ jsx("p", { className: "mt-2 line-clamp-2 max-w-[620px] text-[13.5px] leading-[1.55] text-muted-foreground", children: description })
119
+ ] }),
120
+ /* @__PURE__ */ jsxs("div", { className: "flex w-[150px] shrink-0 flex-col items-end gap-[9px]", children: [
121
+ priceText && /* @__PURE__ */ jsx(
122
+ "span",
123
+ {
124
+ className: cn("text-[15px] font-semibold tabular-nums", fee.kind === "free" && "text-success"),
125
+ children: priceText
126
+ }
127
+ ),
128
+ /* @__PURE__ */ jsx(
129
+ "span",
130
+ {
131
+ className: buttonVariants({
132
+ variant: isSoldOut ? "outline" : "default",
133
+ size: "sm"
134
+ }),
135
+ children: isSoldOut ? labels.notifyMe : labels.reserve
136
+ }
137
+ ),
138
+ menuHref && /* @__PURE__ */ jsx(
139
+ LinkComponent,
140
+ {
141
+ href: menuHref,
142
+ className: "relative z-10 cursor-pointer rounded-sm text-xs font-semibold text-primary underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
143
+ children: labels.seeMenu
144
+ }
145
+ )
146
+ ] })
147
+ ] });
148
+ const rootClasses = cn(
149
+ "relative flex w-full items-start gap-[18px] py-[18px] text-left",
150
+ // The row is a click target — its title carries an `after:inset-0` overlay
151
+ // that makes the WHOLE row the link — and it had no hover response at all,
152
+ // so a pointer user got no confirmation the thing under the cursor was
153
+ // interactive until they had already clicked it.
154
+ //
155
+ // The tint bleeds past the text edges (`-mx-3 px-3`) so the fill reads as
156
+ // one row rather than a box drawn around the copy, and the row keeps its
157
+ // full-bleed separator. Sold-out rows are excluded: they are dimmed and
158
+ // inert, and lighting one up on hover promises an action that is not there.
159
+ //
160
+ // TEXT-KEYED, not surface-keyed — the same reasoning as `EventCompactRow`.
161
+ // This shipped as `bg-muted/50` and the numbers are why it did not stay:
162
+ // composited, that lands 0.0155 L from `--background` in light mode, which
163
+ // is the case this row actually renders in, and 0.0075 from `--card` in
164
+ // dark, which is invisible. `--foreground` at 5% holds 0.038-0.041 L across
165
+ // all four surface/mode combinations, so the wash is the same strength
166
+ // wherever the row is dropped and cannot be silently cancelled by the
167
+ // surface beneath it.
168
+ !isSoldOut && "-mx-3 rounded-xl px-3 transition-colors duration-150 hover:bg-foreground/5 motion-reduce:transition-none",
169
+ isSoldOut && "opacity-60",
170
+ className
171
+ );
172
+ return /* @__PURE__ */ jsx("div", { className: rootClasses, children: body });
173
+ });
174
+ function EventListRowWideSkeleton({
175
+ showDescription = true,
176
+ hideRule,
177
+ className
178
+ }) {
179
+ return /* @__PURE__ */ jsxs(
180
+ "div",
181
+ {
182
+ "aria-hidden": "true",
183
+ className: cn(
184
+ "relative flex w-full items-start gap-[18px] py-[18px] text-left",
185
+ className
186
+ ),
187
+ children: [
188
+ !hideRule && /* @__PURE__ */ jsx(Separator, { className: "absolute inset-x-0 top-0" }),
189
+ /* @__PURE__ */ jsxs("div", { className: "w-[52px] shrink-0 rounded-[10px] py-[7px] text-center", children: [
190
+ /* @__PURE__ */ jsx(Skeleton, { className: "mx-auto h-5 w-6" }),
191
+ /* @__PURE__ */ jsx(Skeleton, { className: "mx-auto mt-[3px] h-[10px] w-7" })
192
+ ] }),
193
+ /* @__PURE__ */ jsx(Skeleton, { className: "aspect-square w-[104px] shrink-0 rounded-[10px]" }),
194
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
195
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[16.5px] w-3/5" }),
196
+ /* @__PURE__ */ jsxs("div", { className: "mt-[5px] flex items-center gap-2", children: [
197
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-10" }),
198
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-3 shrink-0 rounded-full" }),
199
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" }),
200
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[22px] w-16 rounded-full" }),
201
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[22px] w-12 rounded-full" })
202
+ ] }),
203
+ showDescription && /* @__PURE__ */ jsxs("div", { className: "mt-2 max-w-[620px] space-y-1.5", children: [
204
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[13.5px] w-full" }),
205
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[13.5px] w-2/3" })
206
+ ] })
207
+ ] }),
208
+ /* @__PURE__ */ jsxs("div", { className: "flex w-[150px] shrink-0 flex-col items-end gap-[9px]", children: [
209
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[15px] w-16" }),
210
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-20 rounded-full" }),
211
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-20" })
212
+ ] })
213
+ ]
214
+ }
215
+ );
216
+ }
217
+
218
+ export { EventListRowWide, EventListRowWideSkeleton };
@@ -0,0 +1,82 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React$1 from 'react';
3
+ import { ReactNode } from 'react';
4
+ import { EventPreview, EventListRowLabels, EventDateBadgeFormatters } from './event-types.js';
5
+
6
+ /**
7
+ * EventListRow — the dense row used by the list view at phone width.
8
+ *
9
+ * Roughly eight events per screen against the poster card's two, which is the
10
+ * whole reason the list view exists: fourteen days of inventory is punishing to
11
+ * scan in posters.
12
+ *
13
+ * NOTE ON THE ROW ACTION: this row used to carry a trailing "Reserve" CTA that
14
+ * `<EventCard>` deliberately does not, and an earlier version of this comment
15
+ * asked for the two surfaces to be reconciled rather than for the CTA to be
16
+ * quietly dropped. This is that reconciliation, and it lands differently per
17
+ * width. At phone width the CTA is gone: it was an inert `<span>` inside the
18
+ * row's own anchor, so it was drawn like a booking control (`text-primary`,
19
+ * bold) while doing nothing that a tap anywhere else on the row did not
20
+ * already do. `<EventListRowWide>` keeps a real action column, because desktop
21
+ * has the width for one and its row root is a container rather than a single
22
+ * anchor. If a CTA comes back here, it has to be a real one, not a span.
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.
29
+ *
30
+ * Same contract as the rest: DS-owned view model, injected labels and
31
+ * formatters, plain `<img>`, anchor whenever `href` is given.
32
+ */
33
+ type EventListRowLinkProps = {
34
+ href: string;
35
+ className?: string;
36
+ children: React.ReactNode;
37
+ onClick?: (mouseEvent: React.MouseEvent) => void;
38
+ };
39
+ type EventListRowProps = {
40
+ event: EventPreview;
41
+ labels: EventListRowLabels;
42
+ formatters: EventDateBadgeFormatters;
43
+ /** Currently running — fills the date badge and shows the on-air chip. */
44
+ isLive?: boolean;
45
+ /** Sold out or otherwise closed — dims the row and replaces the fee. */
46
+ isSoldOut?: boolean;
47
+ href?: string;
48
+ linkComponent?: React.ComponentType<EventListRowLinkProps>;
49
+ onClick?: (event: EventPreview, mouseEvent: React.MouseEvent) => void;
50
+ className?: string;
51
+ priority?: boolean;
52
+ /**
53
+ * Caller-resolved tag display labels for the chip line, e.g.
54
+ * `["Rock", "Terrace"]`. Same contract as `EventCompactRowProps.tags`: the
55
+ * DS holds no taxonomy display names, so the caller resolves AND caps them
56
+ * — two is what fits beside the live chip at 375px. Anything that does not
57
+ * fit is clipped whole rather than counted; see the chip line below.
58
+ */
59
+ tags?: string[];
60
+ /** Rendered instead of the thumbnail when it's absent or failed to load. Defaults to `<EventPosterFallback />`. */
61
+ fallback?: ReactNode;
62
+ /**
63
+ * Drops this row's top rule. Pass it on the FIRST row under a day heading:
64
+ * the heading already ends the block above it, so the row's own rule lands
65
+ * immediately beneath it and draws two dividers a few pixels apart. The gap
66
+ * is the separator there — whitespace does the same job without the second
67
+ * line. Same prop and same reason as `EventListRowWide` and `EventIndexRow`.
68
+ */
69
+ hideRule?: boolean;
70
+ };
71
+ declare const EventListRow: React$1.NamedExoticComponent<EventListRowProps>;
72
+ type EventListRowSkeletonProps = {
73
+ /** Matches `EventListRowProps["hideRule"]` — drop the top rule on the first row of a day group. */
74
+ hideRule?: boolean;
75
+ /** Reserve the chip line. Matches the real row, where it collapses on events with no live status and no tags. */
76
+ showTags?: boolean;
77
+ className?: string;
78
+ };
79
+ /** Mirrors `<EventListRow>`'s geometry exactly so nothing shifts when data lands. */
80
+ declare function EventListRowSkeleton({ hideRule, showTags, className, }: EventListRowSkeletonProps): react_jsx_runtime.JSX.Element;
81
+
82
+ export { EventListRow, type EventListRowLinkProps, type EventListRowProps, EventListRowSkeleton, type EventListRowSkeletonProps };