@bearmenu/ui 0.8.49 → 0.8.51
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.
- package/dist/{chunk-QY66ME5B.js → chunk-CZ2HC7WY.js} +24 -6
- package/dist/components/alert.d.ts +2 -2
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/banner.d.ts +1 -1
- package/dist/components/button.d.ts +2 -2
- package/dist/components/card.d.ts +2 -2
- package/dist/components/command.d.ts +15 -15
- package/dist/components/concept-compare.d.ts +1 -1
- package/dist/components/doorway-tiles.d.ts +1 -1
- package/dist/components/empty-state.d.ts +2 -2
- package/dist/components/event-detail-panel.d.ts +12 -2
- package/dist/components/event-detail-panel.js +15 -3
- package/dist/components/grade-atom.d.ts +1 -1
- package/dist/components/kitchen-dossier.d.ts +1 -1
- package/dist/components/menu-dead-end.d.ts +1 -1
- package/dist/components/menu-family-block.d.ts +2 -2
- package/dist/components/menu-family-block.js +3 -1
- package/dist/components/menu-family-card.d.ts +1 -1
- package/dist/components/menu-filter-chips.d.ts +1 -1
- package/dist/components/menu-group-rows.d.ts +1 -1
- package/dist/components/menu-index-header.d.ts +1 -1
- package/dist/components/menu-index-list.d.ts +1 -1
- package/dist/components/menu-intent-hero.d.ts +1 -1
- package/dist/components/menu-item.d.ts +1 -1
- package/dist/components/menu-kitchen-list.d.ts +9 -2
- package/dist/components/menu-kitchen-list.js +3 -1
- package/dist/components/menu-mocks.d.ts +1 -1
- package/dist/components/menu-types.d.ts +1 -1
- package/dist/components/open-now-list.d.ts +1 -1
- package/dist/components/place-about-tab.d.ts +1 -1
- package/dist/components/place-card.d.ts +1 -1
- package/dist/components/place-details-mobile.d.ts +1 -1
- package/dist/components/place-schedule-week.d.ts +1 -1
- package/dist/components/place-types.d.ts +1 -1
- package/dist/components/qa-block.d.ts +1 -1
- package/dist/components/sliding-panels.d.ts +6 -0
- package/dist/components/sliding-panels.js +13 -3
- package/dist/components/spinner.d.ts +2 -2
- package/dist/components/tag.d.ts +2 -2
- package/dist/components/text.d.ts +2 -2
- package/dist/components/top-comparison.d.ts +1 -1
- package/dist/components/top-cross-link.d.ts +1 -1
- package/dist/components/top-ranking-entry.d.ts +1 -1
- package/dist/components/top-ranking-hero.d.ts +1 -1
- package/dist/components/top-types.d.ts +1 -1
- package/dist/components/venue-grade-dimensions.d.ts +1 -1
- package/dist/components/venue-quotes.d.ts +1 -1
- package/dist/components/venue-wall.d.ts +1 -1
- package/dist/{place-types-DCVqWmk_.d.ts → place-types-Dzy6FH67.d.ts} +1 -1
- package/package.json +23 -217
- package/src/components/event-detail-panel.test.tsx +35 -0
- package/src/components/event-detail-panel.tsx +32 -10
- package/src/components/menu-kitchen-list.test.tsx +39 -0
- package/src/components/menu-kitchen-list.tsx +36 -7
- package/src/components/sliding-panels.test.tsx +26 -4
- package/src/components/sliding-panels.tsx +15 -4
|
@@ -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
|
|
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 && (
|
|
@@ -18,10 +18,7 @@ const basePanels: Panel[] = [
|
|
|
18
18
|
const panelWrappers = () =>
|
|
19
19
|
Array.from(document.querySelectorAll<HTMLElement>('[data-slot="sliding-panel"]'));
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
// with no text content.
|
|
23
|
-
const backButton = () =>
|
|
24
|
-
screen.getAllByRole("button").filter((button) => button.textContent === "")[0];
|
|
21
|
+
const backButton = () => screen.getByRole("button", { name: "Back" });
|
|
25
22
|
|
|
26
23
|
function Controlled({ initial = "one" }: { initial?: string }) {
|
|
27
24
|
const [current, setCurrent] = useState(initial);
|
|
@@ -113,4 +110,29 @@ describe("SlidingPanels", () => {
|
|
|
113
110
|
await user.click(backButton());
|
|
114
111
|
expect(onPanelChange).toHaveBeenCalledWith("root");
|
|
115
112
|
});
|
|
113
|
+
|
|
114
|
+
it("names the icon-only back button with backAriaLabel", () => {
|
|
115
|
+
const panels: Panel[] = [
|
|
116
|
+
{ id: "root", content: <button type="button">Root</button> },
|
|
117
|
+
{
|
|
118
|
+
id: "child",
|
|
119
|
+
showBackButton: true,
|
|
120
|
+
backButtonLabel: "Categorii",
|
|
121
|
+
backAriaLabel: "Înapoi",
|
|
122
|
+
content: <button type="button">Child</button>,
|
|
123
|
+
},
|
|
124
|
+
];
|
|
125
|
+
render(<SlidingPanels panels={panels} currentPanel="child" onPanelChange={vi.fn()} />);
|
|
126
|
+
// The heading beside it is the panel title, not the button's name
|
|
127
|
+
expect(screen.getByRole("button", { name: "Înapoi" })).toBeInTheDocument();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("drops the slide and height transitions under reduced motion", () => {
|
|
131
|
+
render(<Controlled initial="two" />);
|
|
132
|
+
const container = document.querySelector<HTMLElement>('[data-slot="sliding-panels"]');
|
|
133
|
+
expect(container?.className).toContain("motion-reduce:transition-none");
|
|
134
|
+
for (const panel of panelWrappers()) {
|
|
135
|
+
expect(panel.className).toContain("motion-reduce:transition-none");
|
|
136
|
+
}
|
|
137
|
+
});
|
|
116
138
|
});
|
|
@@ -10,7 +10,13 @@ export interface Panel {
|
|
|
10
10
|
id: string;
|
|
11
11
|
content: React.ReactNode;
|
|
12
12
|
showBackButton?: boolean;
|
|
13
|
+
/** Heading shown next to the back button (the panel's title, not the button's name). */
|
|
13
14
|
backButtonLabel?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Accessible name of the icon-only back button, localized by the caller.
|
|
17
|
+
* Falls back to "Back"; without a name screen readers announce only "button".
|
|
18
|
+
*/
|
|
19
|
+
backAriaLabel?: string;
|
|
14
20
|
onBack?: () => void;
|
|
15
21
|
// When set, the panel is treated as a child of `parentId`. Siblings (panels
|
|
16
22
|
// sharing the same parent) stay off-screen on the right when not active —
|
|
@@ -84,7 +90,7 @@ export const SlidingPanels = ({
|
|
|
84
90
|
<div
|
|
85
91
|
data-slot="sliding-panels"
|
|
86
92
|
className={cn(
|
|
87
|
-
"relative overflow-clip transition-[height] duration-500 ease-[cubic-bezier(0.32,0.72,0,1)]",
|
|
93
|
+
"relative overflow-clip transition-[height] duration-500 ease-[cubic-bezier(0.32,0.72,0,1)] motion-reduce:transition-none",
|
|
88
94
|
className
|
|
89
95
|
)}
|
|
90
96
|
style={{ height: containerHeight, overflowClipMargin: "8px" }}
|
|
@@ -105,7 +111,7 @@ export const SlidingPanels = ({
|
|
|
105
111
|
data-slot="sliding-panel"
|
|
106
112
|
data-state={isActive ? "active" : "inactive"}
|
|
107
113
|
className={cn(
|
|
108
|
-
"absolute top-0 left-0 w-full transition-transform duration-500 ease-[cubic-bezier(0.32,0.72,0,1)]",
|
|
114
|
+
"absolute top-0 left-0 w-full transition-transform duration-500 ease-[cubic-bezier(0.32,0.72,0,1)] motion-reduce:transition-none",
|
|
109
115
|
isActive && "translate-x-0",
|
|
110
116
|
isLeft && "-translate-x-[calc(100%+8px)]",
|
|
111
117
|
isRight && "translate-x-[calc(100%+8px)]"
|
|
@@ -125,8 +131,13 @@ export const SlidingPanels = ({
|
|
|
125
131
|
>
|
|
126
132
|
{panel.showBackButton && (
|
|
127
133
|
<div className="flex items-center gap-2 mb-4">
|
|
128
|
-
<Button
|
|
129
|
-
|
|
134
|
+
<Button
|
|
135
|
+
variant="ghost"
|
|
136
|
+
size="icon"
|
|
137
|
+
onClick={handleBack}
|
|
138
|
+
aria-label={panel.backAriaLabel ?? "Back"}
|
|
139
|
+
>
|
|
140
|
+
<ChevronLeft className="h-4 w-4" aria-hidden />
|
|
130
141
|
</Button>
|
|
131
142
|
{panel.backButtonLabel && (
|
|
132
143
|
<h3 className="font-semibold">{panel.backButtonLabel}</h3>
|