@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,173 @@
1
+ import { Separator } from '../chunk-WSRWFA6K.js';
2
+ import { TagGroup } from '../chunk-6XMYEZVR.js';
3
+ import { Tag } from '../chunk-ZDAHKI3A.js';
4
+ import { resolveEventEntryFee } from '../chunk-DNSXMHYX.js';
5
+ import { EventPosterFallback } from '../chunk-FDITZ2VM.js';
6
+ import { Skeleton } from '../chunk-QXHMPJ35.js';
7
+ import { cn } from '../chunk-FEK5XGZW.js';
8
+ import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
9
+ import { memo, useState } from 'react';
10
+ import { MapPin, Radio } from 'lucide-react';
11
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
12
+
13
+ function DefaultLink(_a) {
14
+ var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
15
+ return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
16
+ }
17
+ var EventListRow = memo(function EventListRow2({
18
+ event,
19
+ labels,
20
+ formatters,
21
+ isLive,
22
+ isSoldOut,
23
+ href,
24
+ linkComponent: LinkComponent = DefaultLink,
25
+ onClick,
26
+ className,
27
+ priority,
28
+ tags,
29
+ fallback = /* @__PURE__ */ jsx(EventPosterFallback, {}),
30
+ hideRule
31
+ }) {
32
+ var _a;
33
+ const [imgError, setImgError] = useState(false);
34
+ const fee = resolveEventEntryFee(event);
35
+ const showPoster = !!event.poster_url && !imgError;
36
+ const venue = (_a = event.place_name) != null ? _a : event.location;
37
+ const priceText = fee.kind === "free" ? labels.free : fee.kind === "paid" ? formatters.price(fee.amountRon) : void 0;
38
+ const body = /* @__PURE__ */ jsxs(Fragment, { children: [
39
+ !hideRule && /* @__PURE__ */ jsx(Separator, { className: "absolute inset-x-0 top-0" }),
40
+ /* @__PURE__ */ jsxs(
41
+ "div",
42
+ {
43
+ className: cn("w-[42px] shrink-0 rounded-[9px] py-1.5 text-center", isLive && "bg-success/10"),
44
+ children: [
45
+ /* @__PURE__ */ jsx(
46
+ "div",
47
+ {
48
+ className: cn(
49
+ "text-sm font-semibold leading-none tabular-nums",
50
+ isLive ? "text-success" : "text-foreground"
51
+ ),
52
+ children: formatters.dayNumber(event.starts_at)
53
+ }
54
+ ),
55
+ /* @__PURE__ */ jsx(
56
+ "div",
57
+ {
58
+ className: cn(
59
+ "mt-[3px] text-[10px] font-semibold tracking-[0.06em]",
60
+ isLive ? "text-success" : "text-muted-foreground"
61
+ ),
62
+ children: formatters.monthShort(event.starts_at)
63
+ }
64
+ )
65
+ ]
66
+ }
67
+ ),
68
+ /* @__PURE__ */ jsx("div", { className: "aspect-square w-[72px] shrink-0 overflow-hidden rounded-[9px] bg-muted", children: showPoster ? (
69
+ // eslint-disable-next-line @next/next/no-img-element
70
+ /* @__PURE__ */ jsx(
71
+ "img",
72
+ {
73
+ src: event.poster_url,
74
+ alt: "",
75
+ loading: priority ? "eager" : "lazy",
76
+ decoding: "async",
77
+ className: "h-full w-full object-cover",
78
+ onError: () => setImgError(true)
79
+ }
80
+ )
81
+ ) : fallback }),
82
+ /* @__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(
91
+ "span",
92
+ {
93
+ className: cn(
94
+ "shrink-0 tabular-nums",
95
+ fee.kind === "free" && "font-semibold text-success"
96
+ ),
97
+ children: priceText
98
+ }
99
+ )
100
+ ] }),
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
105
+ ] }),
106
+ tags == null ? void 0 : tags.map((tag) => /* @__PURE__ */ jsx(Tag, { size: "sm", variant: "quiet", className: "shrink-0 whitespace-nowrap", children: tag }, tag))
107
+ ] })
108
+ ] })
109
+ ] });
110
+ 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",
115
+ isSoldOut && "opacity-60",
116
+ (href || onClick) && "cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
117
+ className
118
+ );
119
+ if (href) {
120
+ return /* @__PURE__ */ jsx(
121
+ LinkComponent,
122
+ {
123
+ href,
124
+ className: rootClasses,
125
+ onClick: onClick ? (mouseEvent) => onClick(event, mouseEvent) : void 0,
126
+ children: body
127
+ }
128
+ );
129
+ }
130
+ if (onClick) {
131
+ return /* @__PURE__ */ jsx("button", { type: "button", className: rootClasses, onClick: (e) => onClick(event, e), children: body });
132
+ }
133
+ return /* @__PURE__ */ jsx("div", { className: rootClasses, children: body });
134
+ });
135
+ function EventListRowSkeleton({
136
+ hideRule,
137
+ showTags = true,
138
+ className
139
+ }) {
140
+ return /* @__PURE__ */ jsxs(
141
+ "div",
142
+ {
143
+ "aria-hidden": "true",
144
+ className: cn("relative flex w-full items-start gap-3 py-3 text-left", className),
145
+ children: [
146
+ !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: [
148
+ /* @__PURE__ */ jsx(Skeleton, { className: "mx-auto h-4 w-5" }),
149
+ /* @__PURE__ */ jsx(Skeleton, { className: "mx-auto mt-[3px] h-[10px] w-6" })
150
+ ] }),
151
+ /* @__PURE__ */ jsx(Skeleton, { className: "aspect-square w-[72px] shrink-0 rounded-[9px]" }),
152
+ /* @__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" })
156
+ ] }),
157
+ /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2", children: [
158
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-10" }),
159
+ /* @__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" })
162
+ ] }),
163
+ showTags && /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex items-center gap-1.5", children: [
164
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[22px] w-14 rounded-full" }),
165
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[22px] w-11 rounded-full" })
166
+ ] })
167
+ ] })
168
+ ]
169
+ }
170
+ );
171
+ }
172
+
173
+ export { EventListRow, EventListRowSkeleton };
@@ -0,0 +1,20 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ /**
5
+ * EventPosterFallback — what every events surface renders in place of a
6
+ * missing (or failed) poster image.
7
+ *
8
+ * Follows the DS image-fallback rule: never a bare icon on a flat background.
9
+ * `--gradient-primary` is warm in both themes, so the drop-shadowed icon
10
+ * always sits on a tinted, on-brand surface rather than the cold, zero-chroma
11
+ * `bg-muted` block a poster box would otherwise show.
12
+ */
13
+ type EventPosterFallbackProps = {
14
+ /** Defaults to a calendar glyph. Pass a tag-derived icon (e.g. `getEventFallbackIcon`) for a closer match to the event's category. */
15
+ icon?: ReactNode;
16
+ className?: string;
17
+ };
18
+ declare function EventPosterFallback({ icon, className }: EventPosterFallbackProps): react_jsx_runtime.JSX.Element;
19
+
20
+ export { EventPosterFallback, type EventPosterFallbackProps };
@@ -0,0 +1,3 @@
1
+ export { EventPosterFallback } from '../chunk-FDITZ2VM.js';
2
+ import '../chunk-FEK5XGZW.js';
3
+ import '../chunk-3GWWZKX7.js';
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Structural mirror of the openapi `Event` schema, decoupled from any one app's
3
+ * generated types. Both FE and admin map their domain shapes into this type
4
+ * before passing data to `<EventCard>` / `<EventListRow>` / `<EventDaySection>`.
5
+ *
6
+ * Same contract as `place-types.ts`: no app schemas, no app hooks, no i18n.
7
+ * Every user-facing string arrives through a `*Labels` object, and every
8
+ * locale-sensitive format arrives as an injected formatter — the DS never owns
9
+ * a translation key or an `Intl` locale.
10
+ */
11
+ type EventPreview = {
12
+ id: string;
13
+ title: string;
14
+ description?: string;
15
+ /** Short teaser (≤79 chars) for tight surfaces. Absent for events without one. */
16
+ short_description?: string;
17
+ /** Free-text venue/location line as returned by the API. */
18
+ location: string;
19
+ /** ISO 8601 date-time. */
20
+ starts_at: string;
21
+ /** ISO 8601 date-time. Absent for events with no published end. */
22
+ ends_at?: string;
23
+ /**
24
+ * Entry fee in RON. `0` means explicitly free; `undefined` means unknown.
25
+ * The distinction is load-bearing — see `resolveEventEntryFee`.
26
+ */
27
+ entry_fee?: number;
28
+ place_name?: string;
29
+ place_slug?: string;
30
+ /** 0–100 social-buzz score. `0` for events with no engagement signal. */
31
+ hype_score?: number;
32
+ performers?: EventPerformerRef[];
33
+ tags?: EventTagRef[];
34
+ event_concept_slug?: string;
35
+ event_concept_title?: string;
36
+ /** Booking URL, when the host takes bookings through a link. */
37
+ bookings?: string;
38
+ /** Ticketing URL, when the event is ticketed. */
39
+ tickets?: string;
40
+ /**
41
+ * Pre-resolved poster URL. Callers compute this themselves — the API returns
42
+ * a `Photo.key`, and CDN base plus transform differ per app.
43
+ */
44
+ poster_url?: string;
45
+ };
46
+ /** A taxonomy tag. `slug` is only unique within its `axis_slug`. */
47
+ type EventTagRef = {
48
+ slug: string;
49
+ axis_slug: string;
50
+ };
51
+ type EventPerformerRef = {
52
+ name: string;
53
+ kind: "person" | "group";
54
+ };
55
+ /**
56
+ * Entry-fee state. `unknown` is a real third case, not a missing `paid` — an
57
+ * event with no published fee must never render as free.
58
+ */
59
+ type EventEntryFee = {
60
+ kind: "free";
61
+ } | {
62
+ kind: "paid";
63
+ amountRon: number;
64
+ } | {
65
+ kind: "unknown";
66
+ };
67
+ /** Structural, not editorial — safe to derive inside the DS. */
68
+ declare function resolveEventEntryFee(event: EventPreview): EventEntryFee;
69
+ /**
70
+ * Locale-sensitive formatters, injected by the caller. The DS holds no `Intl`
71
+ * locale and no currency of its own.
72
+ */
73
+ type EventFormatters = {
74
+ /** e.g. `"20:00"` */
75
+ time: (isoDateTime: string) => string;
76
+ /** e.g. `"Sat, Sep 5"` — used when a card appears outside its own day section. */
77
+ day: (isoDateTime: string) => string;
78
+ /** e.g. `50 => "50 RON"` */
79
+ price: (amountRon: number) => string;
80
+ };
81
+ /**
82
+ * The extra formatters a date badge needs, split out rather than added to
83
+ * `EventFormatters` so `<EventCard>` keeps asking for only what it uses.
84
+ * `<EventListRow>` and the timeline's day headers need the parts separately.
85
+ */
86
+ type EventDateBadgeFormatters = EventFormatters & {
87
+ /** Day of month as displayed, e.g. `"05"`. */
88
+ dayNumber: (isoDateTime: string) => string;
89
+ /** Short month, e.g. `"SEP"`. */
90
+ monthShort: (isoDateTime: string) => string;
91
+ };
92
+ /**
93
+ * Labels passed to `<EventCard>`. All translation happens in the caller.
94
+ *
95
+ * There is no `priceUnknown` here on purpose. An unknown fee is the commonest
96
+ * case in this feed, and every surface that used to render a placeholder for
97
+ * it now renders nothing — see the long note in `event-list-row-wide.tsx`.
98
+ */
99
+ type EventCardLabels = {
100
+ free: string;
101
+ /** Badge shown while the event is currently running. */
102
+ liveNow: string;
103
+ };
104
+ /**
105
+ * Labels passed to `<EventListRow>`. Extends the card's with the sold-out
106
+ * chip; the row's ACTION labels live on `EventListRowWideLabels`, since the
107
+ * phone row has no action to label.
108
+ */
109
+ type EventListRowLabels = EventCardLabels & {
110
+ soldOut: string;
111
+ };
112
+ /** Labels passed to `<DayRailChip>`. */
113
+ type DayRailChipLabels = {
114
+ /** Screen-reader text for a day with no events, rendered where the count sits. */
115
+ noEvents: string;
116
+ };
117
+
118
+ export { type DayRailChipLabels, type EventCardLabels, type EventDateBadgeFormatters, type EventEntryFee, type EventFormatters, type EventListRowLabels, type EventPerformerRef, type EventPreview, type EventTagRef, resolveEventEntryFee };
@@ -0,0 +1,2 @@
1
+ export { resolveEventEntryFee } from '../chunk-DNSXMHYX.js';
2
+ import '../chunk-3GWWZKX7.js';
@@ -0,0 +1,44 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ /**
5
+ * EventsEmptyState — "nothing on in this city".
6
+ *
7
+ * BUILT FRESH, NOT COMPOSED FROM `empty-state.tsx`: that component's actions
8
+ * only take `onClick` (no `href`, no per-action icon, no link-component
9
+ * injection), and its buttons render through the shared `<Button>` variants,
10
+ * none of which produce this design's `bg-foreground`/`text-background`
11
+ * primary chip. Both actions here need to render either an `<a>` (via the
12
+ * same injected `linkComponent` contract as the rest of `Events/*`) or a
13
+ * `<button>`, which `empty-state.tsx` has no path for. Reusing it would mean
14
+ * bolting a second, incompatible action API onto it — the "compose it if it
15
+ * fits" bar isn't met here.
16
+ *
17
+ * Illustration follows the DS image-fallback rule: a real photo when
18
+ * `illustrationUrl` is given, otherwise a tinted gradient circle with a
19
+ * drop-shadowed icon — never a bare icon on a flat background.
20
+ */
21
+ type EventsEmptyStateLinkProps = {
22
+ href: string;
23
+ className?: string;
24
+ children: ReactNode;
25
+ onClick?: (mouseEvent: React.MouseEvent) => void;
26
+ };
27
+ type EventsEmptyStateAction = {
28
+ label: string;
29
+ icon?: ReactNode;
30
+ href?: string;
31
+ onClick?: () => void;
32
+ };
33
+ type EventsEmptyStateProps = {
34
+ title: string;
35
+ body: string;
36
+ illustrationUrl?: string;
37
+ primaryAction?: EventsEmptyStateAction;
38
+ secondaryAction?: EventsEmptyStateAction;
39
+ linkComponent?: React.ComponentType<EventsEmptyStateLinkProps>;
40
+ className?: string;
41
+ };
42
+ declare function EventsEmptyState({ title, body, illustrationUrl, primaryAction, secondaryAction, linkComponent: LinkComponent, className, }: EventsEmptyStateProps): react_jsx_runtime.JSX.Element;
43
+
44
+ export { EventsEmptyState, type EventsEmptyStateAction, type EventsEmptyStateLinkProps, type EventsEmptyStateProps };
@@ -0,0 +1,73 @@
1
+ import { cn } from '../chunk-FEK5XGZW.js';
2
+ import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
3
+ import { CalendarOff } from 'lucide-react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ function DefaultLink(_a) {
7
+ var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
8
+ return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
9
+ }
10
+ var ACTION_BASE = "inline-flex h-11 w-full items-center justify-center gap-2 rounded-xl border px-5 text-sm font-semibold transition-colors duration-150 motion-reduce:transition-none cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 sm:w-auto";
11
+ var PRIMARY_ACTION_CLASSES = cn(
12
+ ACTION_BASE,
13
+ "border-foreground bg-foreground text-background hover:bg-foreground/90"
14
+ );
15
+ var SECONDARY_ACTION_CLASSES = cn(
16
+ ACTION_BASE,
17
+ "border-border bg-background text-foreground hover:bg-muted"
18
+ );
19
+ function renderAction(action, classes, LinkComponent) {
20
+ if (!action) return null;
21
+ if (action.href) {
22
+ return /* @__PURE__ */ jsxs(
23
+ LinkComponent,
24
+ {
25
+ href: action.href,
26
+ className: classes,
27
+ onClick: action.onClick ? () => {
28
+ var _a;
29
+ return (_a = action.onClick) == null ? void 0 : _a.call(action);
30
+ } : void 0,
31
+ children: [
32
+ action.icon,
33
+ action.label
34
+ ]
35
+ }
36
+ );
37
+ }
38
+ return /* @__PURE__ */ jsxs("button", { type: "button", className: classes, onClick: action.onClick, children: [
39
+ action.icon,
40
+ action.label
41
+ ] });
42
+ }
43
+ function EventsEmptyState({
44
+ title,
45
+ body,
46
+ illustrationUrl,
47
+ primaryAction,
48
+ secondaryAction,
49
+ linkComponent: LinkComponent = DefaultLink,
50
+ className
51
+ }) {
52
+ return /* @__PURE__ */ jsxs(
53
+ "div",
54
+ {
55
+ role: "status",
56
+ className: cn("flex flex-col items-center gap-[14px] pt-[44px] pb-[30px] text-center", className),
57
+ children: [
58
+ /* @__PURE__ */ jsx("div", { className: "h-24 w-24 shrink-0 overflow-hidden rounded-full sm:h-[120px] sm:w-[120px]", children: illustrationUrl ? (
59
+ // eslint-disable-next-line @next/next/no-img-element
60
+ /* @__PURE__ */ jsx("img", { src: illustrationUrl, alt: "", className: "h-full w-full object-cover" })
61
+ ) : /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center bg-gradient-to-br from-primary/15 to-primary/5", children: /* @__PURE__ */ jsx(CalendarOff, { className: "h-8 w-8 text-primary drop-shadow-sm sm:h-10 sm:w-10", "aria-hidden": true }) }) }),
62
+ /* @__PURE__ */ jsx("h3", { className: "text-[18px] font-extrabold tracking-[-0.02em] sm:text-[20px]", children: title }),
63
+ /* @__PURE__ */ jsx("p", { className: "max-w-[460px] text-[13px] leading-[1.6] text-muted-foreground sm:text-[13.5px]", children: body }),
64
+ (primaryAction || secondaryAction) && /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-[9px] pt-1 sm:w-auto sm:flex-row sm:gap-[10px]", children: [
65
+ renderAction(primaryAction, PRIMARY_ACTION_CLASSES, LinkComponent),
66
+ renderAction(secondaryAction, SECONDARY_ACTION_CLASSES, LinkComponent)
67
+ ] })
68
+ ]
69
+ }
70
+ );
71
+ }
72
+
73
+ export { EventsEmptyState };
@@ -0,0 +1,93 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ComponentPropsWithoutRef } from 'react';
3
+ import { LucideIcon } from 'lucide-react';
4
+
5
+ /**
6
+ * FacetGroup — one filter group in the events sidebar or the mobile filter sheet.
7
+ *
8
+ * REAL INPUTS, NOT STYLED DIVS: the DS's `<Checkbox>` (`checkbox.tsx`) is
9
+ * a Radix primitive whose check glyph is fixed at 14px inside a 20px box with
10
+ * no prop to shrink either — this design's 16px box with an 11px glyph can't
11
+ * be reached by styling it from the outside, and this file isn't allowed to
12
+ * edit `checkbox.tsx` itself. So each row is a visually-hidden native
13
+ * `<input>` — real semantics, real keyboard/Enter/Space/arrow behaviour, a
14
+ * real accessibility-tree checked state — paired with a decorative box that
15
+ * carries the visual design. `peer`/`peer-focus-visible` puts a visible focus
16
+ * ring on the decorative box when the hidden input has focus.
17
+ *
18
+ * SELECTION MODE IS PART OF THE CONTRACT: `selection="single"` renders real
19
+ * radios sharing one `name`, so the browser and the accessibility tree both
20
+ * know only one value can be live. Rendering checkboxes for a single-valued
21
+ * facet (the events list's WHEN scope, for one) makes the control lie: ticking
22
+ * one option silently unticks another, and a screen reader announces N
23
+ * independent checkboxes one of which is inexplicably always checked.
24
+ *
25
+ * The group itself is a `<fieldset>`/`<legend>`, the correct native pairing
26
+ * for "here is a caption for this set of options" — screen readers announce
27
+ * the group title once per option instead of the title being lost as a bare
28
+ * visual label.
29
+ */
30
+ type FacetOption = {
31
+ id: string;
32
+ label: string;
33
+ count: number;
34
+ checked?: boolean;
35
+ };
36
+ type FacetGroupSelection = "multiple" | "single";
37
+ /**
38
+ * Row density. `comfortable` is the default because this component also renders
39
+ * inside the mobile filter sheet, where a row has to clear the 44px WCAG 2.5.5
40
+ * target floor. `compact` is opt-in, for a dense pointer-driven sidebar.
41
+ */
42
+ type FacetGroupSize = "compact" | "comfortable";
43
+ type FacetGroupProps = Omit<ComponentPropsWithoutRef<"fieldset">, "title" | "children" | "onToggle"> & {
44
+ title: string;
45
+ /** Decorative glyph in the legend, before the title. The title stays the accessible name. */
46
+ icon?: LucideIcon;
47
+ options: FacetOption[];
48
+ /**
49
+ * `"multiple"` (default) renders checkboxes. `"single"` renders radios sharing
50
+ * one `name` — use it for any facet whose model holds exactly one value.
51
+ */
52
+ selection?: FacetGroupSelection;
53
+ /**
54
+ * The radio group's shared `name` when `selection="single"`. Optional: a
55
+ * per-instance name is derived from `useId()` when omitted, so radios can
56
+ * never leak into a neighbouring group. Pass one when the fieldset is
57
+ * submitted as part of a native form and the name has to be stable.
58
+ */
59
+ name?: string;
60
+ size?: FacetGroupSize;
61
+ /**
62
+ * Turns the legend into a disclosure toggle for this group's options.
63
+ *
64
+ * Off by default: a sidebar of permanently-open groups is the right default
65
+ * for a facet panel, because seeing which dimensions exist is most of what
66
+ * the panel is for. Turn it on where several groups are long enough that
67
+ * scanning them costs more than opening one — the events list's five, with
68
+ * venues running to dozens of options.
69
+ */
70
+ collapsible?: boolean;
71
+ /** Only meaningful with `collapsible`. Groups open by default. */
72
+ defaultOpen?: boolean;
73
+ /** Fires with `(id, true)` for the newly picked radio under `selection="single"`. */
74
+ onToggle?: (id: string, checked: boolean) => void;
75
+ /** e.g. "Show all". Omit to hide the trailing action. */
76
+ moreLabel?: string;
77
+ onMore?: () => void;
78
+ className?: string;
79
+ };
80
+ declare function FacetGroup({ title, icon: Icon, options, selection, name, size, collapsible, defaultOpen, onToggle, moreLabel, onMore, className, ...rest }: FacetGroupProps): react_jsx_runtime.JSX.Element;
81
+ type FacetGroupSkeletonProps = {
82
+ /** How many option rows to draw — match the expected/last-known option count. */
83
+ optionCount?: number;
84
+ /** Shows the trailing "more" placeholder, matching `FacetGroupProps["moreLabel"]`. */
85
+ showMore?: boolean;
86
+ /** Must match the `<FacetGroup>` it stands in for, or rows shift when data lands. */
87
+ size?: FacetGroupSize;
88
+ className?: string;
89
+ };
90
+ /** Mirrors `<FacetGroup>`'s geometry exactly so nothing shifts when data lands. */
91
+ declare function FacetGroupSkeleton({ optionCount, showMore, size, className, }: FacetGroupSkeletonProps): react_jsx_runtime.JSX.Element;
92
+
93
+ export { FacetGroup, type FacetGroupProps, type FacetGroupSelection, type FacetGroupSize, FacetGroupSkeleton, type FacetGroupSkeletonProps, type FacetOption };