@bearmenu/ui 0.8.8 → 0.8.10

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 (206) hide show
  1. package/dist/chunk-24RFI4RQ.js +167 -0
  2. package/dist/chunk-2XCZJWTV.js +121 -0
  3. package/dist/chunk-5RWTOT5Y.js +72 -0
  4. package/dist/chunk-62ES6N32.js +27 -0
  5. package/dist/chunk-AKQ57NXY.js +58 -0
  6. package/dist/chunk-CLLY6XB3.js +41 -0
  7. package/dist/chunk-DTXNDLSE.js +125 -0
  8. package/dist/chunk-F6FMZJDG.js +113 -0
  9. package/dist/{chunk-2WDJR6K7.js → chunk-G7IFL4Z4.js} +4 -1
  10. package/dist/chunk-MZL7CGCL.js +109 -0
  11. package/dist/chunk-Q6QH52LJ.js +38 -0
  12. package/dist/chunk-SY6RV476.js +48 -0
  13. package/dist/chunk-TH6W2PWG.js +213 -0
  14. package/dist/chunk-UDN7UHJW.js +60 -0
  15. package/dist/{chunk-TT3WFS6S.js → chunk-YOKHBAIH.js} +11 -11
  16. package/dist/components/alert.d.ts +2 -2
  17. package/dist/components/badge.d.ts +1 -1
  18. package/dist/components/concept-compare-rail.d.ts +50 -0
  19. package/dist/components/concept-compare-rail.js +5 -0
  20. package/dist/components/concept-compare.d.ts +110 -0
  21. package/dist/components/concept-compare.js +238 -0
  22. package/dist/components/concept-convergence.d.ts +41 -0
  23. package/dist/components/concept-convergence.js +53 -0
  24. package/dist/components/convergence.d.ts +25 -0
  25. package/dist/components/convergence.js +4 -0
  26. package/dist/components/date-input.d.ts +1 -1
  27. package/dist/components/event-card.js +1 -1
  28. package/dist/components/event-compact-row.d.ts +1 -1
  29. package/dist/components/event-compact-row.js +1 -1
  30. package/dist/components/event-detail-panel.d.ts +171 -25
  31. package/dist/components/event-detail-panel.js +472 -175
  32. package/dist/components/event-index-row.js +1 -1
  33. package/dist/components/event-list-row-wide.js +2 -2
  34. package/dist/components/event-list-row.js +2 -2
  35. package/dist/components/explainer-steps.d.ts +34 -0
  36. package/dist/components/explainer-steps.js +36 -0
  37. package/dist/components/glass-ground.d.ts +66 -0
  38. package/dist/components/glass-ground.js +3 -0
  39. package/dist/components/hub-surface.d.ts +27 -0
  40. package/dist/components/hub-surface.js +30 -0
  41. package/dist/components/hue-chip.d.ts +70 -0
  42. package/dist/components/hue-chip.js +3 -0
  43. package/dist/components/kitchen-dossier.d.ts +88 -0
  44. package/dist/components/kitchen-dossier.js +187 -0
  45. package/dist/components/menu-dead-end.d.ts +56 -0
  46. package/dist/components/menu-dead-end.js +49 -0
  47. package/dist/components/menu-family-block.d.ts +99 -0
  48. package/dist/components/menu-family-block.js +155 -0
  49. package/dist/components/menu-family-card.d.ts +65 -0
  50. package/dist/components/menu-family-card.js +79 -0
  51. package/dist/components/menu-field.d.ts +57 -0
  52. package/dist/components/menu-field.js +93 -0
  53. package/dist/components/menu-filter-chips.d.ts +86 -0
  54. package/dist/components/menu-filter-chips.js +122 -0
  55. package/dist/components/menu-group-rows.d.ts +53 -0
  56. package/dist/components/menu-group-rows.js +67 -0
  57. package/dist/components/menu-hub-hero.d.ts +65 -0
  58. package/dist/components/menu-hub-hero.js +103 -0
  59. package/dist/components/menu-index-header.d.ts +37 -0
  60. package/dist/components/menu-index-header.js +68 -0
  61. package/dist/components/menu-index-list.d.ts +48 -0
  62. package/dist/components/menu-index-list.js +96 -0
  63. package/dist/components/menu-intent-hero.d.ts +69 -0
  64. package/dist/components/menu-intent-hero.js +87 -0
  65. package/dist/components/menu-intent-tiles.d.ts +31 -0
  66. package/dist/components/menu-intent-tiles.js +50 -0
  67. package/dist/components/menu-item.d.ts +127 -0
  68. package/dist/components/menu-item.js +5 -0
  69. package/dist/components/menu-kitchen-list.d.ts +82 -0
  70. package/dist/components/menu-kitchen-list.js +5 -0
  71. package/dist/components/menu-mocks.d.ts +90 -0
  72. package/dist/components/menu-mocks.js +504 -0
  73. package/dist/components/menu-types.d.ts +421 -0
  74. package/dist/components/menu-types.js +1 -0
  75. package/dist/components/motion-icon-controls.js +2 -2
  76. package/dist/components/motion-icon-set.js +21 -9
  77. package/dist/components/motion-icon.d.ts +22 -1
  78. package/dist/components/motion-icon.js +1 -1
  79. package/dist/components/open-now-list.d.ts +40 -0
  80. package/dist/components/open-now-list.js +69 -0
  81. package/dist/components/photo-ground.d.ts +64 -0
  82. package/dist/components/photo-ground.js +3 -0
  83. package/dist/components/place-about-tab.js +2 -2
  84. package/dist/components/place-details-mobile.js +2 -2
  85. package/dist/components/place-types.d.ts +112 -1
  86. package/dist/components/qa-block.d.ts +36 -0
  87. package/dist/components/qa-block.js +24 -0
  88. package/dist/components/scroll-fade.js +3 -121
  89. package/dist/components/signature-chip.d.ts +37 -0
  90. package/dist/components/signature-chip.js +4 -0
  91. package/dist/components/snap-rail.d.ts +48 -5
  92. package/dist/components/snap-rail.js +3 -51
  93. package/dist/components/stat-banner.d.ts +47 -0
  94. package/dist/components/stat-banner.js +61 -0
  95. package/dist/components/story.d.ts +34 -0
  96. package/dist/components/story.js +3 -0
  97. package/dist/components/tag.d.ts +2 -2
  98. package/dist/components/text.d.ts +1 -1
  99. package/dist/components/top-comparison.d.ts +28 -0
  100. package/dist/components/top-comparison.js +76 -0
  101. package/dist/components/top-cross-link.d.ts +34 -0
  102. package/dist/components/top-cross-link.js +101 -0
  103. package/dist/components/top-ranking-entry.d.ts +53 -0
  104. package/dist/components/top-ranking-entry.js +217 -0
  105. package/dist/components/top-ranking-hero.d.ts +61 -0
  106. package/dist/components/top-ranking-hero.js +99 -0
  107. package/dist/components/top-ranking-legend.d.ts +69 -0
  108. package/dist/components/top-ranking-legend.js +124 -0
  109. package/dist/components/top-types.d.ts +109 -0
  110. package/dist/components/top-types.js +1 -0
  111. package/dist/components/venue-grade-dimensions.d.ts +38 -0
  112. package/dist/components/venue-grade-dimensions.js +3 -0
  113. package/dist/components/venue-quotes.d.ts +32 -0
  114. package/dist/components/venue-quotes.js +3 -0
  115. package/dist/components/venue-wall.d.ts +41 -0
  116. package/dist/components/venue-wall.js +118 -0
  117. package/dist/components/weekday-theme-banner.d.ts +70 -0
  118. package/dist/components/weekday-theme-banner.js +127 -0
  119. package/dist/components/weekend-panel.js +2 -2
  120. package/package.json +1 -1
  121. package/src/components/colour-dictionary.stories.tsx +227 -0
  122. package/src/components/concept-compare-rail.tsx +131 -0
  123. package/src/components/concept-compare.stories.tsx +172 -0
  124. package/src/components/concept-compare.tsx +443 -0
  125. package/src/components/concept-convergence.stories.tsx +53 -0
  126. package/src/components/concept-convergence.tsx +90 -0
  127. package/src/components/convergence.stories.tsx +54 -0
  128. package/src/components/convergence.tsx +177 -0
  129. package/src/components/event-compact-row.tsx +1 -1
  130. package/src/components/event-detail-panel.stories.tsx +205 -97
  131. package/src/components/event-detail-panel.test.tsx +181 -0
  132. package/src/components/event-detail-panel.tsx +703 -185
  133. package/src/components/explainer-steps.stories.tsx +46 -0
  134. package/src/components/explainer-steps.tsx +74 -0
  135. package/src/components/glass-ground.tsx +129 -0
  136. package/src/components/hub-surface.stories.tsx +68 -0
  137. package/src/components/hub-surface.tsx +50 -0
  138. package/src/components/hue-chip.stories.tsx +76 -0
  139. package/src/components/hue-chip.test.tsx +62 -0
  140. package/src/components/hue-chip.tsx +99 -0
  141. package/src/components/kitchen-dossier.stories.tsx +108 -0
  142. package/src/components/kitchen-dossier.tsx +322 -0
  143. package/src/components/menu-dead-end.stories.tsx +67 -0
  144. package/src/components/menu-dead-end.tsx +127 -0
  145. package/src/components/menu-family-block.stories.tsx +91 -0
  146. package/src/components/menu-family-block.tsx +314 -0
  147. package/src/components/menu-family-card.stories.tsx +120 -0
  148. package/src/components/menu-family-card.tsx +191 -0
  149. package/src/components/menu-field.stories.tsx +74 -0
  150. package/src/components/menu-field.tsx +199 -0
  151. package/src/components/menu-filter-chips.stories.tsx +107 -0
  152. package/src/components/menu-filter-chips.tsx +238 -0
  153. package/src/components/menu-group-rows.stories.tsx +54 -0
  154. package/src/components/menu-group-rows.tsx +133 -0
  155. package/src/components/menu-hub-hero.stories.tsx +92 -0
  156. package/src/components/menu-hub-hero.tsx +187 -0
  157. package/src/components/menu-index-header.stories.tsx +72 -0
  158. package/src/components/menu-index-header.tsx +125 -0
  159. package/src/components/menu-index-list.stories.tsx +50 -0
  160. package/src/components/menu-index-list.tsx +149 -0
  161. package/src/components/menu-intent-hero.stories.tsx +67 -0
  162. package/src/components/menu-intent-hero.tsx +189 -0
  163. package/src/components/menu-intent-tiles.stories.tsx +54 -0
  164. package/src/components/menu-intent-tiles.tsx +76 -0
  165. package/src/components/menu-item.tsx +416 -0
  166. package/src/components/menu-kitchen-list.stories.tsx +67 -0
  167. package/src/components/menu-kitchen-list.test.tsx +78 -0
  168. package/src/components/menu-kitchen-list.tsx +284 -0
  169. package/src/components/menu-mocks.ts +592 -0
  170. package/src/components/menu-types.ts +442 -0
  171. package/src/components/motion-icon-controls.tsx +11 -11
  172. package/src/components/motion-icon-set.tsx +36 -8
  173. package/src/components/motion-icon.test.tsx +23 -1
  174. package/src/components/motion-icon.tsx +20 -0
  175. package/src/components/open-now-list.stories.tsx +76 -0
  176. package/src/components/open-now-list.tsx +127 -0
  177. package/src/components/photo-ground.tsx +147 -0
  178. package/src/components/place-types.ts +112 -0
  179. package/src/components/qa-block.stories.tsx +43 -0
  180. package/src/components/qa-block.tsx +60 -0
  181. package/src/components/signature-chip.tsx +77 -0
  182. package/src/components/snap-rail.tsx +133 -9
  183. package/src/components/stat-banner.stories.tsx +100 -0
  184. package/src/components/stat-banner.tsx +117 -0
  185. package/src/components/story.tsx +225 -0
  186. package/src/components/top-comparison.stories.tsx +78 -0
  187. package/src/components/top-comparison.tsx +151 -0
  188. package/src/components/top-cross-link.stories.tsx +84 -0
  189. package/src/components/top-cross-link.tsx +171 -0
  190. package/src/components/top-ranking-entry.stories.tsx +171 -0
  191. package/src/components/top-ranking-entry.test.tsx +105 -0
  192. package/src/components/top-ranking-entry.tsx +425 -0
  193. package/src/components/top-ranking-hero.stories.tsx +76 -0
  194. package/src/components/top-ranking-hero.tsx +218 -0
  195. package/src/components/top-ranking-legend.stories.tsx +78 -0
  196. package/src/components/top-ranking-legend.tsx +239 -0
  197. package/src/components/top-types.ts +110 -0
  198. package/src/components/venue-grade-dimensions.stories.tsx +83 -0
  199. package/src/components/venue-grade-dimensions.tsx +91 -0
  200. package/src/components/venue-quotes.stories.tsx +59 -0
  201. package/src/components/venue-quotes.tsx +64 -0
  202. package/src/components/venue-wall.stories.tsx +78 -0
  203. package/src/components/venue-wall.tsx +185 -0
  204. package/src/components/weekday-theme-banner.stories.tsx +113 -0
  205. package/src/components/weekday-theme-banner.tsx +231 -0
  206. package/dist/{chunk-XWMRABZW.js → chunk-HSIYYA2E.js} +1 -1
@@ -0,0 +1,64 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ /**
4
+ * PhotoGround — venue photography as the ground of a card.
5
+ *
6
+ * Three cards are built on photographs rather than on panels: the hub's family
7
+ * card, the cuisines index's family block and the concept card. Each had grown
8
+ * its own copy of the same stack — a dark ground, a grid of `<img>`s with an
9
+ * initial for the missing ones, a hue layer, an overlay — and the one rule that
10
+ * matters for all of them (the tint has to be `mix-blend-color`, the ground
11
+ * has to be a fixed literal) was written three times. This is the stack, once.
12
+ *
13
+ * ## What it owns and what it leaves to the card
14
+ *
15
+ * It owns the photographs and their colour: the ground, the tiles, the fallback
16
+ * initial, the family's hue and an optional uniform dark overlay. It does NOT
17
+ * own the glass — the scrims and frosted bands that carry a card's type run in
18
+ * a different direction on every card (down the family block's phone, across
19
+ * its desktop, in from both ends of the concept card) and are the card's own.
20
+ *
21
+ * ## Two layouts
22
+ *
23
+ * `mosaic` tiles every photograph into a grid the caller shapes; `stack` shows
24
+ * ONE of them, `active`, and cross-fades to the next — a card whose ground
25
+ * follows a swipe. Same slots, same fallback, same tint either way.
26
+ *
27
+ * ## Why the ground is a literal, and why the tint is `color`
28
+ *
29
+ * The ground is the backdrop a blend or blur samples before a lazy image lands
30
+ * and the tile an empty slot shows, so it must not change with the theme —
31
+ * photography is not themed, and a card that flashed paper-white behind its
32
+ * photographs in light mode was wrong in exactly the mode most people use.
33
+ * `mix-blend-mode: color` takes hue and chroma from the tint layer and
34
+ * luminance from the photograph, so the room keeps its structure and the
35
+ * family keeps its colour; a plain overlay would have muddied both.
36
+ */
37
+ /** The ground under the photography. Fixed, and deliberately not a token. */
38
+ declare const PHOTO_GROUND = "bg-[oklch(0.21_0.012_55)]";
39
+ type PhotoGroundProps = {
40
+ /** One per slot. An absent one draws the slot's initial on the ground. */
41
+ photos: (string | undefined)[];
42
+ /** The fallback glyph per slot — a venue's first letter. One is reused for all. */
43
+ initials: string | string[];
44
+ /** `mosaic` tiles every slot; `stack` shows `active` and cross-fades. */
45
+ mode?: "mosaic" | "stack";
46
+ /** `stack` only: which slot is showing. */
47
+ active?: number;
48
+ /** `mosaic` only: the grid template, e.g. `"grid-cols-2 grid-rows-2 lg:grid-cols-3"`. */
49
+ mosaicClassName?: string;
50
+ /** `mosaic` only: slots from this index on are desktop-only tiles. */
51
+ phoneTiles?: number;
52
+ /** Finished CSS gradient — the family's colour, laid over the photographs. */
53
+ gradient?: string;
54
+ /** A uniform dark overlay on every photograph. */
55
+ overlay?: boolean;
56
+ /** Extra classes on the overlay, e.g. a hover that lifts it. */
57
+ overlayClassName?: string;
58
+ /** How eagerly the first photograph loads. `stack` grounds are above the fold. */
59
+ loading?: "lazy" | "eager";
60
+ className?: string;
61
+ };
62
+ declare function PhotoGround({ photos, initials, mode, active, mosaicClassName, phoneTiles, gradient, overlay, overlayClassName, loading, className, }: PhotoGroundProps): react_jsx_runtime.JSX.Element;
63
+
64
+ export { PHOTO_GROUND, PhotoGround, type PhotoGroundProps };
@@ -0,0 +1,3 @@
1
+ export { PHOTO_GROUND, PhotoGround } from '../chunk-5RWTOT5Y.js';
2
+ import '../chunk-FEK5XGZW.js';
3
+ import '../chunk-3GWWZKX7.js';
@@ -1,7 +1,7 @@
1
- export { PlaceAboutTab } from '../chunk-XWMRABZW.js';
1
+ export { PlaceAboutTab } from '../chunk-HSIYYA2E.js';
2
2
  import '../chunk-VG3PND3D.js';
3
- import '../chunk-WSRWFA6K.js';
4
3
  import '../chunk-ZDAHKI3A.js';
4
+ import '../chunk-WSRWFA6K.js';
5
5
  import '../chunk-7BWTYWM3.js';
6
6
  import '../chunk-FEK5XGZW.js';
7
7
  import '../chunk-3GWWZKX7.js';
@@ -1,7 +1,7 @@
1
- import { PlaceAboutTab } from '../chunk-XWMRABZW.js';
1
+ import { PlaceAboutTab } from '../chunk-HSIYYA2E.js';
2
2
  import '../chunk-VG3PND3D.js';
3
- import '../chunk-WSRWFA6K.js';
4
3
  import '../chunk-ZDAHKI3A.js';
4
+ import '../chunk-WSRWFA6K.js';
5
5
  import { Text } from '../chunk-7BWTYWM3.js';
6
6
  import { Badge } from '../chunk-UKBNQO6Q.js';
7
7
  import { cn } from '../chunk-FEK5XGZW.js';
@@ -47,6 +47,13 @@ type PlacePreview = {
47
47
  hour: number;
48
48
  score: number;
49
49
  }>;
50
+ /**
51
+ * The review distillation. Drives every menu-hub surface that speaks for a
52
+ * venue — `<KitchenDossier>`, `<MenuKitchenList>`, `<OpenNowList>` —
53
+ * because the signature dish, the pull-quotes and the graded dimensions all
54
+ * live here rather than on the menu itself.
55
+ */
56
+ reviews_digest?: PlaceReviewsDigest;
50
57
  type?: string;
51
58
  business_status?: 'operational' | 'closed_temporarily' | 'closed_permanently';
52
59
  phone?: string;
@@ -71,6 +78,110 @@ type PlaceSchedule = Record<WeekdayKey, PlaceHourBlock[]>;
71
78
  type PlacePriceRange = {
72
79
  price_range_low?: number;
73
80
  price_range_high?: number;
81
+ /** Median price across the place's menu, in the local currency. */
82
+ median_price?: number;
83
+ };
84
+ /**
85
+ * Menu items are priced per size; a single-size item still ships one entry.
86
+ *
87
+ * Defined here rather than in `menu-types.ts` because `PlaceMustTry` carries
88
+ * it, and `menu-types.ts` already imports from this file — keeping the
89
+ * definition here leaves that import one-directional. `menu-types.ts`
90
+ * re-exports it, so menu code never reaches into place types for it.
91
+ */
92
+ type MenuSizeAndPrice = {
93
+ /** Grams or millilitres. */
94
+ size: number;
95
+ price: number;
96
+ discounted_price?: number;
97
+ discount_percentage?: number;
98
+ };
99
+ /** A digest string with the reviews that back it. `review_ids.length` is the mention count. */
100
+ type CitedText = {
101
+ text: string;
102
+ review_ids?: string[];
103
+ };
104
+ /** A digest enum value with the reviews that back it. The value is a language-neutral code. */
105
+ type CitedValue = {
106
+ value: string;
107
+ review_ids?: string[];
108
+ };
109
+ /**
110
+ * One dish or drink the reviews single out.
111
+ *
112
+ * `mentions` and `score` come from the item census and are only served by the
113
+ * place DETAIL endpoint — a listing carries the item without them. Surfaces
114
+ * that need a count from a list fall back to `review_ids.length`, which is
115
+ * present in both. `strength`, `why` and `review_ids` are absent for census
116
+ * items the prose digest never mentioned, so none of them can be assumed.
117
+ */
118
+ type PlaceMustTry = {
119
+ name: string;
120
+ why?: string;
121
+ strength?: 'signature' | 'frequent' | 'occasional';
122
+ /** Deep-link slug. Present only when the item matched a live menu row. */
123
+ slug?: string;
124
+ sizes_and_prices?: MenuSizeAndPrice[];
125
+ review_ids?: string[];
126
+ /** 0–100 census sentiment. Detail endpoint only; 3+ mentions required. */
127
+ score?: number;
128
+ /** Censused review mentions of this item. Detail endpoint only. */
129
+ mentions?: number;
130
+ };
131
+ /**
132
+ * Per-dimension 0–100 review scores.
133
+ *
134
+ * A dimension the reviews never mention is ABSENT, not zero — so a surface
135
+ * drawing these must render what it is given rather than a fixed row of seven.
136
+ * Exactly one of `food` / `coffee_quality` / `drinks_quality` is scored per
137
+ * place: a coffee bar has no food score and a restaurant has no coffee one.
138
+ */
139
+ type PlaceGradeDimensions = {
140
+ food?: number;
141
+ coffee_quality?: number;
142
+ drinks_quality?: number;
143
+ value?: number;
144
+ service?: number;
145
+ cleanliness?: number;
146
+ ambiance?: number;
147
+ portion?: number;
148
+ consistency?: number;
149
+ };
150
+ type PlaceGrade = {
151
+ /** 1.0–10.0. */
152
+ overall?: number;
153
+ /**
154
+ * Backend recommendation to show the number at all. When false the caller
155
+ * should draw a "building confidence" state instead — the DS renders what it
156
+ * is told, it does not apply the rule.
157
+ */
158
+ show_number?: boolean;
159
+ /** Locale-resolved band label, e.g. "Foarte bun". Already translated upstream. */
160
+ descriptor?: string;
161
+ confidence?: 'low' | 'medium' | 'high';
162
+ capped?: boolean;
163
+ dimensions?: PlaceGradeDimensions;
164
+ };
165
+ type PlaceReviewsDigest = {
166
+ grade?: PlaceGrade;
167
+ grade_note?: string;
168
+ tagline?: CitedText;
169
+ verdict?: CitedText;
170
+ caveat?: CitedText;
171
+ /** 1–3 standout positives. The pull-quotes on `<KitchenDossier>`. */
172
+ highlights?: CitedText[];
173
+ must_try?: PlaceMustTry[];
174
+ /** Vibe codes (cozy, quiet, family_friendly, …). Localised by the caller. */
175
+ tags?: CitedValue[];
176
+ dietary?: CitedValue[];
177
+ /** small | moderate | generous */
178
+ portion_size?: CitedValue;
179
+ /** cheap | fair | mid_range | splurge */
180
+ value?: CitedValue;
181
+ /** quiet | moderate | loud */
182
+ noise_level?: CitedValue;
183
+ /** Text reviews behind the digest. */
184
+ review_count?: number;
74
185
  };
75
186
  /** Labels passed to `<PlaceCard>`. All translation happens in the caller. */
76
187
  type PlaceCardLabels = {
@@ -151,4 +262,4 @@ type PlaceDetailsMobileLabels = PlaceAboutTabLabels & {
151
262
  noImageAvailable: string;
152
263
  };
153
264
 
154
- export type { PlaceAboutTabLabels, PlaceCardLabels, PlaceDetailsMobileLabels, PlaceHourBlock, PlaceLinkKind, PlacePreview, PlacePriceRange, PlaceSchedule, PlaceScheduleWeekLabels, WeekdayKey };
265
+ export type { CitedText, CitedValue, MenuSizeAndPrice, PlaceAboutTabLabels, PlaceCardLabels, PlaceDetailsMobileLabels, PlaceGrade, PlaceGradeDimensions, PlaceHourBlock, PlaceLinkKind, PlaceMustTry, PlacePreview, PlacePriceRange, PlaceReviewsDigest, PlaceSchedule, PlaceScheduleWeekLabels, WeekdayKey };
@@ -0,0 +1,36 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { QaItem } from './menu-types.js';
3
+ import 'react';
4
+ import './place-types.js';
5
+
6
+ /**
7
+ * QaBlock — questions answered from the numbers, as static prose.
8
+ *
9
+ * ## Never an accordion
10
+ *
11
+ * This block exists to be crawled as much as read: it is the visible half of
12
+ * the page's `FAQPage` markup, and the rule is that structured data must mirror
13
+ * content the reader can actually see. Collapsing it hides every answer from
14
+ * the crawler's first paint and buys nothing — three short answers are cheaper
15
+ * to scroll past than to expand.
16
+ *
17
+ * The caller renders the JSON-LD from the SAME array it passes here, so the
18
+ * markup and the visible answers cannot drift.
19
+ *
20
+ * ## Three across, then one
21
+ *
22
+ * Answers are two or three lines each, so a single column wastes the desktop
23
+ * measure and a two-column grid leaves an orphan. On the phone it is one
24
+ * column, in order.
25
+ */
26
+ type QaBlockProps = {
27
+ items: QaItem[];
28
+ /** Section heading, e.g. "Questions people ask". Omit where the page supplies one. */
29
+ heading?: string;
30
+ /** Heading level for the questions. Defaults to `h3`, under a page's `h2`. */
31
+ questionAs?: "h3" | "h4";
32
+ className?: string;
33
+ };
34
+ declare function QaBlock({ items, heading, questionAs: Question, className }: QaBlockProps): react_jsx_runtime.JSX.Element;
35
+
36
+ export { QaBlock, type QaBlockProps };
@@ -0,0 +1,24 @@
1
+ import { cn } from '../chunk-FEK5XGZW.js';
2
+ import '../chunk-3GWWZKX7.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ function QaBlock({ items, heading, questionAs: Question = "h3", className }) {
6
+ return /* @__PURE__ */ jsxs("section", { className: cn(className), children: [
7
+ heading && /* @__PURE__ */ jsx("h2", { className: "text-[15px] font-bold leading-tight tracking-[-0.01em]", children: heading }),
8
+ /* @__PURE__ */ jsx(
9
+ "div",
10
+ {
11
+ className: cn(
12
+ "grid grid-cols-1 gap-[18px] lg:grid-cols-3 lg:gap-[26px]",
13
+ heading && "mt-3.5"
14
+ ),
15
+ children: items.map((item) => /* @__PURE__ */ jsxs("div", { children: [
16
+ /* @__PURE__ */ jsx(Question, { className: "text-sm font-bold leading-[1.35] tracking-[-0.01em] lg:text-[15px]", children: item.question }),
17
+ /* @__PURE__ */ jsx("p", { className: "mt-[7px] text-[13px] leading-[1.65] text-muted-foreground [text-wrap:pretty] lg:text-[13.5px]", children: item.answer })
18
+ ] }, item.question))
19
+ }
20
+ )
21
+ ] });
22
+ }
23
+
24
+ export { QaBlock };
@@ -1,121 +1,3 @@
1
- import { cn } from '../chunk-FEK5XGZW.js';
2
- import { __objRest, __spreadProps, __spreadValues } from '../chunk-3GWWZKX7.js';
3
- import * as React from 'react';
4
- import { jsxs, jsx } from 'react/jsx-runtime';
5
-
6
- var fromMap = {
7
- background: "from-background",
8
- card: "from-card",
9
- muted: "from-muted"
10
- };
11
- var sizeMap = {
12
- vertical: { sm: "h-6", md: "h-12", lg: "h-20" },
13
- horizontal: { sm: "w-8", md: "w-16", lg: "w-28" }
14
- };
15
- var ScrollFade = React.forwardRef(
16
- (_a, ref) => {
17
- var _b = _a, {
18
- orientation = "vertical",
19
- fadeColor = "background",
20
- size = "md",
21
- className,
22
- scrollClassName,
23
- children
24
- } = _b, props = __objRest(_b, [
25
- "orientation",
26
- "fadeColor",
27
- "size",
28
- "className",
29
- "scrollClassName",
30
- "children"
31
- ]);
32
- const innerRef = React.useRef(null);
33
- React.useImperativeHandle(ref, () => innerRef.current);
34
- const [atStart, setAtStart] = React.useState(true);
35
- const [atEnd, setAtEnd] = React.useState(true);
36
- const update = React.useCallback(() => {
37
- const el = innerRef.current;
38
- if (!el) return;
39
- if (orientation === "vertical") {
40
- const overflow = el.scrollHeight - el.clientHeight;
41
- setAtStart(el.scrollTop <= 1);
42
- setAtEnd(overflow <= 1 || el.scrollTop >= overflow - 1);
43
- } else {
44
- const overflow = el.scrollWidth - el.clientWidth;
45
- setAtStart(el.scrollLeft <= 1);
46
- setAtEnd(overflow <= 1 || el.scrollLeft >= overflow - 1);
47
- }
48
- }, [orientation]);
49
- React.useEffect(() => {
50
- const el = innerRef.current;
51
- if (!el) return;
52
- update();
53
- el.addEventListener("scroll", update, { passive: true });
54
- const ro = new ResizeObserver(update);
55
- ro.observe(el);
56
- return () => {
57
- el.removeEventListener("scroll", update);
58
- ro.disconnect();
59
- };
60
- }, [update]);
61
- const fromClass = fromMap[fadeColor];
62
- const fadeSize = sizeMap[orientation][size];
63
- return /* @__PURE__ */ jsxs(
64
- "div",
65
- {
66
- className: cn(
67
- "relative isolate flex",
68
- orientation === "vertical" ? "flex-col" : "flex-row",
69
- className
70
- ),
71
- children: [
72
- /* @__PURE__ */ jsx(
73
- "div",
74
- __spreadProps(__spreadValues({
75
- ref: innerRef,
76
- className: cn(
77
- "min-h-0 min-w-0 flex-1",
78
- orientation === "vertical" ? "overflow-y-auto" : "overflow-x-auto",
79
- scrollClassName
80
- )
81
- }, props), {
82
- children
83
- })
84
- ),
85
- /* @__PURE__ */ jsx(
86
- "div",
87
- {
88
- "aria-hidden": true,
89
- className: cn(
90
- "pointer-events-none absolute z-10 transition-opacity duration-300",
91
- // `from-30%` adds a solid plateau before the gradient starts
92
- // fading — without it the gradient is a pure linear ramp and only
93
- // the very top pixel reads as solid, leaving the cut edge visible.
94
- // -4px inset pulls the fade past the container edge so the very
95
- // edge of clipped content is covered by the solid plateau.
96
- orientation === "vertical" ? `inset-x-0 -top-1 ${fadeSize} bg-gradient-to-b from-30%` : `inset-y-0 -left-1 ${fadeSize} bg-gradient-to-r from-30%`,
97
- fromClass,
98
- atStart ? "opacity-0" : "opacity-100"
99
- )
100
- }
101
- ),
102
- /* @__PURE__ */ jsx(
103
- "div",
104
- {
105
- "aria-hidden": true,
106
- className: cn(
107
- "pointer-events-none absolute z-10 transition-opacity duration-300",
108
- orientation === "vertical" ? `inset-x-0 -bottom-1 ${fadeSize} bg-gradient-to-t from-30%` : `inset-y-0 -right-1 ${fadeSize} bg-gradient-to-l from-30%`,
109
- fromClass,
110
- atEnd ? "opacity-0" : "opacity-100"
111
- )
112
- }
113
- )
114
- ]
115
- }
116
- );
117
- }
118
- );
119
- ScrollFade.displayName = "ScrollFade";
120
-
121
- export { ScrollFade };
1
+ export { ScrollFade } from '../chunk-2XCZJWTV.js';
2
+ import '../chunk-FEK5XGZW.js';
3
+ import '../chunk-3GWWZKX7.js';
@@ -0,0 +1,37 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ /**
4
+ * "Signature" / "Mentioned" — the marker for a menu item the review digest
5
+ * backs, shared by `<MenuItem>` and the dish/drink cards so the same claim
6
+ * never renders two different ways.
7
+ *
8
+ * When `onEvidence` is supplied the chip becomes a button that opens the
9
+ * reviews behind it, and takes a dashed outline to read as interactive. That is
10
+ * the whole differentiator: every competitor badges items ("Nou", "NEW"), none
11
+ * can show you why. Without evidence it degrades to a plain label rather than
12
+ * offering a tap that would reveal nothing.
13
+ *
14
+ * `stopPropagation` matters on every host: the row is a `role="button"` and the
15
+ * cards carry a stretched crawlable `<a>` overlay, so an un-stopped click would
16
+ * also open the item drawer. On the cards it must additionally out-rank that
17
+ * overlay's `z-[1]`, hence `relative z-[2]` from the caller.
18
+ *
19
+ * `surface="image"` is for card covers, where the chip sits over the photo
20
+ * rather than in the caption block. The accent-on-canvas palette has no
21
+ * contrast guarantee over an arbitrary photo, so it swaps to the same frosted
22
+ * fill the place badge uses there and keeps the dashed edge — which is what
23
+ * says "there is evidence behind this" — in the inverted colour.
24
+ *
25
+ * The label is passed in: the DS owns no translation keys.
26
+ */
27
+ type SignatureChipProps = {
28
+ /** Already translated. `strong` → "Signature", `weak` → "Mentioned". */
29
+ label: string;
30
+ onEvidence?: () => void;
31
+ /** `image` = over a card cover; `canvas` = in a caption or row. */
32
+ surface?: "canvas" | "image";
33
+ className?: string;
34
+ };
35
+ declare function SignatureChip({ label, onEvidence, surface, className, }: SignatureChipProps): react_jsx_runtime.JSX.Element;
36
+
37
+ export { SignatureChip, type SignatureChipProps };
@@ -0,0 +1,4 @@
1
+ export { SignatureChip } from '../chunk-Q6QH52LJ.js';
2
+ import '../chunk-UKBNQO6Q.js';
3
+ import '../chunk-FEK5XGZW.js';
4
+ import '../chunk-3GWWZKX7.js';
@@ -1,3 +1,4 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
1
2
  import * as class_variance_authority_types from 'class-variance-authority/types';
2
3
  import * as React from 'react';
3
4
  import { VariantProps } from 'class-variance-authority';
@@ -20,15 +21,57 @@ import { VariantProps } from 'class-variance-authority';
20
21
  * `card` is the 14px inset of a hub card; `page` is the 16px page gutter.
21
22
  */
22
23
  declare const snapRailVariants: (props?: ({
23
- itemWidth?: "sm" | "lg" | "md" | null | undefined;
24
+ itemWidth?: "sm" | "lg" | "full" | "md" | null | undefined;
24
25
  gap?: "default" | "sm" | null | undefined;
25
26
  bleed?: "none" | "page" | "card" | null | undefined;
26
27
  } & class_variance_authority_types.ClassProp) | undefined) => string;
27
- type SnapRailProps = React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof snapRailVariants>;
28
+ type SnapRailProps = React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof snapRailVariants> & {
29
+ /**
30
+ * Page dots under the rail, one per child, the current one filled. For
31
+ * `itemWidth="full"`, where no next card peeks in to say there is more.
32
+ * Decorative: the rail itself is the control, and every card is reachable
33
+ * by scrolling, so the dots are `aria-hidden`.
34
+ */
35
+ dots?: boolean;
36
+ /** Classes for the dots row, e.g. `lg:hidden` where the rail becomes a grid. */
37
+ dotsClassName?: string;
38
+ /**
39
+ * Reports the current page whenever it changes — for a caller that wants
40
+ * to react to the swipe beyond the dots, e.g. a backdrop that follows the
41
+ * active card. Tracking runs whenever this or `dots` is set.
42
+ */
43
+ onActiveChange?: (index: number) => void;
44
+ };
28
45
  declare const SnapRail: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & VariantProps<(props?: ({
29
- itemWidth?: "sm" | "lg" | "md" | null | undefined;
46
+ itemWidth?: "sm" | "lg" | "full" | "md" | null | undefined;
30
47
  gap?: "default" | "sm" | null | undefined;
31
48
  bleed?: "none" | "page" | "card" | null | undefined;
32
- } & class_variance_authority_types.ClassProp) | undefined) => string> & React.RefAttributes<HTMLDivElement>>;
49
+ } & class_variance_authority_types.ClassProp) | undefined) => string> & {
50
+ /**
51
+ * Page dots under the rail, one per child, the current one filled. For
52
+ * `itemWidth="full"`, where no next card peeks in to say there is more.
53
+ * Decorative: the rail itself is the control, and every card is reachable
54
+ * by scrolling, so the dots are `aria-hidden`.
55
+ */
56
+ dots?: boolean;
57
+ /** Classes for the dots row, e.g. `lg:hidden` where the rail becomes a grid. */
58
+ dotsClassName?: string;
59
+ /**
60
+ * Reports the current page whenever it changes — for a caller that wants
61
+ * to react to the swipe beyond the dots, e.g. a backdrop that follows the
62
+ * active card. Tracking runs whenever this or `dots` is set.
63
+ */
64
+ onActiveChange?: (index: number) => void;
65
+ } & React.RefAttributes<HTMLDivElement>>;
66
+ /**
67
+ * The page dots on their own, for a caller that tracks the rail through
68
+ * `onActiveChange` and wants the dots somewhere other than directly under it —
69
+ * inside a foot band, say. Decorative, as on the rail: the rail is the control.
70
+ */
71
+ declare function SnapRailDots({ count, active, className, }: {
72
+ count: number;
73
+ active: number;
74
+ className?: string;
75
+ }): react_jsx_runtime.JSX.Element;
33
76
 
34
- export { SnapRail, type SnapRailProps };
77
+ export { SnapRail, SnapRailDots, type SnapRailProps };
@@ -1,51 +1,3 @@
1
- import { cn } from '../chunk-FEK5XGZW.js';
2
- import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
3
- import * as React from 'react';
4
- import { cva } from 'class-variance-authority';
5
- import { jsx } from 'react/jsx-runtime';
6
-
7
- var snapRailVariants = cva(
8
- cn(
9
- "flex snap-x snap-mandatory overflow-x-auto pb-0.5 scrollbar-hide",
10
- "[&>*]:shrink-0 [&>*]:snap-start"
11
- ),
12
- {
13
- variants: {
14
- itemWidth: {
15
- sm: "[&>*]:w-[46%]",
16
- md: "[&>*]:w-[60%]",
17
- lg: "[&>*]:w-[80%]"
18
- },
19
- gap: {
20
- sm: "gap-2",
21
- default: "gap-3"
22
- },
23
- bleed: {
24
- none: "",
25
- card: "-mx-3.5 px-3.5 scroll-px-3.5",
26
- page: "-mx-4 px-4 scroll-px-4"
27
- }
28
- },
29
- defaultVariants: {
30
- itemWidth: "sm",
31
- gap: "default",
32
- bleed: "none"
33
- }
34
- }
35
- );
36
- var SnapRail = React.forwardRef(
37
- (_a, ref) => {
38
- var _b = _a, { className, itemWidth, gap, bleed } = _b, props = __objRest(_b, ["className", "itemWidth", "gap", "bleed"]);
39
- return /* @__PURE__ */ jsx(
40
- "div",
41
- __spreadValues({
42
- ref,
43
- "data-slot": "snap-rail",
44
- className: cn(snapRailVariants({ itemWidth, gap, bleed }), className)
45
- }, props)
46
- );
47
- }
48
- );
49
- SnapRail.displayName = "SnapRail";
50
-
51
- export { SnapRail };
1
+ export { SnapRail, SnapRailDots } from '../chunk-DTXNDLSE.js';
2
+ import '../chunk-FEK5XGZW.js';
3
+ import '../chunk-3GWWZKX7.js';
@@ -0,0 +1,47 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as class_variance_authority_types from 'class-variance-authority/types';
3
+ import { VariantProps } from 'class-variance-authority';
4
+
5
+ /**
6
+ * StatBanner — one claim about the catalogue, carried by a single number.
7
+ *
8
+ * These sit between the modules that list things and give the page somewhere to
9
+ * state what it knows rather than only showing it. Two side by side is the
10
+ * usual arrangement, which is a caller's grid rather than a `StatBannerPair`
11
+ * component — pairing is layout, and a consumer wanting one, or three, or a
12
+ * different order should not have to fight a wrapper for it.
13
+ *
14
+ * `scale` draws the distribution the figure sits in — low, the figure, high.
15
+ * Pass it only when all three are real numbers from the same measurement; a
16
+ * scale invented around a figure is worse than no scale, because it implies a
17
+ * spread nobody counted.
18
+ *
19
+ * Server-safe.
20
+ */
21
+ declare const bannerVariants: (props?: ({
22
+ tone?: "dark" | "warm" | null | undefined;
23
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
24
+ type StatBannerProps = VariantProps<typeof bannerVariants> & {
25
+ /** Small caps kicker, e.g. "THE REVIEW CENSUS". */
26
+ kicker?: string;
27
+ /**
28
+ * The headline claim. On the dark tone this is the whole point; on the warm
29
+ * one it usually sits under `figure`.
30
+ */
31
+ headline?: string;
32
+ body?: string;
33
+ /** The number itself, pre-formatted, e.g. "100". */
34
+ figure?: string;
35
+ /** Unit set small beside the figure, e.g. "%" or "lei". */
36
+ figureUnit?: string;
37
+ /** Oversized watermark numeral behind the content. */
38
+ watermark?: string;
39
+ /** Low, middle and high of the distribution. All three, or none. */
40
+ scale?: [string, string, string];
41
+ /** The action — pass a rendered link or button. */
42
+ action?: React.ReactNode;
43
+ className?: string;
44
+ };
45
+ declare function StatBanner({ tone, kicker, headline, body, figure, figureUnit, watermark, scale, action, className, }: StatBannerProps): react_jsx_runtime.JSX.Element;
46
+
47
+ export { StatBanner, type StatBannerProps };