@bearmenu/ui 0.6.0 → 0.7.0

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 (80) hide show
  1. package/dist/chunk-A5ONAJCE.js +102 -0
  2. package/dist/chunk-AV777R4G.js +43 -0
  3. package/dist/{chunk-WKMLZDUT.js → chunk-FRPPIXMY.js} +1 -1
  4. package/dist/{chunk-PSR7N36A.js → chunk-HCM6LKM5.js} +1 -1
  5. package/dist/{chunk-YJ6OBKZJ.js → chunk-TL4YU2O5.js} +10 -3
  6. package/dist/chunk-UX6SWAKH.js +320 -0
  7. package/dist/{chunk-7PPCH42H.js → chunk-VQNDZVI7.js} +1 -1
  8. package/dist/chunk-WSRWFA6K.js +26 -0
  9. package/dist/chunk-YLNYXPIH.js +61 -0
  10. package/dist/components/accordion.js +1 -1
  11. package/dist/components/alert.d.ts +2 -2
  12. package/dist/components/badge.d.ts +3 -2
  13. package/dist/components/badge.js +1 -1
  14. package/dist/components/button.d.ts +1 -1
  15. package/dist/components/card.d.ts +2 -2
  16. package/dist/components/card.js +127 -4
  17. package/dist/components/combobox.js +2 -2
  18. package/dist/components/command.d.ts +15 -15
  19. package/dist/components/command.js +2 -2
  20. package/dist/components/currency-input.js +1 -1
  21. package/dist/components/date-input.d.ts +1 -1
  22. package/dist/components/date-input.js +1 -1
  23. package/dist/components/dialog.js +1 -1
  24. package/dist/components/filter-category-row.d.ts +13 -0
  25. package/dist/components/filter-category-row.js +44 -0
  26. package/dist/components/input-group.d.ts +2 -0
  27. package/dist/components/input-group.js +10 -5
  28. package/dist/components/input.d.ts +1 -0
  29. package/dist/components/input.js +1 -1
  30. package/dist/components/item.d.ts +2 -2
  31. package/dist/components/multi-select-combobox.js +3 -3
  32. package/dist/components/phone-frame.js +1 -1
  33. package/dist/components/place-about-tab.d.ts +2 -2
  34. package/dist/components/place-about-tab.js +4 -3
  35. package/dist/components/place-details-mobile.js +5 -3
  36. package/dist/components/place-schedule-week.d.ts +19 -0
  37. package/dist/components/place-schedule-week.js +4 -0
  38. package/dist/components/place-types.d.ts +18 -9
  39. package/dist/components/scroll-fade.d.ts +15 -0
  40. package/dist/components/scroll-fade.js +121 -0
  41. package/dist/components/searchable-select.js +2 -2
  42. package/dist/components/separator.js +3 -26
  43. package/dist/components/sheet.js +1 -1
  44. package/dist/components/sliding-panels.d.ts +1 -0
  45. package/dist/components/sliding-panels.js +22 -6
  46. package/dist/components/sort-option-list.d.ts +16 -0
  47. package/dist/components/sort-option-list.js +46 -0
  48. package/dist/components/spinner.d.ts +2 -2
  49. package/dist/components/tabs.js +98 -17
  50. package/dist/components/tag.d.ts +2 -2
  51. package/dist/components/tag.js +3 -61
  52. package/dist/components/text.d.ts +3 -3
  53. package/dist/components/toast.js +1 -1
  54. package/dist/components/toaster.js +1 -1
  55. package/package.json +23 -112
  56. package/src/components/accordion.tsx +1 -1
  57. package/src/components/badge.tsx +9 -2
  58. package/src/components/card.tsx +22 -18
  59. package/src/components/dialog.tsx +1 -1
  60. package/src/components/filter-category-row.tsx +52 -0
  61. package/src/components/input-group.tsx +9 -4
  62. package/src/components/input.tsx +8 -3
  63. package/src/components/phone-frame.tsx +1 -1
  64. package/src/components/place-about-tab.stories.tsx +24 -13
  65. package/src/components/place-about-tab.test.tsx +92 -38
  66. package/src/components/place-about-tab.tsx +310 -344
  67. package/src/components/place-schedule-week.tsx +128 -0
  68. package/src/components/place-types.ts +27 -8
  69. package/src/components/scroll-fade.stories.tsx +98 -0
  70. package/src/components/scroll-fade.tsx +132 -0
  71. package/src/components/sheet.tsx +1 -1
  72. package/src/components/sliding-panels.tsx +33 -6
  73. package/src/components/sort-option-list.tsx +57 -0
  74. package/src/components/tabs.tsx +76 -11
  75. package/src/components/toast.tsx +1 -1
  76. package/src/globals.css +77 -19
  77. package/src/lib/motion.ts +137 -0
  78. package/dist/chunk-BAZFVSSG.js +0 -279
  79. package/dist/chunk-RIDXFY6M.js +0 -38
  80. package/dist/chunk-XK2ZDQVE.js +0 -122
@@ -1,20 +1,20 @@
1
1
  import { describe, it, expect, vi } from "vitest";
2
2
  import { render, screen, fireEvent } from "@testing-library/react";
3
3
  import { PlaceAboutTab } from "./place-about-tab";
4
- import type { PlaceAboutTabLabels, PlacePreview } from "./place-types";
4
+ import type {
5
+ PlaceAboutTabLabels,
6
+ PlacePreview,
7
+ PlaceSchedule,
8
+ } from "./place-types";
5
9
 
6
10
  // ─── Fixtures ─────────────────────────────────────────────────────────────────
7
11
 
8
12
  const LABELS: PlaceAboutTabLabels = {
9
- overview: "Overview",
10
13
  description: "Description",
11
- whatPeopleSay: "What people say",
12
14
  contactAndLocation: "Contact & Location",
13
- address: "Address",
14
15
  instagram: "Instagram",
15
16
  facebook: "Facebook",
16
- todayHours: "Today's hours",
17
- statusOpen: "Open now",
17
+ todayHours: "Hours",
18
18
  statusClosed: "Closed",
19
19
  typicalBusyness: "Typical busyness",
20
20
  cuisines: "Cuisines",
@@ -23,10 +23,16 @@ const LABELS: PlaceAboutTabLabels = {
23
23
  accessibility: "Accessibility",
24
24
  parking: "Parking",
25
25
  nearbyLandmarks: "Nearby landmarks",
26
- neighborhood: "Neighborhood",
27
- businessInformation: "Business information",
28
- type: "Type",
29
- status: "Status",
26
+ scheduleDays: {
27
+ monday: "Monday",
28
+ tuesday: "Tuesday",
29
+ wednesday: "Wednesday",
30
+ thursday: "Thursday",
31
+ friday: "Friday",
32
+ saturday: "Saturday",
33
+ sunday: "Sunday",
34
+ },
35
+ noHoursAvailable: "Hours not available",
30
36
  amenityLabels: { wifi: "Free Wi-Fi" },
31
37
  paymentLabels: {},
32
38
  accessibilityLabels: {},
@@ -35,6 +41,19 @@ const LABELS: PlaceAboutTabLabels = {
35
41
  statusLabels: {},
36
42
  };
37
43
 
44
+ function makeSchedule(overrides: Partial<PlaceSchedule> = {}): PlaceSchedule {
45
+ return {
46
+ monday: [],
47
+ tuesday: [],
48
+ wednesday: [],
49
+ thursday: [],
50
+ friday: [],
51
+ saturday: [],
52
+ sunday: [],
53
+ ...overrides,
54
+ };
55
+ }
56
+
38
57
  function makePlace(overrides: Partial<PlacePreview> = {}): PlacePreview {
39
58
  return {
40
59
  id: "1",
@@ -104,6 +123,33 @@ describe("PlaceAboutTab", () => {
104
123
  expect(screen.queryByText("Facebook")).not.toBeInTheDocument();
105
124
  });
106
125
 
126
+ // ─── Address + neighborhood subline ─────────────────────────────────────────
127
+
128
+ it("renders address as primary text and neighborhood as muted subline", () => {
129
+ render(
130
+ <PlaceAboutTab
131
+ place={makePlace({
132
+ location: { address: "Strada Napoca 12" },
133
+ areas: [{ name: "Centru" }, { name: "Piata Unirii" }],
134
+ })}
135
+ labels={LABELS}
136
+ />
137
+ );
138
+ expect(screen.getByText("Strada Napoca 12")).toBeInTheDocument();
139
+ expect(screen.getByText("Centru · Piata Unirii")).toBeInTheDocument();
140
+ });
141
+
142
+ it("does not render neighborhood subline when areas is empty", () => {
143
+ render(
144
+ <PlaceAboutTab
145
+ place={makePlace({ location: { address: "Strada Napoca 12" } })}
146
+ labels={LABELS}
147
+ />
148
+ );
149
+ expect(screen.getByText("Strada Napoca 12")).toBeInTheDocument();
150
+ expect(screen.queryByText(/·/)).not.toBeInTheDocument();
151
+ });
152
+
107
153
  // ─── mapSlot ────────────────────────────────────────────────────────────────
108
154
 
109
155
  it("renders mapSlot when prop is passed (regardless of busyness data)", () => {
@@ -227,29 +273,49 @@ describe("PlaceAboutTab", () => {
227
273
  );
228
274
  });
229
275
 
230
- // ─── Today's hours card ──────────────────────────────────────────────────────
276
+ // ─── Hours section (full week, schedule-driven) ─────────────────────────────
231
277
 
232
- it("renders today's hours card when place.hours has entries", () => {
278
+ it("renders the hours section heading and a slot row when place.schedule is provided", () => {
233
279
  render(
234
280
  <PlaceAboutTab
235
- place={makePlace({ hours: [{ opens_at: 9, closes_at: 22 }] })}
281
+ place={makePlace({
282
+ schedule: makeSchedule({ monday: [{ opens_at: 9, closes_at: 22 }] }),
283
+ })}
236
284
  labels={LABELS}
237
285
  />
238
286
  );
239
- expect(screen.getByText("Today's hours")).toBeInTheDocument();
240
- expect(screen.getByText("09:00 - 22:00")).toBeInTheDocument();
287
+ expect(screen.getByText("Hours")).toBeInTheDocument();
288
+ expect(screen.getByText("09:00 22:00")).toBeInTheDocument();
289
+ expect(screen.getByText("Monday")).toBeInTheDocument();
241
290
  });
242
291
 
243
- it("does NOT render today's hours card when place.hours is empty", () => {
292
+ it("renders all 7 weekday labels when schedule is present", () => {
244
293
  render(
245
- <PlaceAboutTab place={makePlace({ hours: [] })} labels={LABELS} />
294
+ <PlaceAboutTab
295
+ place={makePlace({ schedule: makeSchedule() })}
296
+ labels={LABELS}
297
+ />
298
+ );
299
+ expect(screen.getByText("Monday")).toBeInTheDocument();
300
+ expect(screen.getByText("Sunday")).toBeInTheDocument();
301
+ });
302
+
303
+ it("renders 'Closed' (line-through) for days with no slots", () => {
304
+ render(
305
+ <PlaceAboutTab
306
+ place={makePlace({
307
+ schedule: makeSchedule({ monday: [{ opens_at: 9, closes_at: 22 }] }),
308
+ })}
309
+ labels={LABELS}
310
+ />
246
311
  );
247
- expect(screen.queryByText("Today's hours")).not.toBeInTheDocument();
312
+ // Six remaining days are closed → six "Closed" line-through entries.
313
+ expect(screen.getAllByText("Closed")).toHaveLength(6);
248
314
  });
249
315
 
250
- it("does NOT render today's hours card when place.hours is absent", () => {
316
+ it("does NOT render the hours section when place.schedule is absent", () => {
251
317
  render(<PlaceAboutTab place={makePlace()} labels={LABELS} />);
252
- expect(screen.queryByText("Today's hours")).not.toBeInTheDocument();
318
+ expect(screen.queryByText("Hours")).not.toBeInTheDocument();
253
319
  });
254
320
 
255
321
  // ─── amenityLabels fallback to humanizeEnum ──────────────────────────────────
@@ -261,7 +327,6 @@ describe("PlaceAboutTab", () => {
261
327
  labels={LABELS}
262
328
  />
263
329
  );
264
- // LABELS.amenityLabels.wifi = "Free Wi-Fi"
265
330
  expect(screen.getByText("Free Wi-Fi")).toBeInTheDocument();
266
331
  });
267
332
 
@@ -272,13 +337,12 @@ describe("PlaceAboutTab", () => {
272
337
  labels={LABELS}
273
338
  />
274
339
  );
275
- // humanizeEnum("outdoor_seating") → "outdoor seating"
276
340
  expect(screen.getByText("outdoor seating")).toBeInTheDocument();
277
341
  });
278
342
 
279
- // ─── Description card visibility ────────────────────────────────────────────
343
+ // ─── Description visibility ────────────────────────────────────────────────
280
344
 
281
- it("renders description card when description is set", () => {
345
+ it("renders description prose when description is set", () => {
282
346
  render(
283
347
  <PlaceAboutTab
284
348
  place={makePlace({ description: "A great place to eat." })}
@@ -288,7 +352,7 @@ describe("PlaceAboutTab", () => {
288
352
  expect(screen.getByText("A great place to eat.")).toBeInTheDocument();
289
353
  });
290
354
 
291
- it("renders description card when generative_summary is set", () => {
355
+ it("renders description prose when generative_summary is set", () => {
292
356
  render(
293
357
  <PlaceAboutTab
294
358
  place={makePlace({ generative_summary: "AI summary here." })}
@@ -298,7 +362,7 @@ describe("PlaceAboutTab", () => {
298
362
  expect(screen.getByText("AI summary here.")).toBeInTheDocument();
299
363
  });
300
364
 
301
- it("renders description card when review_summary is set", () => {
365
+ it("renders description prose when review_summary is set", () => {
302
366
  render(
303
367
  <PlaceAboutTab
304
368
  place={makePlace({ review_summary: "People love it." })}
@@ -308,18 +372,8 @@ describe("PlaceAboutTab", () => {
308
372
  expect(screen.getByText("People love it.")).toBeInTheDocument();
309
373
  });
310
374
 
311
- it("hides description card when none of description/generative_summary/review_summary are set", () => {
375
+ it("hides the description section heading when no prose and no business chips are present", () => {
312
376
  render(<PlaceAboutTab place={makePlace()} labels={LABELS} />);
313
- // The card header title is "Description" which is the same as labels.description.
314
- // The description card renders labels.description as its CardTitle.
315
- // Use a more specific query: look for the card header content.
316
- // Since labels.contactAndLocation is always rendered, we need to count occurrences.
317
- // "Description" appears in labels.description; if no card exists it should not appear at all.
318
- expect(screen.queryByText("A great place to eat.")).not.toBeInTheDocument();
319
- // Verify no card title "Description" is rendered (description card uses labels.description as title)
320
- // Note: "Description" also equals labels.description label inside the card — use getAllByText and check count
321
- const descTexts = screen.queryAllByText("Description");
322
- // When description card is hidden, "Description" label should not appear
323
- expect(descTexts).toHaveLength(0);
377
+ expect(screen.queryByText("Description")).not.toBeInTheDocument();
324
378
  });
325
379
  });