@bearmenu/ui 0.8.48 → 0.8.50

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 (59) hide show
  1. package/dist/{chunk-QY66ME5B.js → chunk-CZ2HC7WY.js} +24 -6
  2. package/dist/components/alert.d.ts +2 -2
  3. package/dist/components/avatar.d.ts +2 -2
  4. package/dist/components/badge.d.ts +1 -1
  5. package/dist/components/banner.d.ts +1 -1
  6. package/dist/components/button.d.ts +2 -2
  7. package/dist/components/card.d.ts +2 -2
  8. package/dist/components/command.d.ts +3 -3
  9. package/dist/components/concept-compare.d.ts +1 -1
  10. package/dist/components/doorway-tiles.d.ts +1 -1
  11. package/dist/components/empty-state.d.ts +2 -2
  12. package/dist/components/event-detail-panel.d.ts +12 -2
  13. package/dist/components/event-detail-panel.js +15 -3
  14. package/dist/components/grade-atom.d.ts +1 -1
  15. package/dist/components/item.d.ts +2 -2
  16. package/dist/components/kitchen-dossier.d.ts +1 -1
  17. package/dist/components/menu-dead-end.d.ts +1 -1
  18. package/dist/components/menu-family-block.d.ts +2 -2
  19. package/dist/components/menu-family-block.js +3 -1
  20. package/dist/components/menu-family-card.d.ts +1 -1
  21. package/dist/components/menu-filter-chips.d.ts +1 -1
  22. package/dist/components/menu-group-rows.d.ts +1 -1
  23. package/dist/components/menu-index-header.d.ts +1 -1
  24. package/dist/components/menu-index-list.d.ts +1 -1
  25. package/dist/components/menu-intent-hero.d.ts +1 -1
  26. package/dist/components/menu-item.d.ts +1 -1
  27. package/dist/components/menu-kitchen-list.d.ts +9 -2
  28. package/dist/components/menu-kitchen-list.js +3 -1
  29. package/dist/components/menu-mocks.d.ts +1 -1
  30. package/dist/components/menu-types.d.ts +1 -1
  31. package/dist/components/open-now-list.d.ts +1 -1
  32. package/dist/components/place-about-tab.d.ts +1 -1
  33. package/dist/components/place-card.d.ts +1 -1
  34. package/dist/components/place-card.js +13 -5
  35. package/dist/components/place-details-mobile.d.ts +1 -1
  36. package/dist/components/place-schedule-week.d.ts +1 -1
  37. package/dist/components/place-types.d.ts +1 -1
  38. package/dist/components/qa-block.d.ts +1 -1
  39. package/dist/components/spinner.d.ts +2 -2
  40. package/dist/components/tag.d.ts +2 -2
  41. package/dist/components/text.d.ts +3 -3
  42. package/dist/components/top-comparison.d.ts +1 -1
  43. package/dist/components/top-cross-link.d.ts +1 -1
  44. package/dist/components/top-ranking-entry.d.ts +1 -1
  45. package/dist/components/top-ranking-hero.d.ts +1 -1
  46. package/dist/components/top-types.d.ts +1 -1
  47. package/dist/components/venue-grade-dimensions.d.ts +1 -1
  48. package/dist/components/venue-quotes.d.ts +1 -1
  49. package/dist/components/venue-wall.d.ts +1 -1
  50. package/dist/{place-types-C4rR3LTs.d.ts → place-types-Dzy6FH67.d.ts} +12 -1
  51. package/package.json +217 -23
  52. package/src/components/event-detail-panel.test.tsx +35 -0
  53. package/src/components/event-detail-panel.tsx +32 -10
  54. package/src/components/menu-kitchen-list.test.tsx +39 -0
  55. package/src/components/menu-kitchen-list.tsx +36 -7
  56. package/src/components/place-card.stories.tsx +36 -0
  57. package/src/components/place-card.test.tsx +29 -0
  58. package/src/components/place-card.tsx +24 -5
  59. package/src/components/place-types.ts +11 -0
@@ -22,9 +22,9 @@ import { VariantProps } from 'class-variance-authority';
22
22
  * Weights are 400 / 600 / 700. 500 is not in the system.
23
23
  */
24
24
  declare const textVariants: (props?: ({
25
- variant?: "body" | "small" | "display" | "h2" | "h3" | "label" | "caption" | "h1" | "h4" | "body-lg" | "body-sm" | "overline" | null | undefined;
26
- color?: "default" | "inherit" | "primary" | "destructive" | "muted" | "primary-foreground" | null | undefined;
27
- weight?: "bold" | "medium" | "normal" | "semibold" | null | undefined;
25
+ variant?: "small" | "display" | "h1" | "h2" | "h3" | "h4" | "body-lg" | "body" | "body-sm" | "caption" | "label" | "overline" | null | undefined;
26
+ color?: "default" | "destructive" | "inherit" | "muted" | "primary" | "primary-foreground" | null | undefined;
27
+ weight?: "bold" | "normal" | "medium" | "semibold" | null | undefined;
28
28
  leading?: "none" | "normal" | "tight" | "snug" | "relaxed" | "loose" | null | undefined;
29
29
  tracking?: "normal" | "tight" | "wide" | "wider" | null | undefined;
30
30
  wrap?: "balance" | "pretty" | "nowrap" | null | undefined;
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { MenuLinkComponent } from './menu-types.js';
3
3
  import { TopComparisonRow } from './top-types.js';
4
4
  import 'react';
5
- import '../place-types-C4rR3LTs.js';
5
+ import '../place-types-Dzy6FH67.js';
6
6
  import '../lib/grade.js';
7
7
 
8
8
  type TopComparisonLabels = {
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { MenuLinkComponent } from './menu-types.js';
3
3
  import 'react';
4
- import '../place-types-C4rR3LTs.js';
4
+ import '../place-types-Dzy6FH67.js';
5
5
  import '../lib/grade.js';
6
6
 
7
7
  type TopCrossLinkProps = {
@@ -3,7 +3,7 @@ import { MenuItemLabels } from './menu-item.js';
3
3
  import { MenuItemPreview, MenuLinkComponent } from './menu-types.js';
4
4
  import { TopRankEntry } from './top-types.js';
5
5
  import 'react';
6
- import '../place-types-C4rR3LTs.js';
6
+ import '../place-types-Dzy6FH67.js';
7
7
  import '../lib/grade.js';
8
8
 
9
9
  type TopRankingEntryLabels = {
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { MenuLinkComponent } from './menu-types.js';
3
3
  import { TopExit } from './top-types.js';
4
4
  import 'react';
5
- import '../place-types-C4rR3LTs.js';
5
+ import '../place-types-Dzy6FH67.js';
6
6
  import '../lib/grade.js';
7
7
 
8
8
  type TopRankingHeroProps = {
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { MenuItemPreview } from './menu-types.js';
3
- import '../place-types-C4rR3LTs.js';
3
+ import '../place-types-Dzy6FH67.js';
4
4
  import 'react/jsx-runtime';
5
5
  import '../lib/grade.js';
6
6
 
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { a as PlaceGradeDimensions } from '../place-types-C4rR3LTs.js';
2
+ import { b as PlaceGradeDimensions } from '../place-types-Dzy6FH67.js';
3
3
  import '../lib/grade.js';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { C as CitedText } from '../place-types-C4rR3LTs.js';
2
+ import { C as CitedText } from '../place-types-Dzy6FH67.js';
3
3
  import '../lib/grade.js';
4
4
 
5
5
  /**
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { MenuLinkComponent, MenuLinkProps } from './menu-types.js';
3
- import { P as PlacePreview } from '../place-types-C4rR3LTs.js';
3
+ import { P as PlacePreview } from '../place-types-Dzy6FH67.js';
4
4
  import 'react';
5
5
  import '../lib/grade.js';
6
6
 
@@ -123,6 +123,12 @@ type PlacePreview = {
123
123
  * bare storage key straight to `next/image`'s loader).
124
124
  */
125
125
  cover_url?: string;
126
+ /**
127
+ * Year and month the place launched (`YYYY-MM`), as the schema ships it.
128
+ * The backend approximates it from the earliest review it holds, so it is a
129
+ * floor rather than a founding date. `<PlaceCard>` shows the year only.
130
+ */
131
+ launched_at?: string;
126
132
  };
127
133
  type PlaceHourBlock = {
128
134
  opens_at: number;
@@ -248,6 +254,11 @@ type PlaceCardLabels = {
248
254
  viewDetails: (name: string) => string;
249
255
  /** Accessible name of the `$` price glyphs, e.g. "Price level 2 of 4". */
250
256
  priceLevel: (level: number) => string;
257
+ /**
258
+ * The launch year on the meta line, e.g. "Est. 2020" / "Din 2020". Optional:
259
+ * without it the card shows no year even when `launched_at` is set.
260
+ */
261
+ established?: (year: number) => string;
251
262
  grade: GradeAtomLabels;
252
263
  };
253
264
  /**
@@ -321,4 +332,4 @@ type PlaceDetailsMobileLabels = PlaceAboutTabLabels & {
321
332
  noImageAvailable: string;
322
333
  };
323
334
 
324
- export { type CitedText as C, GradeAtom as G, type MenuSizeAndPrice as M, type PlacePreview as P, type WeekdayKey as W, type PlaceGradeDimensions as a, type PlaceAboutTabLabels as b, type PlaceLinkKind as c, type PlaceCardLabels as d, type PlaceDetailsMobileLabels as e, type PlaceSchedule as f, type PlaceScheduleWeekLabels as g, type GradeAtomLabels as h, type GradeAtomProps as i, type GradeAtomSize as j, type CitedValue as k, type PlaceGrade as l, type PlaceHourBlock as m, type PlaceMustTry as n, type PlacePriceRange as o, type PlaceReviewsDigest as p };
335
+ export { type CitedText as C, type GradeAtomLabels as G, type MenuSizeAndPrice as M, type PlacePreview as P, type WeekdayKey as W, type PlaceGrade as a, type PlaceGradeDimensions as b, type PlaceAboutTabLabels as c, type PlaceLinkKind as d, type PlaceCardLabels as e, type PlaceDetailsMobileLabels as f, type PlaceSchedule as g, type PlaceScheduleWeekLabels as h, GradeAtom as i, type GradeAtomProps as j, type GradeAtomSize as k, type CitedValue as l, type PlaceHourBlock as m, type PlaceMustTry as n, type PlacePriceRange as o, type PlaceReviewsDigest as p };
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@bearmenu/ui",
3
- "version": "0.8.48",
3
+ "version": "0.8.50",
4
+ "packageManager": "pnpm@10.28.1",
4
5
  "description": "BearMenu design system — shared UI tokens, primitives, and components",
5
6
  "license": "UNLICENSED",
6
7
  "repository": {
@@ -16,20 +17,223 @@
16
17
  "src"
17
18
  ],
18
19
  "exports": {
20
+ "./components/accordion": "./src/components/accordion.tsx",
21
+ "./components/action-bar": "./src/components/action-bar.tsx",
22
+ "./components/activity-row": "./src/components/activity-row.tsx",
23
+ "./components/alert": "./src/components/alert.tsx",
24
+ "./components/alert-dialog": "./src/components/alert-dialog.tsx",
25
+ "./components/aspect-ratio": "./src/components/aspect-ratio.tsx",
26
+ "./components/avatar": "./src/components/avatar.tsx",
27
+ "./components/badge": "./src/components/badge.tsx",
28
+ "./components/banner": "./src/components/banner.tsx",
29
+ "./components/booking-row": "./src/components/booking-row.tsx",
30
+ "./components/booking-summary-card": "./src/components/booking-summary-card.tsx",
31
+ "./components/breadcrumb": "./src/components/breadcrumb.tsx",
32
+ "./components/button": "./src/components/button.tsx",
33
+ "./components/button-group": "./src/components/button-group.tsx",
34
+ "./components/calendar": "./src/components/calendar.tsx",
35
+ "./components/card": "./src/components/card.tsx",
36
+ "./components/carousel": "./src/components/carousel.tsx",
37
+ "./components/category-deck": "./src/components/category-deck.tsx",
38
+ "./components/checkbox": "./src/components/checkbox.tsx",
39
+ "./components/circular-progress": "./src/components/circular-progress.tsx",
40
+ "./components/coach-marks": "./src/components/coach-marks.tsx",
41
+ "./components/collapsible": "./src/components/collapsible.tsx",
42
+ "./components/combobox": "./src/components/combobox.tsx",
43
+ "./components/command": "./src/components/command.tsx",
44
+ "./components/concept-card": "./src/components/concept-card.tsx",
45
+ "./components/concept-compare": "./src/components/concept-compare.tsx",
46
+ "./components/concept-compare-rail": "./src/components/concept-compare-rail.tsx",
47
+ "./components/concept-convergence": "./src/components/concept-convergence.tsx",
48
+ "./components/convergence": "./src/components/convergence.tsx",
49
+ "./components/coverflow": "./src/components/coverflow.tsx",
50
+ "./components/currency-input": "./src/components/currency-input.tsx",
51
+ "./components/date-input": "./src/components/date-input.tsx",
52
+ "./components/day-rail-chip": "./src/components/day-rail-chip.tsx",
53
+ "./components/description-list": "./src/components/description-list.tsx",
54
+ "./components/dialog": "./src/components/dialog.tsx",
55
+ "./components/doorway-tiles": "./src/components/doorway-tiles.tsx",
56
+ "./components/drawer": "./src/components/drawer.tsx",
57
+ "./components/drift-rail": "./src/components/drift-rail.tsx",
58
+ "./components/dropdown-menu": "./src/components/dropdown-menu.tsx",
59
+ "./components/empty-state": "./src/components/empty-state.tsx",
60
+ "./components/event-card": "./src/components/event-card.tsx",
61
+ "./components/event-compact-row": "./src/components/event-compact-row.tsx",
62
+ "./components/event-day-header": "./src/components/event-day-header.tsx",
63
+ "./components/event-day-separator": "./src/components/event-day-separator.tsx",
64
+ "./components/event-detail-panel": "./src/components/event-detail-panel.tsx",
65
+ "./components/event-hub-hero": "./src/components/event-hub-hero.tsx",
66
+ "./components/event-index-row": "./src/components/event-index-row.tsx",
67
+ "./components/event-list-row": "./src/components/event-list-row.tsx",
68
+ "./components/event-list-row-wide": "./src/components/event-list-row-wide.tsx",
69
+ "./components/event-poster-fallback": "./src/components/event-poster-fallback.tsx",
70
+ "./components/event-tonight-strip": "./src/components/event-tonight-strip.tsx",
71
+ "./components/event-types": "./src/components/event-types.ts",
72
+ "./components/events-empty-state": "./src/components/events-empty-state.tsx",
73
+ "./components/explainer-steps": "./src/components/explainer-steps.tsx",
74
+ "./components/facet-group": "./src/components/facet-group.tsx",
75
+ "./components/featured-rail-item": "./src/components/featured-rail-item.tsx",
76
+ "./components/field": "./src/components/field.tsx",
77
+ "./components/filter-category-row": "./src/components/filter-category-row.tsx",
78
+ "./components/form": "./src/components/form.tsx",
79
+ "./components/glass-ground": "./src/components/glass-ground.tsx",
80
+ "./components/grade-atom": "./src/components/grade-atom.tsx",
81
+ "./components/haptic-switch": "./src/components/haptic-switch.tsx",
82
+ "./components/hold-countdown": "./src/components/hold-countdown.tsx",
83
+ "./components/hub-surface": "./src/components/hub-surface.tsx",
84
+ "./components/hue-chip": "./src/components/hue-chip.tsx",
85
+ "./components/icon": "./src/components/icon.tsx",
86
+ "./components/input": "./src/components/input.tsx",
87
+ "./components/input-group": "./src/components/input-group.tsx",
88
+ "./components/input-otp": "./src/components/input-otp.tsx",
89
+ "./components/item": "./src/components/item.tsx",
90
+ "./components/kbd": "./src/components/kbd.tsx",
91
+ "./components/label": "./src/components/label.tsx",
92
+ "./components/kitchen-dossier": "./src/components/kitchen-dossier.tsx",
93
+ "./components/lazy-markdown": "./src/components/lazy-markdown.tsx",
94
+ "./components/link-button": "./src/components/link-button.tsx",
95
+ "./components/markdown-renderer": "./src/components/markdown-renderer.tsx",
96
+ "./components/menu-dead-end": "./src/components/menu-dead-end.tsx",
97
+ "./components/menu-family-block": "./src/components/menu-family-block.tsx",
98
+ "./components/menu-family-card": "./src/components/menu-family-card.tsx",
99
+ "./components/menu-field": "./src/components/menu-field.tsx",
100
+ "./components/menu-filter-chips": "./src/components/menu-filter-chips.tsx",
101
+ "./components/menu-group-rows": "./src/components/menu-group-rows.tsx",
102
+ "./components/menu-hub-hero": "./src/components/menu-hub-hero.tsx",
103
+ "./components/menu-index-header": "./src/components/menu-index-header.tsx",
104
+ "./components/menu-index-list": "./src/components/menu-index-list.tsx",
105
+ "./components/menu-intent-hero": "./src/components/menu-intent-hero.tsx",
106
+ "./components/menu-item": "./src/components/menu-item.tsx",
107
+ "./components/menu-pick-row": "./src/components/menu-pick-row.tsx",
108
+ "./components/menu-kitchen-list": "./src/components/menu-kitchen-list.tsx",
109
+ "./components/menu-mocks": "./src/components/menu-mocks.ts",
110
+ "./components/menu-types": "./src/components/menu-types.ts",
111
+ "./components/motion-icon": "./src/components/motion-icon.tsx",
112
+ "./components/motion-icon-actions": "./src/components/motion-icon-actions.tsx",
113
+ "./components/motion-icon-controls": "./src/components/motion-icon-controls.tsx",
114
+ "./components/motion-icon-set": "./src/components/motion-icon-set.tsx",
115
+ "./components/multi-select-combobox": "./src/components/multi-select-combobox.tsx",
116
+ "./components/multi-select-menu": "./src/components/multi-select-menu.tsx",
117
+ "./components/native-select": "./src/components/native-select.tsx",
118
+ "./components/open-now-list": "./src/components/open-now-list.tsx",
119
+ "./components/pagination": "./src/components/pagination.tsx",
120
+ "./components/pan-zoom-viewport": "./src/components/pan-zoom-viewport.tsx",
121
+ "./components/party-counter": "./src/components/party-counter.tsx",
122
+ "./components/phone-frame": "./src/components/phone-frame.tsx",
123
+ "./components/photo-ground": "./src/components/photo-ground.tsx",
124
+ "./components/place-about-tab": "./src/components/place-about-tab.tsx",
125
+ "./components/place-card": "./src/components/place-card.tsx",
126
+ "./components/place-details-mobile": "./src/components/place-details-mobile.tsx",
127
+ "./components/place-schedule-week": "./src/components/place-schedule-week.tsx",
128
+ "./components/place-types": "./src/components/place-types.ts",
129
+ "./components/popover": "./src/components/popover.tsx",
130
+ "./components/poster-stack": "./src/components/poster-stack.tsx",
131
+ "./components/poster-tape": "./src/components/poster-tape.tsx",
132
+ "./components/poster-wall": "./src/components/poster-wall.tsx",
133
+ "./components/progress": "./src/components/progress.tsx",
134
+ "./components/qa-block": "./src/components/qa-block.tsx",
135
+ "./components/qr-panel": "./src/components/qr-panel.tsx",
136
+ "./components/quiet-stretch": "./src/components/quiet-stretch.tsx",
137
+ "./components/radio-group": "./src/components/radio-group.tsx",
138
+ "./components/reconcile-bar": "./src/components/reconcile-bar.tsx",
139
+ "./components/responsive-overlay": "./src/components/responsive-overlay.tsx",
140
+ "./components/rating": "./src/components/rating.tsx",
141
+ "./components/scroll-area": "./src/components/scroll-area.tsx",
142
+ "./components/scroll-fade": "./src/components/scroll-fade.tsx",
143
+ "./components/search-bar": "./src/components/search-bar.tsx",
144
+ "./components/searchable-select": "./src/components/searchable-select.tsx",
145
+ "./components/section-header": "./src/components/section-header.tsx",
146
+ "./components/segmented-nav": "./src/components/segmented-nav.tsx",
147
+ "./components/select": "./src/components/select.tsx",
148
+ "./components/selection-bar": "./src/components/selection-bar.tsx",
149
+ "./components/separator": "./src/components/separator.tsx",
150
+ "./components/sheet": "./src/components/sheet.tsx",
151
+ "./components/signature-chip": "./src/components/signature-chip.tsx",
152
+ "./components/skeleton": "./src/components/skeleton.tsx",
153
+ "./components/skeleton-card": "./src/components/skeleton-card.tsx",
154
+ "./components/slider": "./src/components/slider.tsx",
155
+ "./components/sliding-panels": "./src/components/sliding-panels.tsx",
156
+ "./components/sonner": "./src/components/sonner.tsx",
157
+ "./components/sort-option-list": "./src/components/sort-option-list.tsx",
158
+ "./components/spinner": "./src/components/spinner.tsx",
159
+ "./components/split-share-row": "./src/components/split-share-row.tsx",
160
+ "./components/stat-banner": "./src/components/stat-banner.tsx",
161
+ "./components/stepper": "./src/components/stepper.tsx",
162
+ "./components/sticky-container": "./src/components/sticky-container.tsx",
163
+ "./components/story": "./src/components/story.tsx",
164
+ "./components/switch": "./src/components/switch.tsx",
165
+ "./components/table": "./src/components/table.tsx",
166
+ "./components/table-ledger-card": "./src/components/table-ledger-card.tsx",
167
+ "./components/table-trigger-band": "./src/components/table-trigger-band.tsx",
168
+ "./components/tabs": "./src/components/tabs.tsx",
169
+ "./components/tag": "./src/components/tag.tsx",
170
+ "./components/tag-group": "./src/components/tag-group.tsx",
171
+ "./components/text": "./src/components/text.tsx",
172
+ "./components/textarea": "./src/components/textarea.tsx",
173
+ "./components/time-slot": "./src/components/time-slot.tsx",
174
+ "./components/timeline-day": "./src/components/timeline-day.tsx",
175
+ "./components/timeline-hour": "./src/components/timeline-hour.tsx",
176
+ "./components/timeline-hour-puck": "./src/components/timeline-hour-puck.tsx",
177
+ "./components/toggle": "./src/components/toggle.tsx",
178
+ "./components/toggle-group": "./src/components/toggle-group.tsx",
179
+ "./components/tooltip": "./src/components/tooltip.tsx",
180
+ "./components/top-comparison": "./src/components/top-comparison.tsx",
181
+ "./components/top-cross-link": "./src/components/top-cross-link.tsx",
182
+ "./components/top-ranking-entry": "./src/components/top-ranking-entry.tsx",
183
+ "./components/top-ranking-hero": "./src/components/top-ranking-hero.tsx",
184
+ "./components/top-ranking-legend": "./src/components/top-ranking-legend.tsx",
185
+ "./components/top-types": "./src/components/top-types.ts",
186
+ "./components/use-mobile": "./src/components/use-mobile.tsx",
187
+ "./components/venue-events-block": "./src/components/venue-events-block.tsx",
188
+ "./components/venue-grade-dimensions": "./src/components/venue-grade-dimensions.tsx",
189
+ "./components/venue-quotes": "./src/components/venue-quotes.tsx",
190
+ "./components/venue-wall": "./src/components/venue-wall.tsx",
191
+ "./components/weekday-chip": "./src/components/weekday-chip.tsx",
192
+ "./components/weekday-theme-banner": "./src/components/weekday-theme-banner.tsx",
193
+ "./components/weekend-panel": "./src/components/weekend-panel.tsx",
19
194
  "./globals.css": "./src/globals.css",
20
- "./components/*": {
21
- "types": "./dist/components/*.d.ts",
22
- "import": "./dist/components/*.js"
23
- },
24
- "./hooks/*": {
25
- "types": "./dist/hooks/*.d.ts",
26
- "import": "./dist/hooks/*.js"
27
- },
28
- "./lib/*": {
29
- "types": "./dist/lib/*.d.ts",
30
- "import": "./dist/lib/*.js"
195
+ "./hooks/use-drag-swipe": "./src/hooks/use-drag-swipe.ts",
196
+ "./hooks/use-haptic": "./src/hooks/use-haptic.ts",
197
+ "./hooks/use-media-query": "./src/hooks/use-media-query.ts",
198
+ "./hooks/use-mobile": "./src/hooks/use-mobile.ts",
199
+ "./hooks/use-mounted-theme": "./src/hooks/use-mounted-theme.ts",
200
+ "./hooks/use-sticky": "./src/hooks/use-sticky.ts",
201
+ "./lib/card-hover": "./src/lib/card-hover.ts",
202
+ "./lib/grade": "./src/lib/grade.ts",
203
+ "./lib/icon-depth": "./src/lib/icon-depth.ts",
204
+ "./lib/icon-registry": "./src/lib/icon-registry.ts",
205
+ "./lib/motion": "./src/lib/motion.ts",
206
+ "./lib/overlay-pill": "./src/lib/overlay-pill.ts",
207
+ "./lib/utils": "./src/lib/utils.ts"
208
+ },
209
+ "publishConfig": {
210
+ "exports": {
211
+ "./globals.css": "./src/globals.css",
212
+ "./components/*": {
213
+ "types": "./dist/components/*.d.ts",
214
+ "import": "./dist/components/*.js"
215
+ },
216
+ "./hooks/*": {
217
+ "types": "./dist/hooks/*.d.ts",
218
+ "import": "./dist/hooks/*.js"
219
+ },
220
+ "./lib/*": {
221
+ "types": "./dist/lib/*.d.ts",
222
+ "import": "./dist/lib/*.js"
223
+ }
31
224
  }
32
225
  },
226
+ "scripts": {
227
+ "storybook": "storybook dev -p 6006",
228
+ "build-storybook": "storybook build",
229
+ "build": "tsup",
230
+ "dev": "tsup --watch",
231
+ "typecheck": "tsc --noEmit",
232
+ "test": "vitest run",
233
+ "test:watch": "vitest",
234
+ "clean": "rm -rf dist",
235
+ "prepublishOnly": "pnpm run build"
236
+ },
33
237
  "peerDependencies": {
34
238
  "@hookform/resolvers": "^3.0.0 || ^5.0.0",
35
239
  "@radix-ui/react-accordion": "*",
@@ -138,15 +342,5 @@
138
342
  "vaul": "^1.1.2",
139
343
  "vitest": "^4.1.5",
140
344
  "zod": "^3.25.67"
141
- },
142
- "scripts": {
143
- "storybook": "storybook dev -p 6006",
144
- "build-storybook": "storybook build",
145
- "build": "tsup",
146
- "dev": "tsup --watch",
147
- "typecheck": "tsc --noEmit",
148
- "test": "vitest run",
149
- "test:watch": "vitest",
150
- "clean": "rm -rf dist"
151
345
  }
152
- }
346
+ }
@@ -84,6 +84,41 @@ describe("EventDetailPanel", () => {
84
84
  expect(screen.getByText(labels.venueNoPage)).toBeInTheDocument();
85
85
  });
86
86
 
87
+ it("shows the venue's BearMenu grade instead of the Google star when given", () => {
88
+ const venue = {
89
+ name: "Sophie",
90
+ address: "Str. 5",
91
+ ratingLabel: "4.7",
92
+ href: "/places/sophie",
93
+ grade: { overall: 8.7, show_number: true },
94
+ };
95
+ const gradeLabels = {
96
+ soft: "Few reviews",
97
+ bands: {
98
+ exceptional: "Exceptional",
99
+ great: "Great",
100
+ good: "Good",
101
+ decent: "Decent",
102
+ weak: "Weak",
103
+ },
104
+ aria: (value: string) => `Grade ${value}`,
105
+ capped: "Capped",
106
+ };
107
+ const { container, rerender } = render(
108
+ <EventDetailPanel
109
+ {...base}
110
+ labels={{ ...labels, grade: gradeLabels }}
111
+ venue={venue}
112
+ />,
113
+ );
114
+ expect(container.textContent).toMatch(/8[.,]7/);
115
+ expect(container.textContent).not.toContain("4.7");
116
+
117
+ // No grade labels: exactly the old card.
118
+ rerender(<EventDetailPanel {...base} venue={venue} />);
119
+ expect(container.textContent).toContain("4.7");
120
+ });
121
+
87
122
  it("previews five performers and reveals the rest on request", () => {
88
123
  const performers = ["A", "B", "C", "D", "E", "F", "G"];
89
124
  render(
@@ -14,7 +14,10 @@ import {
14
14
  Unplug,
15
15
  User,
16
16
  } from "lucide-react";
17
+ import { showsGradeAtom } from "../lib/grade";
17
18
  import { cn } from "../lib/utils";
19
+ import { GradeAtom, type GradeAtomLabels } from "./grade-atom";
20
+ import type { PlaceGrade } from "./place-types";
18
21
  import { Button } from "./button";
19
22
  import { EventPosterFallback } from "./event-poster-fallback";
20
23
  import { Separator } from "./separator";
@@ -81,7 +84,13 @@ export type EventDetailVenue = {
81
84
  name: string;
82
85
  /** Address line, e.g. "Str. Iuliu Maniu 5". */
83
86
  address?: string;
84
- /** e.g. "4.7" — rendered with a star. */
87
+ /**
88
+ * The venue's BearMenu grade. Shown as the grade pill in the rating's place
89
+ * when `labels.grade` is given; the star `ratingLabel` then stays only for a
90
+ * venue without a grade.
91
+ */
92
+ grade?: PlaceGrade;
93
+ /** e.g. "4.7" — Google's rating, rendered with a star. The fallback for an ungraded venue. */
85
94
  ratingLabel?: string;
86
95
  /** e.g. "open until 20:00" — appended to the meta row when given. */
87
96
  openLabel?: string;
@@ -97,6 +106,8 @@ export type EventDetailVenue = {
97
106
  };
98
107
 
99
108
  export type EventDetailPanelLabels = {
109
+ /** The venue's grade pill. Optional: without it the venue shows the star, as before. */
110
+ grade?: GradeAtomLabels;
100
111
  free: string;
101
112
  liveNow: string;
102
113
  /** The ended chip, e.g. "Ended". */
@@ -752,7 +763,7 @@ export function EventDetailChipRow({
752
763
 
753
764
  export type EventDetailVenueCardProps = {
754
765
  venue: EventDetailVenue;
755
- labels: Pick<EventDetailPanelLabels, "venueNoPage">;
766
+ labels: Pick<EventDetailPanelLabels, "venueNoPage" | "grade">;
756
767
  linkComponent?: React.ComponentType<EventDetailPanelLinkProps>;
757
768
  /** Thumbnail size in px: 52 in the sheet, 64 on the page. */
758
769
  thumbnailSize?: 52 | 64;
@@ -774,8 +785,10 @@ export function EventDetailVenueCard({
774
785
  action,
775
786
  className,
776
787
  }: EventDetailVenueCardProps) {
777
- const meta =
778
- venue.href && (venue.address || venue.ratingLabel || venue.openLabel);
788
+ const showGrade =
789
+ labels.grade !== undefined && showsGradeAtom(venue.grade, "xs");
790
+ const hasRating = showGrade || Boolean(venue.ratingLabel);
791
+ const meta = venue.href && (venue.address || hasRating || venue.openLabel);
779
792
  // The main area (thumb, name, meta, chevron) is the link; `action` sits
780
793
  // BESIDE it, never inside — an anchor cannot contain another control, and a
781
794
  // page's "Open in Maps" must not navigate to the venue instead.
@@ -816,16 +829,25 @@ export function EventDetailVenueCard({
816
829
  {venue.address && (
817
830
  <span className="truncate">{venue.address}</span>
818
831
  )}
819
- {venue.address && venue.ratingLabel && (
832
+ {venue.address && hasRating && (
820
833
  <span aria-hidden className="text-border">
821
834
  ·
822
835
  </span>
823
836
  )}
824
- {venue.ratingLabel && (
825
- <span className="inline-flex shrink-0 items-center gap-1">
826
- <Star className="h-[11px] w-[11px]" aria-hidden />
827
- {venue.ratingLabel}
828
- </span>
837
+ {showGrade && labels.grade && venue.grade ? (
838
+ <GradeAtom
839
+ grade={venue.grade}
840
+ labels={labels.grade}
841
+ size="xs"
842
+ className="shrink-0"
843
+ />
844
+ ) : (
845
+ venue.ratingLabel && (
846
+ <span className="inline-flex shrink-0 items-center gap-1">
847
+ <Star className="h-[11px] w-[11px]" aria-hidden />
848
+ {venue.ratingLabel}
849
+ </span>
850
+ )
829
851
  )}
830
852
  {venue.openLabel && (
831
853
  <>
@@ -24,6 +24,45 @@ const kitchen: MenuKitchenPreview = {
24
24
  },
25
25
  };
26
26
 
27
+ const gradeLabels = {
28
+ soft: "Few reviews",
29
+ bands: { exceptional: "Exceptional", great: "Great", good: "Good", decent: "Decent", weak: "Weak" },
30
+ aria: (value: string) => `Grade ${value}`,
31
+ capped: "Capped",
32
+ };
33
+
34
+ describe("MenuKitchenList rating", () => {
35
+ const graded = {
36
+ ...kitchen,
37
+ place: {
38
+ ...kitchen.place,
39
+ rating: { rating: 4.8, count: 900 },
40
+ reviews_digest: { grade: { overall: 8.7, show_number: true } },
41
+ },
42
+ } as MenuKitchenPreview;
43
+
44
+ it("shows the BearMenu grade instead of the Google star when the venue has one", () => {
45
+ const { container } = render(
46
+ <MenuKitchenList kitchens={[graded]} labels={{ ...labels, grade: gradeLabels }} />
47
+ );
48
+ expect(container.textContent).toMatch(/8[.,]7/);
49
+ expect(container.textContent).not.toContain("4.8");
50
+ });
51
+
52
+ it("keeps the star for a venue with no grade", () => {
53
+ const ungraded = { ...graded, place: { ...graded.place, reviews_digest: undefined } };
54
+ const { container } = render(
55
+ <MenuKitchenList kitchens={[ungraded]} labels={{ ...labels, grade: gradeLabels }} />
56
+ );
57
+ expect(container.textContent).toContain("4.8");
58
+ });
59
+
60
+ it("keeps the star for callers that pass no grade labels", () => {
61
+ const { container } = render(<MenuKitchenList kitchens={[graded]} labels={labels} />);
62
+ expect(container.textContent).toContain("4.8");
63
+ });
64
+ });
65
+
27
66
  describe("MenuKitchenList", () => {
28
67
  /**
29
68
  * The reason this component exists rather than a flag on `RankedVenueList`.
@@ -1,5 +1,7 @@
1
1
  import { Check, ChevronRight, Clock, MessageSquare, Star } from "lucide-react";
2
+ import { showsGradeAtom } from "../lib/grade";
2
3
  import { cn } from "../lib/utils";
4
+ import { GradeAtom, type GradeAtomLabels } from "./grade-atom";
3
5
  import { Separator } from "./separator";
4
6
  import { Skeleton } from "./skeleton";
5
7
  import type { MenuKitchenPreview, MenuLinkComponent, MenuLinkProps } from "./menu-types";
@@ -59,6 +61,13 @@ export type MenuKitchenListLabels = {
59
61
  openNow: string;
60
62
  /** Reveals the next page of rows, e.g. "Show 10 more". */
61
63
  showMore?: string;
64
+ /**
65
+ * The grade pill's labels. With them, a graded venue shows its BearMenu
66
+ * grade where the Google star was; the star stays only for a venue with no
67
+ * grade. Optional so existing callers keep compiling — without it every row
68
+ * shows the star, as before.
69
+ */
70
+ grade?: GradeAtomLabels;
62
71
  };
63
72
 
64
73
  /**
@@ -127,6 +136,31 @@ export function MenuKitchenList({
127
136
  );
128
137
  }
129
138
 
139
+ function gradeShown(place: MenuKitchenPreview["place"], labels: MenuKitchenListLabels) {
140
+ return labels.grade !== undefined && showsGradeAtom(place.reviews_digest?.grade, "xs");
141
+ }
142
+
143
+ /** BearMenu's grade when the venue has one; Google's star only without it. */
144
+ function KitchenRating({
145
+ place,
146
+ labels,
147
+ }: {
148
+ place: MenuKitchenPreview["place"];
149
+ labels: MenuKitchenListLabels;
150
+ }) {
151
+ const grade = place.reviews_digest?.grade;
152
+ if (labels.grade && showsGradeAtom(grade, "xs")) {
153
+ return <GradeAtom grade={grade} labels={labels.grade} size="xs" className="shrink-0" />;
154
+ }
155
+ if (!place.rating) return null;
156
+ return (
157
+ <>
158
+ <Star className="h-[11px] w-[11px] shrink-0" aria-hidden />
159
+ {place.rating.rating}
160
+ </>
161
+ );
162
+ }
163
+
130
164
  function KitchenRow({
131
165
  kitchen,
132
166
  labels,
@@ -189,13 +223,8 @@ function KitchenRow({
189
223
  {place.name}
190
224
  </span>
191
225
  <span className="flex items-center gap-1 truncate text-xs text-muted-foreground">
192
- {place.rating && (
193
- <>
194
- <Star className="h-[11px] w-[11px] shrink-0" aria-hidden />
195
- {place.rating.rating}
196
- {kitchen.metaLabel && " · "}
197
- </>
198
- )}
226
+ <KitchenRating place={place} labels={labels} />
227
+ {kitchen.metaLabel && (gradeShown(place, labels) || place.rating) && " · "}
199
228
  {kitchen.metaLabel}
200
229
  </span>
201
230
  {kitchen.hoursLabel && (