@bearmenu/ui 0.8.9 → 0.8.11

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 (225) hide show
  1. package/dist/chunk-24RFI4RQ.js +167 -0
  2. package/dist/{chunk-UKBNQO6Q.js → chunk-2CXU5WZO.js} +1 -1
  3. package/dist/chunk-2XCZJWTV.js +121 -0
  4. package/dist/{chunk-62ES6N32.js → chunk-43RC7MHY.js} +1 -1
  5. package/dist/chunk-5RWTOT5Y.js +72 -0
  6. package/dist/{chunk-Q6QH52LJ.js → chunk-6TEEY5YA.js} +2 -2
  7. package/dist/{chunk-AXV5O2IZ.js → chunk-AKQ57NXY.js} +3 -3
  8. package/dist/chunk-CLLY6XB3.js +41 -0
  9. package/dist/chunk-DTXNDLSE.js +125 -0
  10. package/dist/chunk-F6FMZJDG.js +113 -0
  11. package/dist/{chunk-2WDJR6K7.js → chunk-G7IFL4Z4.js} +4 -1
  12. package/dist/chunk-H3ZZDX5L.js +61 -0
  13. package/dist/{chunk-H3BV4VAG.js → chunk-JS3EINZD.js} +2 -2
  14. package/dist/chunk-MZL7CGCL.js +109 -0
  15. package/dist/{chunk-TH6W2PWG.js → chunk-UDTG3RSE.js} +1 -1
  16. package/dist/chunk-WCTHZKU7.js +37 -0
  17. package/dist/{chunk-TT3WFS6S.js → chunk-YOKHBAIH.js} +11 -11
  18. package/dist/components/alert-dialog.js +1 -1
  19. package/dist/components/alert.d.ts +2 -2
  20. package/dist/components/avatar.d.ts +3 -3
  21. package/dist/components/badge.d.ts +1 -1
  22. package/dist/components/badge.js +1 -1
  23. package/dist/components/button.d.ts +2 -2
  24. package/dist/components/button.js +1 -1
  25. package/dist/components/calendar.js +1 -1
  26. package/dist/components/card.d.ts +4 -4
  27. package/dist/components/carousel.js +1 -1
  28. package/dist/components/combobox.js +1 -1
  29. package/dist/components/command.d.ts +2 -2
  30. package/dist/components/concept-compare-rail.d.ts +50 -0
  31. package/dist/components/concept-compare-rail.js +5 -0
  32. package/dist/components/concept-compare.d.ts +75 -38
  33. package/dist/components/concept-compare.js +209 -133
  34. package/dist/components/concept-convergence.d.ts +41 -0
  35. package/dist/components/concept-convergence.js +53 -0
  36. package/dist/components/convergence.d.ts +25 -0
  37. package/dist/components/convergence.js +4 -0
  38. package/dist/components/dialog.d.ts +2 -2
  39. package/dist/components/empty-state.js +1 -1
  40. package/dist/components/event-card.js +1 -1
  41. package/dist/components/event-compact-row.js +1 -1
  42. package/dist/components/event-detail-panel.js +2 -2
  43. package/dist/components/event-index-row.js +1 -1
  44. package/dist/components/event-list-row-wide.js +2 -2
  45. package/dist/components/event-list-row.js +2 -2
  46. package/dist/components/explainer-steps.d.ts +34 -0
  47. package/dist/components/explainer-steps.js +36 -0
  48. package/dist/components/filter-category-row.js +1 -1
  49. package/dist/components/glass-ground.d.ts +61 -0
  50. package/dist/components/glass-ground.js +3 -0
  51. package/dist/components/haptic-button.js +1 -1
  52. package/dist/components/hub-surface.js +11 -1
  53. package/dist/components/hue-chip.d.ts +70 -0
  54. package/dist/components/hue-chip.js +3 -0
  55. package/dist/components/input-group.d.ts +2 -2
  56. package/dist/components/input.d.ts +1 -1
  57. package/dist/components/item.d.ts +4 -4
  58. package/dist/components/kbd.d.ts +2 -2
  59. package/dist/components/kitchen-dossier.d.ts +88 -0
  60. package/dist/components/kitchen-dossier.js +186 -0
  61. package/dist/components/link-button.js +1 -1
  62. package/dist/components/menu-dead-end.d.ts +56 -0
  63. package/dist/components/menu-dead-end.js +49 -0
  64. package/dist/components/menu-family-block.d.ts +98 -0
  65. package/dist/components/menu-family-block.js +153 -0
  66. package/dist/components/menu-family-card.d.ts +33 -27
  67. package/dist/components/menu-family-card.js +41 -85
  68. package/dist/components/menu-field.js +92 -2
  69. package/dist/components/menu-filter-chips.d.ts +86 -0
  70. package/dist/components/menu-filter-chips.js +122 -0
  71. package/dist/components/menu-group-rows.d.ts +53 -0
  72. package/dist/components/menu-group-rows.js +67 -0
  73. package/dist/components/menu-hub-hero.js +10 -5
  74. package/dist/components/menu-index-header.d.ts +37 -0
  75. package/dist/components/menu-index-header.js +68 -0
  76. package/dist/components/menu-index-list.d.ts +48 -0
  77. package/dist/components/menu-index-list.js +96 -0
  78. package/dist/components/menu-intent-hero.d.ts +69 -0
  79. package/dist/components/menu-intent-hero.js +87 -0
  80. package/dist/components/menu-item.js +3 -3
  81. package/dist/components/menu-kitchen-list.d.ts +82 -0
  82. package/dist/components/menu-kitchen-list.js +5 -0
  83. package/dist/components/menu-mocks.d.ts +37 -2
  84. package/dist/components/menu-mocks.js +152 -27
  85. package/dist/components/menu-types.d.ts +182 -6
  86. package/dist/components/motion-icon-controls.js +2 -2
  87. package/dist/components/motion-icon-set.js +6 -6
  88. package/dist/components/motion-icon.d.ts +22 -1
  89. package/dist/components/motion-icon.js +1 -1
  90. package/dist/components/multi-select-combobox.js +2 -2
  91. package/dist/components/native-select.d.ts +2 -2
  92. package/dist/components/pagination.js +1 -1
  93. package/dist/components/photo-ground.d.ts +64 -0
  94. package/dist/components/photo-ground.js +3 -0
  95. package/dist/components/place-about-tab.js +2 -2
  96. package/dist/components/place-details-mobile.js +3 -3
  97. package/dist/components/place-types.d.ts +2 -2
  98. package/dist/components/qa-block.d.ts +36 -0
  99. package/dist/components/qa-block.js +24 -0
  100. package/dist/components/scroll-fade.js +3 -121
  101. package/dist/components/searchable-select.js +1 -1
  102. package/dist/components/select.d.ts +1 -1
  103. package/dist/components/signature-chip.d.ts +2 -2
  104. package/dist/components/signature-chip.js +2 -2
  105. package/dist/components/sliding-panels.js +1 -1
  106. package/dist/components/snap-rail.d.ts +26 -3
  107. package/dist/components/snap-rail.js +3 -109
  108. package/dist/components/spinner.d.ts +4 -4
  109. package/dist/components/story.d.ts +34 -0
  110. package/dist/components/story.js +3 -0
  111. package/dist/components/tag.d.ts +4 -4
  112. package/dist/components/text.d.ts +5 -5
  113. package/dist/components/toggle.d.ts +1 -1
  114. package/dist/components/top-comparison.d.ts +28 -0
  115. package/dist/components/top-comparison.js +76 -0
  116. package/dist/components/top-cross-link.d.ts +34 -0
  117. package/dist/components/top-cross-link.js +101 -0
  118. package/dist/components/top-ranking-entry.d.ts +53 -0
  119. package/dist/components/top-ranking-entry.js +217 -0
  120. package/dist/components/top-ranking-hero.d.ts +61 -0
  121. package/dist/components/top-ranking-hero.js +99 -0
  122. package/dist/components/top-ranking-legend.d.ts +69 -0
  123. package/dist/components/top-ranking-legend.js +124 -0
  124. package/dist/components/top-types.d.ts +109 -0
  125. package/dist/components/top-types.js +1 -0
  126. package/dist/components/venue-grade-dimensions.d.ts +3 -1
  127. package/dist/components/venue-grade-dimensions.js +1 -1
  128. package/dist/components/venue-quotes.d.ts +1 -1
  129. package/dist/components/venue-quotes.js +1 -1
  130. package/dist/components/venue-wall.js +5 -3
  131. package/dist/components/weekday-theme-banner.js +1 -1
  132. package/dist/components/weekend-panel.js +2 -2
  133. package/package.json +1 -1
  134. package/src/components/badge.tsx +1 -1
  135. package/src/components/button.tsx +2 -2
  136. package/src/components/concept-compare-rail.tsx +132 -0
  137. package/src/components/concept-compare.stories.tsx +122 -54
  138. package/src/components/concept-compare.tsx +368 -196
  139. package/src/components/concept-convergence.stories.tsx +53 -0
  140. package/src/components/concept-convergence.tsx +90 -0
  141. package/src/components/convergence.stories.tsx +54 -0
  142. package/src/components/convergence.tsx +177 -0
  143. package/src/components/explainer-steps.stories.tsx +46 -0
  144. package/src/components/explainer-steps.tsx +74 -0
  145. package/src/components/glass-ground.tsx +104 -0
  146. package/src/components/hub-surface.tsx +11 -1
  147. package/src/components/hue-chip.stories.tsx +76 -0
  148. package/src/components/hue-chip.test.tsx +62 -0
  149. package/src/components/hue-chip.tsx +99 -0
  150. package/src/components/kitchen-dossier.stories.tsx +108 -0
  151. package/src/components/kitchen-dossier.tsx +321 -0
  152. package/src/components/menu-dead-end.stories.tsx +67 -0
  153. package/src/components/menu-dead-end.tsx +127 -0
  154. package/src/components/menu-family-block.stories.tsx +91 -0
  155. package/src/components/menu-family-block.tsx +303 -0
  156. package/src/components/menu-family-card.stories.tsx +43 -35
  157. package/src/components/menu-family-card.tsx +115 -142
  158. package/src/components/menu-filter-chips.stories.tsx +107 -0
  159. package/src/components/menu-filter-chips.tsx +238 -0
  160. package/src/components/menu-group-rows.stories.tsx +54 -0
  161. package/src/components/menu-group-rows.tsx +133 -0
  162. package/src/components/menu-hub-hero.test.tsx +39 -0
  163. package/src/components/menu-hub-hero.tsx +17 -5
  164. package/src/components/menu-index-header.stories.tsx +72 -0
  165. package/src/components/menu-index-header.tsx +125 -0
  166. package/src/components/menu-index-list.stories.tsx +50 -0
  167. package/src/components/menu-index-list.tsx +149 -0
  168. package/src/components/menu-intent-hero.stories.tsx +67 -0
  169. package/src/components/menu-intent-hero.tsx +189 -0
  170. package/src/components/menu-kitchen-list.stories.tsx +67 -0
  171. package/src/components/menu-kitchen-list.test.tsx +78 -0
  172. package/src/components/menu-kitchen-list.tsx +284 -0
  173. package/src/components/menu-mocks.ts +198 -23
  174. package/src/components/menu-types.ts +189 -6
  175. package/src/components/motion-icon-controls.tsx +11 -11
  176. package/src/components/motion-icon-set.tsx +6 -5
  177. package/src/components/motion-icon.test.tsx +23 -1
  178. package/src/components/motion-icon.tsx +20 -0
  179. package/src/components/photo-ground.tsx +147 -0
  180. package/src/components/place-types.ts +2 -2
  181. package/src/components/qa-block.stories.tsx +43 -0
  182. package/src/components/qa-block.tsx +60 -0
  183. package/src/components/signature-chip.tsx +3 -3
  184. package/src/components/snap-rail.tsx +58 -15
  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.tsx +2 -2
  199. package/src/components/venue-quotes.stories.tsx +1 -1
  200. package/src/components/venue-quotes.tsx +4 -2
  201. package/src/components/venue-wall.tsx +9 -4
  202. package/src/components/weekday-theme-banner.tsx +1 -1
  203. package/dist/chunk-THOVPZNN.js +0 -37
  204. package/dist/chunk-YS6BHKZO.js +0 -92
  205. package/dist/components/ranked-venue-list.d.ts +0 -49
  206. package/dist/components/ranked-venue-list.js +0 -87
  207. package/dist/components/signature-line-list.d.ts +0 -45
  208. package/dist/components/signature-line-list.js +0 -99
  209. package/dist/components/venue-busyness-strip.d.ts +0 -35
  210. package/dist/components/venue-busyness-strip.js +0 -37
  211. package/dist/components/venue-signature-block.d.ts +0 -39
  212. package/dist/components/venue-signature-block.js +0 -6
  213. package/dist/components/venue-spotlight.d.ts +0 -74
  214. package/dist/components/venue-spotlight.js +0 -138
  215. package/src/components/ranked-venue-list.stories.tsx +0 -80
  216. package/src/components/ranked-venue-list.tsx +0 -177
  217. package/src/components/signature-line-list.stories.tsx +0 -85
  218. package/src/components/signature-line-list.tsx +0 -136
  219. package/src/components/venue-busyness-strip.stories.tsx +0 -66
  220. package/src/components/venue-busyness-strip.tsx +0 -64
  221. package/src/components/venue-signature-block.stories.tsx +0 -68
  222. package/src/components/venue-signature-block.tsx +0 -71
  223. package/src/components/venue-spotlight.stories.tsx +0 -141
  224. package/src/components/venue-spotlight.tsx +0 -236
  225. package/dist/{chunk-XWMRABZW.js → chunk-HSIYYA2E.js} +1 -1
@@ -0,0 +1,50 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+
4
+ /**
5
+ * ConceptCompareRail — the rooms as a rail, the card's backdrop following the
6
+ * active room, and the foot band that carries the page dots.
7
+ *
8
+ * On the phone the card IS the current room's photograph: the head, the rail
9
+ * and the foot all sit on it, and it cross-fades to the next room as the
10
+ * reader swipes. That needs the rail's active index, which is state — so this
11
+ * is the one client boundary in `ConceptCompare`. It takes only what can cross
12
+ * that boundary: photograph URLs, initials, and the pre-rendered rooms and
13
+ * foot as children. `labels`, `formatPrice` and the rest stay server-side.
14
+ *
15
+ * ## Why the backdrop lives here and not in each slide
16
+ *
17
+ * A slide carrying its own photograph is a boxed card sliding over a dark
18
+ * ground; the backdrop changing under a transparent slide is the reader
19
+ * turning to look at the next room. The second is the smoother thing, and it
20
+ * is also cheaper to look at — one photograph at a time instead of the edge of
21
+ * the next one peeking in.
22
+ *
23
+ * ## Why the foot is here too
24
+ *
25
+ * The dots need the rail's state, and on the phone they belong INSIDE the foot
26
+ * band's glass — under the rail they sat on a strip of bare photograph between
27
+ * the room's scrim and the foot's. So the foot renders here, with the dots as
28
+ * its first row below `lg`, and `ConceptCompare` hands it the foot's content.
29
+ *
30
+ * Desktop ignores the backdrop and the dots (`lg:hidden`); each room carries
31
+ * its own photograph there, side by side, and the foot is an absolute glass
32
+ * band over them.
33
+ */
34
+ type ConceptCompareBackdrop = {
35
+ /** The room's photograph. Absent: the ground with the venue's initial. */
36
+ src?: string;
37
+ /** The venue's first letter, for the no-photograph fallback. */
38
+ initial: string;
39
+ };
40
+ type ConceptCompareRailProps = {
41
+ backdrops: ConceptCompareBackdrop[];
42
+ /** Classes for the rail itself — the desktop grid lives here. */
43
+ railClassName?: string;
44
+ /** The foot's content: the note and the action. Omit for no foot. */
45
+ foot?: React.ReactNode;
46
+ children: React.ReactNode;
47
+ };
48
+ declare function ConceptCompareRail({ backdrops, railClassName, foot, children, }: ConceptCompareRailProps): react_jsx_runtime.JSX.Element;
49
+
50
+ export { type ConceptCompareBackdrop, ConceptCompareRail, type ConceptCompareRailProps };
@@ -0,0 +1,5 @@
1
+ export { ConceptCompareRail } from '../chunk-H3ZZDX5L.js';
2
+ import '../chunk-DTXNDLSE.js';
3
+ import '../chunk-5RWTOT5Y.js';
4
+ import '../chunk-FEK5XGZW.js';
5
+ import '../chunk-3GWWZKX7.js';
@@ -1,73 +1,110 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { MenuItemLabels } from './menu-item.js';
3
2
  import { MenuConceptPreview, MenuLinkComponent, MenuLinkProps } from './menu-types.js';
4
3
  import 'react';
5
4
  import './place-types.js';
6
5
 
7
6
  /**
8
- * ConceptCompare — one dish or drink across every kitchen that makes it, under
9
- * whatever name each of them uses.
7
+ * ConceptCompare — one dish or drink across the kitchens that make it, under
8
+ * whatever name each of them uses. No surfaces at all.
10
9
  *
11
10
  * The keystone module: a single menu can list papanași, only a catalogue can
12
- * say that seventy kitchens make them under fifty different names between 8 and
13
- * 44 lei. The alias column is what makes it honest — these are not the same row
14
- * seventy times, they are seventy differently-named rows we matched, and
15
- * showing each kitchen's own wording is the evidence for that.
11
+ * say that forty-five kitchens make them under eight names between 29 and 52
12
+ * lei. Each kitchen's own wording is the evidence that these are matched rows
13
+ * rather than one row repeated.
16
14
  *
17
- * ## The row is place-led
15
+ * ## The card IS the rooms
18
16
  *
19
- * Each row leads with the VENUE PHOTOGRAPH, which is real and licensed. It
20
- * replaced a price bar, and the trade is not close: the bar measured the one
21
- * value already printed beside it in words, while the thing a reader is
22
- * actually choosing between the restaurant had no image at all. Five
23
- * restaurants that disagree about a name is the story; five bars of similar
24
- * length is not.
17
+ * Every panel is gone. Each room is a VENUE photograph real and licensed
18
+ * where an item's would be generated with the kitchen's line floating over
19
+ * it, and the three readable things sit on glass: the identity in a band
20
+ * across the top, each kitchen's line over its own photograph, the foot along
21
+ * the bottom.
25
22
  *
26
- * ## Two layouts, one component
23
+ * ## Read across on desktop, one at a time on the phone
27
24
  *
28
- * From `lg` the row is a table: rank, venue, alias, mentions, price. Below it,
29
- * the rows become the production `<MenuItem>` the alias as the name, the
30
- * venue underneath because a five-column table does not survive 390px and
31
- * the item row already solves this exact shape everywhere else in the app.
25
+ * From `lg` the rooms stand side by side four kitchens, each with its own
26
+ * name for the dish and its own price, so comparing is a horizontal glance
27
+ * and the head and foot are ABSOLUTE glass bands over them, so the photographs
28
+ * run the full height of the card beneath both. The head's glass fades out
29
+ * downward on the same curve as its mask; the foot's fades out upward the same
30
+ * way. It was the ink stopping short of the mask that drew a line where a band
31
+ * ended.
32
+ *
33
+ * Below `lg` four rooms in a 2×2 was too much happening in one card, so the
34
+ * rooms become a `SnapRail`: one room per swipe, page dots under it, the head
35
+ * and foot static on the card's ground above and below. The dots are the
36
+ * rail's own — the same object the hub's other rails use.
37
+ *
38
+ * ## The dark overlay, and the hover that lifts it
39
+ *
40
+ * Four busy interiors are four competing subjects, and type over them had
41
+ * nothing to sit on but its own local scrim — the eye could not settle. Every
42
+ * photograph carries a uniform dark overlay so the words lead and the picture
43
+ * supports; hovering a room lifts the overlay off THAT room only, so the reader
44
+ * can look at the place they are about to open.
45
+ *
46
+ * ## Light and dark
47
+ *
48
+ * There is nothing in it to theme. Photographs and their scrims are identical
49
+ * in both, because text over an image needs the same treatment either way —
50
+ * the content is `.dark`-scoped for exactly that. What adapts is the card's
51
+ * EDGE: a soft shadow and hairline on light, a deeper shadow and a light
52
+ * hairline on dark. The edge lives on the outer wrapper, outside the scope.
53
+ *
54
+ * ## No room here is a room that does not serve it
55
+ *
56
+ * The earlier card led with an AI-generated picture of the dish, and a
57
+ * generated image at the head of a block whose whole argument is "we counted
58
+ * real menus" undercut the argument. The rooms are real.
32
59
  */
33
60
  /** @deprecated Alias of `MenuLinkProps`; kept so existing imports keep working. */
34
61
  type ConceptCompareLinkProps = MenuLinkProps;
35
62
  type ConceptCompareFigure = {
36
- /** Pre-formatted, e.g. "44". */
63
+ /** Pre-formatted, e.g. "44" or "29–52". */
37
64
  value: string;
38
65
  label: string;
66
+ /** Draws the value in amber — the spread, which is the number the card is about. */
67
+ accent?: boolean;
39
68
  };
40
69
  type ConceptCompareLabels = {
41
70
  /** Small caps kicker, e.g. "DISH CONCEPT". */
42
71
  kind: string;
43
- /** Column heading over the aliases, e.g. "ON THEIR MENU AS". */
44
- alias: string;
45
- /** Under each price, e.g. "per portion". */
46
- perPortion?: string;
47
- /** Badge on the lowest-priced row, e.g. "cheapest shown". */
48
- cheapest?: string;
72
+ /** The badge on the lowest-priced room, e.g. "CHEAPEST". */
73
+ cheapest: string;
74
+ /** The badge on every other room, e.g. "#2". Defaults to `#${rank}`. */
75
+ rank?: (rank: number) => string;
76
+ /** Beside each price, e.g. "12 mentions". Pluralised by the caller. */
77
+ mentions: (count: number) => string;
78
+ /** Accessible name for a room's link, e.g. "Papanași at Casa Maramureșeană". */
79
+ openRoom: (alias: string, venue: string) => string;
49
80
  };
50
81
  type ConceptCompareProps = {
51
82
  concept: MenuConceptPreview;
52
83
  labels: ConceptCompareLabels;
53
- /** Passed to the mobile `<MenuItem>` rows. */
54
- itemLabels: MenuItemLabels;
84
+ /** One line under the title, e.g. "45 kitchens make it, and they do not agree on the name". */
85
+ lede?: string;
55
86
  formatPrice: (amount: number) => string;
56
- formatCount?: (value: number) => string;
57
- /** CSS gradient for the header swatch, when there is no photograph. */
58
- gradient: string;
59
- /** A real photograph of the concept, when the matched menu row carries one. */
60
- imageUrl?: string;
61
87
  figures?: ConceptCompareFigure[];
62
- /** Destination per row, keyed by place slug. */
88
+ /** Destination per room, keyed by place slug. A room without one is inert. */
63
89
  hrefs?: Record<string, string>;
64
- /** The provenance note in the footer. */
90
+ /** The provenance note in the foot. */
65
91
  footnote?: string;
66
- /** Actions in the footer — pass rendered links or buttons. */
92
+ /** The action in the foot — pass a rendered link or button. */
67
93
  actions?: React.ReactNode;
68
94
  linkComponent?: MenuLinkComponent;
69
95
  className?: string;
70
96
  };
71
- declare function ConceptCompare({ concept, labels, itemLabels, formatPrice, formatCount, gradient, imageUrl, figures, hrefs, footnote, actions, linkComponent: LinkComponent, className, }: ConceptCompareProps): react_jsx_runtime.JSX.Element;
97
+ declare function ConceptCompare({ concept, labels, lede, formatPrice, figures, hrefs, footnote, actions, linkComponent: LinkComponent, className, }: ConceptCompareProps): react_jsx_runtime.JSX.Element | null;
98
+ /**
99
+ * The card's own loading state, at the card's footprint.
100
+ *
101
+ * The ground is the card's own dark surface, so the placeholder is already
102
+ * what the photographs will land on and nothing flashes from paper to ink.
103
+ * The phone shape is one room tall with the head above and the foot below;
104
+ * from `lg` it is the four-room row with the head and foot laid over it.
105
+ */
106
+ declare function ConceptCompareSkeleton({ className }: {
107
+ className?: string;
108
+ }): react_jsx_runtime.JSX.Element;
72
109
 
73
- export { ConceptCompare, type ConceptCompareFigure, type ConceptCompareLabels, type ConceptCompareLinkProps, type ConceptCompareProps };
110
+ export { ConceptCompare, type ConceptCompareFigure, type ConceptCompareLabels, type ConceptCompareLinkProps, type ConceptCompareProps, ConceptCompareSkeleton };
@@ -1,24 +1,38 @@
1
- import { MenuItem } from '../chunk-TH6W2PWG.js';
2
- import '../chunk-Q6QH52LJ.js';
3
- import { MenuField } from '../chunk-YS6BHKZO.js';
4
- import '../chunk-UKBNQO6Q.js';
1
+ import { Separator } from '../chunk-WSRWFA6K.js';
2
+ import { ConceptCompareRail } from '../chunk-H3ZZDX5L.js';
3
+ import '../chunk-DTXNDLSE.js';
4
+ import { PhotoGround, PHOTO_GROUND } from '../chunk-5RWTOT5Y.js';
5
+ import { Skeleton } from '../chunk-QXHMPJ35.js';
5
6
  import { cn } from '../chunk-FEK5XGZW.js';
6
7
  import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
7
- import { Star, MessageSquare } from 'lucide-react';
8
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
+ import { ArrowDown, MapPin, Star } from 'lucide-react';
9
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
10
 
10
11
  function DefaultLink(_a) {
11
12
  var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
12
13
  return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
13
14
  }
15
+ var MAX_ROOMS = 4;
16
+ var initialOf = (name) => {
17
+ var _a, _b;
18
+ return ((_b = (_a = name.match(new RegExp("\\p{L}", "u"))) == null ? void 0 : _a[0]) != null ? _b : "").toLocaleUpperCase();
19
+ };
20
+ var GROUND = PHOTO_GROUND;
21
+ var PHOTO_OVERLAY_HOVER = "transition-opacity duration-300 group-hover/room:opacity-0 motion-reduce:transition-none";
22
+ var ROOM_SCRIM = "absolute inset-0 bg-[linear-gradient(to_bottom,oklch(0.16_0.012_55_/_0)_0%,oklch(0.16_0.012_55_/_0)_30%,oklch(0.16_0.012_55_/_0.55)_58%,oklch(0.16_0.012_55_/_0.9)_100%)]";
23
+ var HEAD_GLASS = "before:pointer-events-none before:absolute before:inset-0 before:-z-10 before:content-[''] before:bg-[linear-gradient(to_bottom,oklch(0.16_0.012_55_/_0.86)_0%,oklch(0.16_0.012_55_/_0.7)_35%,oklch(0.16_0.012_55_/_0.28)_75%,oklch(0.16_0.012_55_/_0)_100%)]";
24
+ var COLUMNS = {
25
+ 1: "lg:grid-cols-1",
26
+ 2: "lg:grid-cols-2",
27
+ 3: "lg:grid-cols-3",
28
+ 4: "lg:grid-cols-4"
29
+ };
30
+ var DESKTOP_FOOT_CLEARANCE = "lg:pb-[104px]";
14
31
  function ConceptCompare({
15
32
  concept,
16
33
  labels,
17
- itemLabels,
34
+ lede,
18
35
  formatPrice,
19
- formatCount,
20
- gradient,
21
- imageUrl,
22
36
  figures,
23
37
  hrefs,
24
38
  footnote,
@@ -26,137 +40,199 @@ function ConceptCompare({
26
40
  linkComponent: LinkComponent = DefaultLink,
27
41
  className
28
42
  }) {
29
- var _a;
30
- const rows = (_a = concept.rows) != null ? _a : [];
31
- const cheapest = rows.reduce(
32
- (lowest, row) => lowest === void 0 || row.price < lowest ? row.price : lowest,
43
+ var _a, _b, _c;
44
+ const rooms = ((_a = concept.rows) != null ? _a : []).slice(0, MAX_ROOMS);
45
+ const count = rooms.length;
46
+ if (count === 0) return null;
47
+ const cheapest = rooms.reduce(
48
+ (lowest, room) => lowest === void 0 || room.price < lowest ? room.price : lowest,
33
49
  void 0
34
50
  );
35
- return /* @__PURE__ */ jsxs("div", { className: cn("overflow-hidden rounded-[18px] border border-border bg-card", className), children: [
36
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 p-4 lg:flex-row lg:items-center lg:gap-6 lg:p-5", children: [
37
- imageUrl ? (
38
- // eslint-disable-next-line @next/next/no-img-element
51
+ const rankOf = (_b = labels.rank) != null ? _b : ((rank) => `#${rank}`);
52
+ const hasFoot = Boolean(footnote || actions);
53
+ return /* @__PURE__ */ jsx(
54
+ "div",
55
+ {
56
+ className: cn(
57
+ /* The edge, OUTSIDE the dark scope — the one thing about this card
58
+ that belongs to the page it sits on. */
59
+ "overflow-hidden rounded-[18px] border border-border shadow-[var(--shadow-card)]",
60
+ className
61
+ ),
62
+ children: /* @__PURE__ */ jsxs("div", { className: cn("dark relative isolate flex flex-col text-foreground", GROUND), children: [
63
+ /* @__PURE__ */ jsxs(
64
+ "div",
65
+ {
66
+ className: cn(
67
+ "relative isolate flex flex-col gap-3 px-4 pb-5 pt-4",
68
+ "lg:absolute lg:inset-x-0 lg:top-0 lg:z-10 lg:flex-row lg:items-start lg:justify-between lg:gap-6 lg:px-5 lg:pb-12 lg:pt-5",
69
+ HEAD_GLASS
70
+ ),
71
+ children: [
72
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
73
+ /* @__PURE__ */ jsx("span", { className: "block text-[10.5px] font-extrabold uppercase tracking-[0.13em] text-white/70", children: labels.kind }),
74
+ /* @__PURE__ */ jsx("h3", { className: "mt-1 font-serif text-[28px] font-semibold leading-tight tracking-[-0.02em] text-white lg:text-[32px]", children: concept.title }),
75
+ lede && /* @__PURE__ */ jsx("p", { className: "mt-1 text-[13px] leading-snug text-white/75", children: lede })
76
+ ] }),
77
+ figures && figures.length > 0 && /* @__PURE__ */ jsx("dl", { className: "flex shrink-0 flex-wrap gap-x-5 gap-y-2 lg:gap-x-6", children: figures.map((figure) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start lg:items-center", children: [
78
+ /* @__PURE__ */ jsx(
79
+ "dd",
80
+ {
81
+ className: cn(
82
+ "text-[22px] font-bold leading-none tabular-nums tracking-[-0.02em]",
83
+ figure.accent ? "text-[oklch(0.82_0.15_85)]" : "text-white"
84
+ ),
85
+ children: figure.value
86
+ }
87
+ ),
88
+ /* @__PURE__ */ jsx("dt", { className: "mt-1 text-[11px] text-white/65", children: figure.label })
89
+ ] }, figure.label)) })
90
+ ]
91
+ }
92
+ ),
39
93
  /* @__PURE__ */ jsx(
40
- "img",
94
+ ConceptCompareRail,
41
95
  {
42
- src: imageUrl,
43
- alt: "",
44
- className: "aspect-[16/9] w-full shrink-0 rounded-xl object-cover lg:aspect-auto lg:h-[88px] lg:w-[88px]"
96
+ backdrops: rooms.map((room) => ({
97
+ src: room.place_thumbnail_url,
98
+ initial: initialOf(room.place_name)
99
+ })),
100
+ railClassName: cn(
101
+ "lg:grid lg:gap-px lg:overflow-visible lg:[&>*]:w-auto",
102
+ (_c = COLUMNS[count]) != null ? _c : COLUMNS[4]
103
+ ),
104
+ foot: hasFoot ? /* @__PURE__ */ jsxs(Fragment, { children: [
105
+ footnote && /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 text-[12px] leading-relaxed text-white/70", children: footnote }),
106
+ actions && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 [&>*]:w-full lg:[&>*]:w-auto", children: actions })
107
+ ] }) : void 0,
108
+ children: rooms.map((room, index) => {
109
+ const href = hrefs == null ? void 0 : hrefs[room.place_slug];
110
+ const isCheapest = room.price === cheapest;
111
+ const roomClass = cn(
112
+ /* Transparent on the phone — the card behind it is the room's
113
+ photograph — with only its scrim and its line. A photograph of
114
+ its own from `lg`, where four stand side by side. */
115
+ "group/room relative isolate flex aspect-[4/3] flex-col justify-end overflow-hidden p-4",
116
+ "lg:aspect-auto lg:min-h-[440px] lg:p-4",
117
+ DESKTOP_FOOT_CLEARANCE
118
+ );
119
+ const body = /* @__PURE__ */ jsxs(Fragment, { children: [
120
+ /* @__PURE__ */ jsxs("span", { "aria-hidden": true, className: "absolute inset-0 -z-10", children: [
121
+ /* @__PURE__ */ jsx(
122
+ PhotoGround,
123
+ {
124
+ className: "hidden lg:block",
125
+ photos: [room.place_thumbnail_url],
126
+ initials: initialOf(room.place_name),
127
+ mosaicClassName: "grid-cols-1",
128
+ overlay: true,
129
+ overlayClassName: PHOTO_OVERLAY_HOVER
130
+ }
131
+ ),
132
+ /* @__PURE__ */ jsx("span", { className: ROOM_SCRIM })
133
+ ] }),
134
+ /* @__PURE__ */ jsxs(
135
+ "span",
136
+ {
137
+ className: cn(
138
+ "inline-flex h-[22px] w-max items-center gap-1 rounded-full px-2 text-[10px] font-extrabold uppercase tracking-[0.08em]",
139
+ isCheapest ? "bg-success text-white" : "bg-white/20 text-white/85"
140
+ ),
141
+ children: [
142
+ isCheapest && /* @__PURE__ */ jsx(ArrowDown, { className: "h-3 w-3 shrink-0", "aria-hidden": true }),
143
+ isCheapest ? labels.cheapest : rankOf(index + 1)
144
+ ]
145
+ }
146
+ ),
147
+ /* @__PURE__ */ jsxs("span", { className: "mt-2.5 flex items-center gap-1.5 text-white", children: [
148
+ /* @__PURE__ */ jsx(MapPin, { className: "h-3.5 w-3.5 shrink-0 text-white/70", "aria-hidden": true }),
149
+ /* @__PURE__ */ jsx("b", { className: "min-w-0 flex-1 truncate text-[15px] font-bold leading-tight", children: room.place_name }),
150
+ room.rating !== void 0 && /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1 text-[12px] text-white/70", children: [
151
+ /* @__PURE__ */ jsx(Star, { className: "h-3 w-3 shrink-0", "aria-hidden": true }),
152
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: room.rating })
153
+ ] })
154
+ ] }),
155
+ room.place_area && /* @__PURE__ */ jsx("span", { className: "mt-0.5 block text-[12px] text-white/70", children: room.place_area }),
156
+ /* @__PURE__ */ jsx("span", { className: "mt-2 block truncate font-serif text-[14px] text-white/90", children: room.alias }),
157
+ /* @__PURE__ */ jsx(Separator, { className: "my-2.5 via-white/20" }),
158
+ /* @__PURE__ */ jsxs("span", { className: "flex items-baseline gap-2", children: [
159
+ /* @__PURE__ */ jsx(
160
+ "b",
161
+ {
162
+ className: cn(
163
+ "text-[19px] font-bold leading-none tabular-nums tracking-[-0.02em]",
164
+ isCheapest ? "text-success" : "text-white"
165
+ ),
166
+ children: formatPrice(room.price)
167
+ }
168
+ ),
169
+ room.mentions !== void 0 && room.mentions > 0 && /* @__PURE__ */ jsx("span", { className: "text-[11.5px] text-white/65", children: labels.mentions(room.mentions) })
170
+ ] })
171
+ ] });
172
+ return href ? /* @__PURE__ */ jsx(
173
+ LinkComponent,
174
+ {
175
+ href,
176
+ "aria-label": labels.openRoom(room.alias, room.place_name),
177
+ className: cn(
178
+ roomClass,
179
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-white"
180
+ ),
181
+ children: body
182
+ },
183
+ room.place_slug
184
+ ) : /* @__PURE__ */ jsx("div", { className: roomClass, children: body }, room.place_slug);
185
+ })
45
186
  }
46
187
  )
47
- ) : /* @__PURE__ */ jsx(
48
- MenuField,
49
- {
50
- name: concept.title,
51
- gradient,
52
- seedKey: concept.slug,
53
- className: "aspect-[16/9] w-full shrink-0 rounded-xl lg:aspect-auto lg:h-[88px] lg:w-[88px]"
54
- }
188
+ ] })
189
+ }
190
+ );
191
+ }
192
+ function ConceptCompareSkeleton({ className }) {
193
+ return /* @__PURE__ */ jsx(
194
+ "div",
195
+ {
196
+ className: cn(
197
+ "overflow-hidden rounded-[18px] border border-border shadow-[var(--shadow-card)]",
198
+ className
55
199
  ),
56
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
57
- /* @__PURE__ */ jsx("span", { className: "text-[9.5px] font-bold uppercase tracking-[0.12em] text-muted-foreground", children: labels.kind }),
58
- /* @__PURE__ */ jsx("h3", { className: "mt-1 font-serif text-2xl font-semibold tracking-[-0.02em] lg:text-[30px]", children: concept.title })
59
- ] }),
60
- figures && figures.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 gap-6 lg:gap-8", children: figures.map((figure) => /* @__PURE__ */ jsxs("div", { className: "text-left lg:text-right", children: [
61
- /* @__PURE__ */ jsx("div", { className: "text-xl font-extrabold leading-none tracking-[-0.03em] tabular-nums lg:text-2xl", children: figure.value }),
62
- /* @__PURE__ */ jsx("div", { className: "mt-1 text-[10.5px] text-muted-foreground", children: figure.label })
63
- ] }, figure.label)) })
64
- ] }),
65
- /* @__PURE__ */ jsx("ul", { className: "border-t border-border lg:hidden", children: rows.map((row) => /* @__PURE__ */ jsx("li", { className: "border-b border-border last:border-b-0", children: /* @__PURE__ */ jsx(
66
- MenuItem,
67
- {
68
- item: {
69
- id: row.place_slug,
70
- slug: row.place_slug,
71
- // The kitchen's OWN wording leads the row — that IS the point
72
- // of the module.
73
- name: row.alias,
74
- kind: concept.kind,
75
- mentions: row.mentions,
76
- sizes_and_prices: [{ size: 0, price: row.price }]
77
- },
78
- labels: itemLabels,
79
- formatPrice,
80
- formatCount,
81
- venueName: row.place_name,
82
- href: hrefs == null ? void 0 : hrefs[row.place_slug],
83
- linkComponent: LinkComponent,
84
- className: cn(row.price === cheapest && "bg-accent-subtle/40")
85
- }
86
- ) }, row.place_slug)) }),
87
- /* @__PURE__ */ jsx("ol", { className: "hidden border-t border-border lg:block", children: rows.map((row, index) => {
88
- const isCheapest = row.price === cheapest;
89
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
90
- /* @__PURE__ */ jsx("span", { className: "w-5 shrink-0 text-center text-xs font-bold tabular-nums text-muted-foreground", children: index + 1 }),
91
- /* @__PURE__ */ jsxs("span", { className: "relative h-10 w-10 shrink-0 overflow-hidden rounded-lg bg-[repeating-linear-gradient(135deg,oklch(0.78_0.018_55)_0_8px,oklch(0.84_0.012_58)_8px_16px)]", children: [
92
- row.place_thumbnail_url && // eslint-disable-next-line @next/next/no-img-element
93
- /* @__PURE__ */ jsx(
94
- "img",
95
- {
96
- src: row.place_thumbnail_url,
97
- alt: "",
98
- loading: "lazy",
99
- className: "h-full w-full object-cover"
100
- }
101
- ),
102
- row.open_now && /* @__PURE__ */ jsx(
103
- "i",
104
- {
105
- "aria-hidden": true,
106
- className: "absolute right-0.5 top-0.5 h-[6px] w-[6px] rounded-full bg-[var(--free,currentColor)] ring-2 ring-white/80"
107
- }
108
- )
200
+ "aria-hidden": true,
201
+ children: /* @__PURE__ */ jsxs("div", { className: cn("dark relative flex flex-col text-foreground", GROUND), children: [
202
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 px-4 pb-5 pt-4 lg:absolute lg:inset-x-0 lg:top-0 lg:z-10 lg:flex-row lg:justify-between lg:px-5 lg:pt-5", children: [
203
+ /* @__PURE__ */ jsxs("div", { children: [
204
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-[90px] bg-white/15" }),
205
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-8 w-[160px] bg-white/15" }),
206
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3.5 w-[240px] bg-white/15" })
207
+ ] }),
208
+ /* @__PURE__ */ jsx("div", { className: "flex gap-5", children: Array.from({ length: 4 }, (_, index) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-1.5 lg:items-center", children: [
209
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-8 bg-white/15" }),
210
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-12 bg-white/15" })
211
+ ] }, index)) })
109
212
  ] }),
110
- /* @__PURE__ */ jsxs("span", { className: "min-w-0 w-[200px] shrink-0", children: [
111
- /* @__PURE__ */ jsx("span", { className: "block truncate text-sm font-bold tracking-[-0.01em]", children: row.place_name }),
112
- /* @__PURE__ */ jsxs("span", { className: "mt-px flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
113
- row.rating != null && /* @__PURE__ */ jsxs(Fragment, { children: [
114
- /* @__PURE__ */ jsx(Star, { className: "h-2.5 w-2.5", "aria-hidden": true }),
115
- /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: row.rating })
116
- ] }),
117
- row.place_area && /* @__PURE__ */ jsx("span", { className: "truncate", children: row.place_area })
118
- ] })
119
- ] }),
120
- /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
121
- /* @__PURE__ */ jsx("span", { className: "block text-[9.5px] font-bold uppercase tracking-[0.1em] text-muted-foreground", children: labels.alias }),
122
- /* @__PURE__ */ jsx("span", { className: "block truncate font-serif text-[13px] italic", children: row.alias })
123
- ] }),
124
- row.mentions != null && row.mentions > 0 && /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-1 text-[11px] tabular-nums text-muted-foreground", children: [
125
- /* @__PURE__ */ jsx(MessageSquare, { className: "h-[11px] w-[11px]", "aria-hidden": true }),
126
- row.mentions
127
- ] }),
128
- /* @__PURE__ */ jsxs("span", { className: "w-[92px] shrink-0 text-right", children: [
129
- /* @__PURE__ */ jsx(
130
- "b",
131
- {
132
- className: cn(
133
- "block text-sm font-extrabold tabular-nums",
134
- isCheapest && "text-[var(--free,currentColor)]"
135
- ),
136
- children: formatPrice(row.price)
137
- }
138
- ),
139
- /* @__PURE__ */ jsx("span", { className: "block text-[10px] text-muted-foreground", children: isCheapest && labels.cheapest ? labels.cheapest : labels.perPortion })
213
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 lg:grid-cols-4 lg:gap-px", children: Array.from({ length: 4 }, (_, index) => /* @__PURE__ */ jsxs(
214
+ "div",
215
+ {
216
+ className: cn(
217
+ "flex aspect-[4/3] flex-col justify-end p-4 lg:aspect-auto lg:min-h-[440px] lg:pb-[104px]",
218
+ index > 0 && "hidden lg:flex"
219
+ ),
220
+ children: [
221
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[22px] w-[72px] rounded-full bg-white/15" }),
222
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-2.5 h-4 w-[60%] bg-white/15" }),
223
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3.5 w-[50%] bg-white/15" }),
224
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-4 h-5 w-[80px] bg-white/15" })
225
+ ]
226
+ },
227
+ index
228
+ )) }),
229
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 px-4 pb-4 pt-3 lg:absolute lg:inset-x-0 lg:bottom-0 lg:flex-row lg:items-center lg:gap-5 lg:px-5 lg:pb-4 lg:pt-6", children: [
230
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-full bg-white/15 lg:flex-1" }),
231
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full rounded-full bg-white/15 lg:w-[120px]" })
140
232
  ] })
141
- ] });
142
- const rowClasses = "flex items-center gap-4 px-5 py-3";
143
- return /* @__PURE__ */ jsx("li", { className: "border-b border-border last:border-b-0", children: (hrefs == null ? void 0 : hrefs[row.place_slug]) ? /* @__PURE__ */ jsx(
144
- LinkComponent,
145
- {
146
- href: hrefs[row.place_slug],
147
- className: cn(
148
- rowClasses,
149
- "transition-colors hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
150
- ),
151
- children: content
152
- }
153
- ) : /* @__PURE__ */ jsx("div", { className: rowClasses, children: content }) }, row.place_slug);
154
- }) }),
155
- (footnote || actions) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 p-4", children: [
156
- footnote && /* @__PURE__ */ jsx("span", { className: "text-[11.5px] text-muted-foreground", children: footnote }),
157
- actions && /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center gap-2", children: actions })
158
- ] })
159
- ] });
233
+ ] })
234
+ }
235
+ );
160
236
  }
161
237
 
162
- export { ConceptCompare };
238
+ export { ConceptCompare, ConceptCompareSkeleton };
@@ -0,0 +1,41 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ /**
4
+ * ConceptConvergence — many names, one dish, drawn on a dark stage.
5
+ *
6
+ * The explainer's proof: the kitchens' OWN spellings of a dish, each with its
7
+ * price, converging on the one concept they were matched into. Five visibly
8
+ * different strings under one photograph with one price column say what a
9
+ * paragraph about "matching" cannot.
10
+ *
11
+ * Drawn for the explainer's dark stage, and only there: the chips are white
12
+ * on ink, not a family's hue — the tint was doing no work once the stage
13
+ * went dark, and the spellings are the point, not the kitchens' cuisines.
14
+ * The concept card is the venue's real photograph, never the item's (which
15
+ * is generated), on the same ground as every photographed card.
16
+ */
17
+ type ConceptConvergenceAlias = {
18
+ /** The kitchen's spelling, verbatim. */
19
+ label: string;
20
+ /** Pre-formatted, e.g. "32 lei". */
21
+ price: string;
22
+ };
23
+ type ConceptConvergenceProps = {
24
+ aliases: ConceptConvergenceAlias[];
25
+ concept: {
26
+ title: string;
27
+ /** A room's photograph — venue photography only. */
28
+ photoUrl?: string;
29
+ /** "32 names" — the badge on the card. */
30
+ badge: string;
31
+ };
32
+ /**
33
+ * Low, middle and high of the ruler under the diagram, e.g.
34
+ * `["8 lei", "45 kitchens", "44 lei"]`. All three, or none.
35
+ */
36
+ scale?: [string, string, string];
37
+ className?: string;
38
+ };
39
+ declare function ConceptConvergence({ aliases, concept, scale, className }: ConceptConvergenceProps): react_jsx_runtime.JSX.Element;
40
+
41
+ export { ConceptConvergence, type ConceptConvergenceAlias, type ConceptConvergenceProps };