@bearmenu/ui 0.8.15 → 0.8.17

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 (102) hide show
  1. package/README.md +1 -0
  2. package/dist/{chunk-ZLPWEHZO.js → chunk-54FQQZZJ.js} +1 -1
  3. package/dist/{chunk-5FCC5L5F.js → chunk-5LTILG3L.js} +29 -6
  4. package/dist/{chunk-P43B3ONY.js → chunk-5XREWOBB.js} +3 -1
  5. package/dist/{chunk-V4E333QS.js → chunk-5YNIQ2BL.js} +7 -29
  6. package/dist/{chunk-CLLY6XB3.js → chunk-6VOWT4YR.js} +6 -3
  7. package/dist/{chunk-S33K4RC5.js → chunk-BKKQ7GCZ.js} +1 -1
  8. package/dist/chunk-QY66ME5B.js +207 -0
  9. package/dist/chunk-RIH2IS7X.js +29 -0
  10. package/dist/{chunk-T6S2ZBV6.js → chunk-SDWN6L4O.js} +1 -1
  11. package/dist/{chunk-CNJQUHCU.js → chunk-SWD6CJ35.js} +2 -1
  12. package/dist/{chunk-HDR7V6IZ.js → chunk-TIQNM4XD.js} +8 -1
  13. package/dist/components/alert-dialog.js +3 -2
  14. package/dist/components/badge.d.ts +1 -1
  15. package/dist/components/badge.js +1 -1
  16. package/dist/components/button.d.ts +5 -1
  17. package/dist/components/button.js +3 -2
  18. package/dist/components/calendar.js +3 -2
  19. package/dist/components/carousel.js +3 -2
  20. package/dist/components/coach-marks.d.ts +63 -0
  21. package/dist/components/coach-marks.js +162 -0
  22. package/dist/components/combobox.js +3 -2
  23. package/dist/components/concept-compare-rail.js +2 -2
  24. package/dist/components/concept-compare.js +2 -2
  25. package/dist/components/concept-convergence.js +2 -2
  26. package/dist/components/date-input.d.ts +1 -1
  27. package/dist/components/doorway-tiles.d.ts +11 -0
  28. package/dist/components/doorway-tiles.js +5 -3
  29. package/dist/components/empty-state.js +3 -2
  30. package/dist/components/event-detail-panel.js +4 -3
  31. package/dist/components/event-index-row.js +1 -1
  32. package/dist/components/event-list-row-wide.js +4 -3
  33. package/dist/components/event-list-row.js +1 -1
  34. package/dist/components/facet-group.d.ts +8 -1
  35. package/dist/components/facet-group.js +3 -0
  36. package/dist/components/filter-category-row.js +1 -1
  37. package/dist/components/haptic-switch.d.ts +35 -0
  38. package/dist/components/haptic-switch.js +3 -0
  39. package/dist/components/hue-chip.js +1 -1
  40. package/dist/components/item.js +4 -1
  41. package/dist/components/kitchen-dossier.js +2 -2
  42. package/dist/components/link-button.js +3 -2
  43. package/dist/components/menu-family-block.d.ts +8 -1
  44. package/dist/components/menu-family-block.js +103 -69
  45. package/dist/components/menu-family-card.js +2 -2
  46. package/dist/components/menu-filter-chips.d.ts +12 -3
  47. package/dist/components/menu-filter-chips.js +22 -4
  48. package/dist/components/menu-index-list.js +3 -2
  49. package/dist/components/menu-item.js +3 -3
  50. package/dist/components/menu-kitchen-list.d.ts +14 -2
  51. package/dist/components/menu-kitchen-list.js +1 -1
  52. package/dist/components/multi-select-combobox.js +4 -3
  53. package/dist/components/pagination.js +3 -2
  54. package/dist/components/photo-ground.d.ts +7 -1
  55. package/dist/components/photo-ground.js +1 -1
  56. package/dist/components/place-card.js +2 -2
  57. package/dist/components/place-details-mobile.js +1 -1
  58. package/dist/components/searchable-select.js +3 -2
  59. package/dist/components/section-header.d.ts +7 -1
  60. package/dist/components/section-header.js +11 -7
  61. package/dist/components/signature-chip.js +2 -2
  62. package/dist/components/sliding-panels.js +3 -2
  63. package/dist/components/switch.d.ts +7 -1
  64. package/dist/components/switch.js +33 -24
  65. package/dist/components/toggle-group.js +9 -4
  66. package/dist/components/toggle.d.ts +1 -1
  67. package/dist/components/toggle.js +1 -1
  68. package/dist/components/top-ranking-entry.js +3 -3
  69. package/dist/hooks/use-haptic.d.ts +9 -1
  70. package/dist/hooks/use-haptic.js +1 -1
  71. package/package.json +1 -1
  72. package/src/components/badge.stories.tsx +31 -1
  73. package/src/components/badge.tsx +2 -0
  74. package/src/components/button.stories.tsx +5 -4
  75. package/src/components/button.test.tsx +11 -1
  76. package/src/components/button.tsx +41 -6
  77. package/src/components/coach-marks.stories.tsx +79 -0
  78. package/src/components/coach-marks.test.tsx +140 -0
  79. package/src/components/coach-marks.tsx +252 -0
  80. package/src/components/doorway-tiles.stories.tsx +34 -0
  81. package/src/components/doorway-tiles.test.tsx +27 -0
  82. package/src/components/doorway-tiles.tsx +30 -2
  83. package/src/components/facet-group.tsx +9 -0
  84. package/src/components/haptic-switch.test.tsx +134 -0
  85. package/src/components/haptic-switch.tsx +62 -0
  86. package/src/components/hue-chip.test.tsx +6 -3
  87. package/src/components/hue-chip.tsx +5 -2
  88. package/src/components/item.tsx +4 -1
  89. package/src/components/menu-family-block.stories.tsx +12 -0
  90. package/src/components/menu-family-block.tsx +53 -20
  91. package/src/components/menu-filter-chips.tsx +32 -4
  92. package/src/components/menu-kitchen-list.tsx +45 -6
  93. package/src/components/photo-ground.tsx +7 -0
  94. package/src/components/section-header.test.tsx +15 -0
  95. package/src/components/section-header.tsx +26 -12
  96. package/src/components/switch.tsx +29 -18
  97. package/src/components/toggle-group.stories.tsx +37 -1
  98. package/src/components/toggle-group.tsx +11 -6
  99. package/src/components/toggle.tsx +8 -0
  100. package/src/hooks/use-haptic.test.tsx +54 -59
  101. package/src/hooks/use-haptic.ts +18 -44
  102. package/dist/chunk-SXQZ7DLH.js +0 -167
@@ -1,80 +1,75 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
2
  import { act, renderHook } from "@testing-library/react";
3
- import { useHaptic } from "./use-haptic";
3
+ import { isIos, useHaptic } from "./use-haptic";
4
4
 
5
- const hapticSwitch = () => document.body.querySelector<HTMLInputElement>("input[type=checkbox][switch]");
5
+ const IOS_UA =
6
+ "Mozilla/5.0 (iPhone; CPU iPhone OS 26_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.5 Mobile/15E148 Safari/604.1";
7
+ const IPAD_AS_MAC_UA =
8
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.5 Safari/605.1.15";
6
9
 
7
- describe("useHaptic", () => {
10
+ describe("isIos", () => {
8
11
  afterEach(() => {
9
12
  vi.restoreAllMocks();
10
13
  });
11
14
 
12
- describe("on iOS Safari (no Vibration API, switch supported)", () => {
13
- beforeEach(() => {
14
- Object.defineProperty(HTMLInputElement.prototype, "switch", { value: false, configurable: true });
15
- });
16
-
17
- afterEach(() => {
18
- Reflect.deleteProperty(HTMLInputElement.prototype, "switch");
19
- hapticSwitch()?.parentElement?.remove();
20
- });
21
-
22
- it("reports support", () => {
23
- const { result } = renderHook(() => useHaptic());
24
- expect(result.current.isSupported).toBe(true);
25
- });
15
+ it("is false in jsdom", () => {
16
+ expect(isIos()).toBe(false);
17
+ });
26
18
 
27
- it("toggles one hidden switch through its label on every trigger", () => {
28
- const { result } = renderHook(() => useHaptic());
19
+ it("matches an iPhone user agent", () => {
20
+ vi.spyOn(navigator, "userAgent", "get").mockReturnValue(IOS_UA);
21
+ expect(isIos()).toBe(true);
22
+ });
29
23
 
30
- act(() => result.current.trigger("light"));
31
- const input = hapticSwitch();
32
- expect(input).not.toBeNull();
33
- expect(input?.checked).toBe(true);
34
- expect(input?.parentElement?.getAttribute("aria-hidden")).toBe("true");
24
+ it("matches an iPad presenting as a Mac by its touch points", () => {
25
+ vi.spyOn(navigator, "userAgent", "get").mockReturnValue(IPAD_AS_MAC_UA);
26
+ vi.spyOn(navigator, "platform", "get").mockReturnValue("MacIntel");
27
+ Object.defineProperty(navigator, "maxTouchPoints", { value: 5, configurable: true });
28
+ expect(isIos()).toBe(true);
29
+ Reflect.deleteProperty(navigator, "maxTouchPoints");
30
+ });
31
+ });
35
32
 
36
- act(() => result.current.trigger("light"));
37
- expect(document.body.querySelectorAll("input[switch]")).toHaveLength(1);
38
- expect(input?.checked).toBe(false);
39
- });
33
+ describe("useHaptic", () => {
34
+ afterEach(() => {
35
+ vi.restoreAllMocks();
36
+ Reflect.deleteProperty(navigator, "vibrate");
37
+ });
40
38
 
41
- it("collapses every style to the one tick WebKit has", () => {
42
- const { result } = renderHook(() => useHaptic());
39
+ it("reports support on iOS without adding anything to the DOM the switch lives in the control", () => {
40
+ vi.spyOn(navigator, "userAgent", "get").mockReturnValue(IOS_UA);
41
+ const debug = vi.spyOn(console, "debug").mockImplementation(() => {});
42
+ const { result } = renderHook(() => useHaptic());
43
43
 
44
- act(() => result.current.trigger("heavy"));
45
- expect(hapticSwitch()?.checked).toBe(true);
46
- act(() => result.current.trigger("success"));
47
- expect(hapticSwitch()?.checked).toBe(false);
48
- });
44
+ expect(result.current.isSupported).toBe(true);
45
+ expect(result.current.platform).toBe("ios");
46
+ act(() => result.current.trigger("light"));
47
+ expect(document.body.querySelector("input[switch]")).toBeNull();
48
+ expect(debug).toHaveBeenCalled();
49
49
  });
50
50
 
51
- describe("without any haptic API", () => {
52
- it("reports no support and renders no switch", () => {
53
- const debug = vi.spyOn(console, "debug").mockImplementation(() => {});
54
- const { result } = renderHook(() => useHaptic());
51
+ it("reports no support without any haptic API", () => {
52
+ const debug = vi.spyOn(console, "debug").mockImplementation(() => {});
53
+ const { result } = renderHook(() => useHaptic());
55
54
 
56
- expect(result.current.isSupported).toBe(false);
57
- act(() => result.current.trigger("light"));
58
- expect(hapticSwitch()).toBeNull();
59
- expect(debug).toHaveBeenCalled();
60
- });
55
+ expect(result.current.isSupported).toBe(false);
56
+ act(() => result.current.trigger("light"));
57
+ expect(debug).toHaveBeenCalled();
61
58
  });
62
59
 
63
- describe("with the Vibration API", () => {
64
- afterEach(() => {
65
- Reflect.deleteProperty(navigator, "vibrate");
66
- });
60
+ it("vibrates through navigator.vibrate where it exists", () => {
61
+ const vibrate = vi.fn();
62
+ Object.defineProperty(navigator, "vibrate", { value: vibrate, configurable: true });
63
+ const { result } = renderHook(() => useHaptic());
67
64
 
68
- it("prefers navigator.vibrate over the switch", () => {
69
- const vibrate = vi.fn();
70
- Object.defineProperty(navigator, "vibrate", { value: vibrate, configurable: true });
71
- Object.defineProperty(HTMLInputElement.prototype, "switch", { value: false, configurable: true });
72
- const { result } = renderHook(() => useHaptic());
65
+ act(() => result.current.trigger("medium"));
66
+ expect(vibrate).toHaveBeenCalledWith(20);
67
+ });
73
68
 
74
- act(() => result.current.trigger("medium"));
75
- expect(vibrate).toHaveBeenCalledWith(20);
76
- expect(hapticSwitch()).toBeNull();
77
- Reflect.deleteProperty(HTMLInputElement.prototype, "switch");
78
- });
69
+ it("keeps trigger referentially stable across renders", () => {
70
+ const { result, rerender } = renderHook(() => useHaptic());
71
+ const first = result.current.trigger;
72
+ rerender();
73
+ expect(result.current.trigger).toBe(first);
79
74
  });
80
75
  });
@@ -10,6 +10,21 @@ interface HapticAPI {
10
10
  trigger: (style: HapticStyle) => void;
11
11
  }
12
12
 
13
+ /**
14
+ * iOS Safari, including iPadOS masquerading as a Mac. Haptics there come from
15
+ * `HapticSwitch`, not from `trigger`: WebKit has no Vibration API, and since
16
+ * iOS 26.5 the only haptic it plays is a native switch flipping under the
17
+ * user's own finger — a programmatic click on the switch or its label no
18
+ * longer counts (WebKit #65327).
19
+ */
20
+ export function isIos(): boolean {
21
+ if (typeof navigator === "undefined") return false;
22
+ return (
23
+ /iPad|iPhone|iPod/.test(navigator.userAgent) ||
24
+ (navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1)
25
+ );
26
+ }
27
+
13
28
  export const useHaptic = (): HapticAPI => {
14
29
  const [platform, setPlatform] = useState<"ios" | "android" | "desktop" | "unknown">("unknown");
15
30
  const [isSupported, setIsSupported] = useState(false);
@@ -17,10 +32,9 @@ export const useHaptic = (): HapticAPI => {
17
32
  useEffect(() => {
18
33
  // Detect platform
19
34
  const userAgent = navigator.userAgent.toLowerCase();
20
- const isIOS = /iphone|ipad|ipod/.test(userAgent);
21
35
  const isAndroid = /android/.test(userAgent);
22
36
 
23
- if (isIOS) {
37
+ if (isIos()) {
24
38
  setPlatform("ios");
25
39
  } else if (isAndroid) {
26
40
  setPlatform("android");
@@ -32,7 +46,7 @@ export const useHaptic = (): HapticAPI => {
32
46
  const hasVibration = "vibrate" in navigator;
33
47
  const hasTelegram = typeof window !== "undefined" && window.Telegram?.WebApp?.HapticFeedback;
34
48
 
35
- setIsSupported(hasVibration || !!hasTelegram || supportsSwitchHaptic());
49
+ setIsSupported(hasVibration || !!hasTelegram || isIos());
36
50
  }, []);
37
51
 
38
52
  const trigger = useCallback((style: HapticStyle) => {
@@ -48,12 +62,7 @@ export const useHaptic = (): HapticAPI => {
48
62
  return;
49
63
  }
50
64
 
51
- // iOS Safari has no Vibration API; the switch toggle is the only haptic it exposes
52
- if (supportsSwitchHaptic()) {
53
- triggerSwitchHaptic();
54
- return;
55
- }
56
-
65
+ // iOS: nothing to call see HapticSwitch, which sits inside the control
57
66
  // No haptic support - silently fail
58
67
  console.debug("Haptic feedback not supported on this device");
59
68
  }, []);
@@ -108,41 +117,6 @@ function triggerVibrationAPI(style: HapticStyle) {
108
117
  navigator.vibrate(patterns[style]);
109
118
  }
110
119
 
111
- // Switch implementation (iOS 18+ Safari and home-screen PWAs)
112
- //
113
- // WebKit plays the system "toggle" haptic when an `<input type="checkbox" switch>`
114
- // flips through its label, and a programmatic `label.click()` counts. One hidden
115
- // switch appended to the body doubles as a haptic trigger. It is the only haptic
116
- // WebKit exposes, so every style collapses to that one tick here.
117
- // https://github.com/ionic-team/ionic-framework/issues/29942
118
- let hapticSwitch: HTMLLabelElement | null = null;
119
-
120
- function supportsSwitchHaptic(): boolean {
121
- return typeof HTMLInputElement !== "undefined" && "switch" in HTMLInputElement.prototype;
122
- }
123
-
124
- function getHapticSwitch(): HTMLLabelElement {
125
- if (hapticSwitch?.isConnected) return hapticSwitch;
126
-
127
- const label = document.createElement("label");
128
- const input = document.createElement("input");
129
- input.type = "checkbox";
130
- input.setAttribute("switch", "");
131
- input.tabIndex = -1;
132
- label.setAttribute("aria-hidden", "true");
133
- label.style.cssText =
134
- "position:fixed;top:0;left:0;width:1px;height:1px;overflow:hidden;opacity:0;pointer-events:none";
135
- label.appendChild(input);
136
- document.body.appendChild(label);
137
-
138
- hapticSwitch = label;
139
- return label;
140
- }
141
-
142
- function triggerSwitchHaptic() {
143
- getHapticSwitch().click();
144
- }
145
-
146
120
  // Extend Window interface for TypeScript
147
121
  declare global {
148
122
  interface Window {
@@ -1,167 +0,0 @@
1
- import { Separator } from './chunk-NWZGSLPU.js';
2
- import { Skeleton } from './chunk-XBBEX4SF.js';
3
- import { cn } from './chunk-FEK5XGZW.js';
4
- import { __objRest, __spreadValues } from './chunk-MMUBH76A.js';
5
- import { Star, Clock, Check, MessageSquare, ChevronRight } from 'lucide-react';
6
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
-
8
- function DefaultLink(_a) {
9
- var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
10
- return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
11
- }
12
- function MenuKitchenList({
13
- kitchens,
14
- labels,
15
- onShowMore,
16
- linkComponent = DefaultLink,
17
- className
18
- }) {
19
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", className), children: [
20
- /* @__PURE__ */ jsx("ol", { children: kitchens.map((kitchen, index) => /* @__PURE__ */ jsxs("li", { className: "[&:first-child>div]:pt-0", children: [
21
- index > 0 && /* @__PURE__ */ jsx(Separator, {}),
22
- /* @__PURE__ */ jsx(KitchenRow, { kitchen, labels, linkComponent })
23
- ] }, kitchen.place.slug)) }),
24
- onShowMore && labels.showMore && /* @__PURE__ */ jsx(
25
- "button",
26
- {
27
- type: "button",
28
- onClick: onShowMore,
29
- className: "mt-2 self-start rounded-md py-2 text-[13px] font-bold text-accent transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none",
30
- children: labels.showMore
31
- }
32
- )
33
- ] });
34
- }
35
- function KitchenRow({
36
- kitchen,
37
- labels,
38
- linkComponent: LinkComponent
39
- }) {
40
- const { place, dish } = kitchen;
41
- const openNow = place.open_now === true;
42
- return /* @__PURE__ */ jsxs("div", { className: "relative flex flex-wrap items-center gap-[11px] py-3 transition-colors hover:bg-muted/30 motion-reduce:transition-none lg:flex-nowrap lg:gap-4 lg:py-3.5", children: [
43
- /* @__PURE__ */ jsx(
44
- LinkComponent,
45
- {
46
- href: kitchen.href,
47
- "aria-label": labels.openVenue(place.name),
48
- className: "absolute inset-0 z-[1] rounded-xl focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
49
- }
50
- ),
51
- /* @__PURE__ */ jsxs("span", { className: "relative h-[46px] w-[46px] shrink-0 overflow-hidden rounded-[11px] bg-[repeating-linear-gradient(135deg,oklch(0.78_0.018_55)_0_8px,oklch(0.84_0.012_58)_8px_16px)] lg:h-[58px] lg:w-[58px] lg:rounded-[13px]", children: [
52
- place.thumbnail_url && // eslint-disable-next-line @next/next/no-img-element
53
- /* @__PURE__ */ jsx(
54
- "img",
55
- {
56
- src: place.thumbnail_url,
57
- alt: "",
58
- loading: "lazy",
59
- decoding: "async",
60
- className: "h-full w-full object-cover"
61
- }
62
- ),
63
- /* @__PURE__ */ jsx(
64
- "span",
65
- {
66
- title: openNow ? labels.openNow : void 0,
67
- className: cn(
68
- "absolute right-[5px] top-[5px] h-[7px] w-[7px] rounded-full ring-2 ring-white/85",
69
- openNow ? "bg-[var(--free,oklch(0.55_0.13_155))]" : "bg-[oklch(0.8_0.01_60)]"
70
- )
71
- }
72
- )
73
- ] }),
74
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 lg:w-[226px] lg:flex-none", children: [
75
- /* @__PURE__ */ jsx("span", { className: "truncate text-[14.5px] font-bold tracking-[-0.01em] lg:line-clamp-2 lg:whitespace-normal lg:text-[15.5px] lg:leading-tight", children: place.name }),
76
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 truncate text-xs text-muted-foreground", children: [
77
- place.rating && /* @__PURE__ */ jsxs(Fragment, { children: [
78
- /* @__PURE__ */ jsx(Star, { className: "h-[11px] w-[11px] shrink-0", "aria-hidden": true }),
79
- place.rating.rating,
80
- kitchen.metaLabel && " \xB7 "
81
- ] }),
82
- kitchen.metaLabel
83
- ] }),
84
- kitchen.hoursLabel && /* @__PURE__ */ jsxs(
85
- "span",
86
- {
87
- className: cn(
88
- "mt-[3px] inline-flex h-[21px] w-max items-center gap-[5px] rounded-md px-2 text-[10.5px] font-bold",
89
- openNow ? "bg-[oklch(0.96_0.02_155)] text-[var(--free,oklch(0.45_0.13_155))]" : "bg-muted text-muted-foreground"
90
- ),
91
- children: [
92
- /* @__PURE__ */ jsx(Clock, { className: "h-2.5 w-2.5 shrink-0", "aria-hidden": true }),
93
- kitchen.hoursLabel
94
- ]
95
- }
96
- )
97
- ] }),
98
- dish && /* DESKTOP ONLY, where it is a column of its own beside the venue.
99
- On the phone it wrapped to a third line under the row — kicker, dish,
100
- mention count — which turned a four-line venue row into a seven-line
101
- block and, ten rows down, buried the venue names the list exists to
102
- be scanned for. The dish is not what a reader is choosing here; it is
103
- one tap away on the venue's own page, with room to state it.
104
-
105
- `order-5` puts it last in the visual order without moving it in the
106
- DOM, where it belongs to the venue. */
107
- /* @__PURE__ */ jsxs("div", { className: "hidden min-w-0 basis-full pl-[57px] lg:order-none lg:block lg:flex-1 lg:basis-auto lg:pl-0", children: [
108
- /* @__PURE__ */ jsxs(
109
- "span",
110
- {
111
- className: cn(
112
- "flex items-center gap-1.5 text-[9px] font-extrabold uppercase tracking-[0.1em]",
113
- dish.matched ? "text-accent" : "text-[oklch(0.72_0.01_60)]"
114
- ),
115
- children: [
116
- dish.kicker,
117
- dish.matched && dish.matchLabel && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 rounded-[5px] bg-accent-subtle px-1.5 py-px text-[10.5px] font-bold normal-case tracking-normal text-accent", children: [
118
- /* @__PURE__ */ jsx(Check, { className: "h-2.5 w-2.5 shrink-0", "aria-hidden": true }),
119
- dish.matchLabel
120
- ] })
121
- ]
122
- }
123
- ),
124
- dish.href ? /* @__PURE__ */ jsx(
125
- LinkComponent,
126
- {
127
- href: dish.href,
128
- "aria-label": labels.openDish(dish.name),
129
- className: "relative z-[2] mt-0.5 block truncate font-serif text-[13.5px] italic underline decoration-[oklch(0.84_0.01_60)] decoration-1 underline-offset-[3px] transition-colors hover:text-accent hover:decoration-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none lg:text-[15px]",
130
- children: dish.name
131
- }
132
- ) : /* @__PURE__ */ jsx("span", { className: "mt-0.5 block truncate font-serif text-[13.5px] italic lg:text-[15px]", children: dish.name }),
133
- dish.meta && /* @__PURE__ */ jsxs("span", { className: "mt-[3px] flex items-center gap-1 text-[11.5px] text-muted-foreground", children: [
134
- !dish.matched && /* @__PURE__ */ jsx(MessageSquare, { className: "h-2.5 w-2.5 shrink-0", "aria-hidden": true }),
135
- dish.meta
136
- ] })
137
- ] }),
138
- /* @__PURE__ */ jsxs("div", { className: "ml-auto flex shrink-0 items-center gap-[11px] lg:ml-0", children: [
139
- kitchen.priceLabel && /* @__PURE__ */ jsx("span", { className: "text-base font-extrabold tabular-nums text-accent", children: kitchen.priceLabel }),
140
- /* @__PURE__ */ jsx(ChevronRight, { className: "h-[15px] w-[15px] shrink-0 text-muted-foreground", "aria-hidden": true })
141
- ] })
142
- ] });
143
- }
144
- function MenuKitchenListSkeleton({
145
- rows = 10,
146
- className
147
- }) {
148
- return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, index) => /* @__PURE__ */ jsxs("div", { children: [
149
- index > 0 && /* @__PURE__ */ jsx(Separator, {}),
150
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-[11px] py-3 lg:flex-nowrap lg:gap-4 lg:py-3.5", children: [
151
- /* @__PURE__ */ jsx(Skeleton, { className: "h-[46px] w-[46px] rounded-[11px] lg:h-[58px] lg:w-[58px] lg:rounded-[13px]" }),
152
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5 lg:w-[226px] lg:flex-none", children: [
153
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-[60%]" }),
154
- /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-[45%]" }),
155
- /* @__PURE__ */ jsx(Skeleton, { className: "h-[21px] w-[120px] rounded-md" })
156
- ] }),
157
- /* @__PURE__ */ jsxs("div", { className: "hidden min-w-0 basis-full pl-[57px] lg:order-none lg:block lg:flex-1 lg:basis-auto lg:pl-0", children: [
158
- /* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-[90px]" }),
159
- /* @__PURE__ */ jsx(Skeleton, { className: "mt-1.5 h-4 w-[70%]" }),
160
- /* @__PURE__ */ jsx(Skeleton, { className: "mt-1.5 h-3 w-[40%]" })
161
- ] }),
162
- /* @__PURE__ */ jsx(Skeleton, { className: "ml-auto h-5 w-[56px] lg:ml-0" })
163
- ] })
164
- ] }, index)) });
165
- }
166
-
167
- export { MenuKitchenList, MenuKitchenListSkeleton };