@bearmenu/ui 0.8.47 → 0.8.49
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/components/alert.d.ts +2 -2
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +2 -2
- package/dist/components/coach-marks.d.ts +1 -0
- package/dist/components/coach-marks.js +30 -17
- package/dist/components/command.d.ts +3 -3
- package/dist/components/concept-compare.d.ts +1 -1
- package/dist/components/doorway-tiles.d.ts +1 -1
- 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 +1 -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 +1 -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-card.js +13 -5
- 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/spinner.d.ts +2 -2
- package/dist/components/tag.d.ts +2 -2
- package/dist/components/text.d.ts +2 -2
- package/dist/components/toggle.d.ts +1 -1
- 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-C4rR3LTs.d.ts → place-types-DCVqWmk_.d.ts} +11 -0
- package/package.json +217 -23
- package/src/components/coach-marks.test.tsx +1 -1
- package/src/components/coach-marks.tsx +28 -16
- package/src/components/place-card.stories.tsx +36 -0
- package/src/components/place-card.test.tsx +29 -0
- package/src/components/place-card.tsx +24 -5
- package/src/components/place-types.ts +11 -0
|
@@ -3,10 +3,10 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const alertVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "success" | "warning" | "default" | "destructive" | null | undefined;
|
|
7
7
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
8
8
|
declare const Alert: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & VariantProps<(props?: ({
|
|
9
|
-
variant?: "
|
|
9
|
+
variant?: "success" | "warning" | "default" | "destructive" | null | undefined;
|
|
10
10
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & React.RefAttributes<HTMLDivElement>>;
|
|
11
11
|
declare const AlertTitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLParagraphElement>>;
|
|
12
12
|
declare const AlertDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>>;
|
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
import { VariantProps } from 'class-variance-authority';
|
|
5
5
|
|
|
6
6
|
declare const badgeVariants: (props?: ({
|
|
7
|
-
variant?: "secondary" | "
|
|
7
|
+
variant?: "secondary" | "success" | "warning" | "default" | "destructive" | "outline" | "glass" | "overlay" | "brown" | "code" | "onPrimary" | "confirmed" | "pending" | "completed" | "assignee" | "softSuccess" | "softWarning" | "softDestructive" | "softNeutral" | null | undefined;
|
|
8
8
|
size?: "status" | "chip" | null | undefined;
|
|
9
9
|
live?: boolean | null | undefined;
|
|
10
10
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
@@ -3,8 +3,8 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
7
|
-
size?: "
|
|
6
|
+
variant?: "link" | "secondary" | "warning" | "default" | "destructive" | "outline" | "ghost" | "glass" | "overlay" | "ink" | "brown" | "cta" | null | undefined;
|
|
7
|
+
size?: "icon" | "default" | "cta" | "xs" | "sm" | "lg" | "pill" | "cta-sm" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
|
|
8
8
|
fullWidth?: boolean | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
10
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
@@ -5,7 +5,7 @@ import { cn } from '../chunk-FEK5XGZW.js';
|
|
|
5
5
|
import '../chunk-MMUBH76A.js';
|
|
6
6
|
import { useState, useLayoutEffect, useCallback, useRef, useEffect } from 'react';
|
|
7
7
|
import { createPortal } from 'react-dom';
|
|
8
|
-
import { Lightbulb, ArrowRight } from 'lucide-react';
|
|
8
|
+
import { Lightbulb, X, ArrowRight } from 'lucide-react';
|
|
9
9
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
10
10
|
|
|
11
11
|
var PAD = 8;
|
|
@@ -203,14 +203,38 @@ function CoachMarks({
|
|
|
203
203
|
style: { left: caretLeft }
|
|
204
204
|
}
|
|
205
205
|
),
|
|
206
|
-
/* @__PURE__ */ jsxs("
|
|
207
|
-
/* @__PURE__ */
|
|
208
|
-
|
|
206
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
207
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-full bg-[oklch(0.82_0.15_85)] px-2.5 py-1 text-xs font-extrabold uppercase tracking-[0.08em] text-[oklch(0.26_0.03_60)]", children: [
|
|
208
|
+
/* @__PURE__ */ jsx(Lightbulb, { className: "h-3 w-3", "aria-hidden": true }),
|
|
209
|
+
labels.progress(index + 1, available.length)
|
|
210
|
+
] }),
|
|
211
|
+
/* @__PURE__ */ jsx(
|
|
212
|
+
Button,
|
|
213
|
+
{
|
|
214
|
+
type: "button",
|
|
215
|
+
variant: "ghost",
|
|
216
|
+
size: "icon",
|
|
217
|
+
className: "-my-2.5 -mr-2.5 shrink-0 text-muted-foreground hover:text-foreground",
|
|
218
|
+
"aria-label": labels.skip,
|
|
219
|
+
onClick: onClose,
|
|
220
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4", "aria-hidden": true })
|
|
221
|
+
}
|
|
222
|
+
)
|
|
209
223
|
] }),
|
|
210
224
|
/* @__PURE__ */ jsx("p", { className: "mt-3 text-base font-semibold leading-snug", children: current.title }),
|
|
211
225
|
/* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: current.body }),
|
|
212
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-2", children: [
|
|
213
|
-
index > 0 && /* @__PURE__ */ jsx(
|
|
226
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-4 flex flex-wrap items-center justify-end gap-2", children: [
|
|
227
|
+
index > 0 && /* @__PURE__ */ jsx(
|
|
228
|
+
Button,
|
|
229
|
+
{
|
|
230
|
+
type: "button",
|
|
231
|
+
variant: "ghost",
|
|
232
|
+
size: "pill",
|
|
233
|
+
className: "mr-auto",
|
|
234
|
+
onClick: () => setIndex(index - 1),
|
|
235
|
+
children: labels.back
|
|
236
|
+
}
|
|
237
|
+
),
|
|
214
238
|
/* @__PURE__ */ jsxs(
|
|
215
239
|
Button,
|
|
216
240
|
{
|
|
@@ -222,17 +246,6 @@ function CoachMarks({
|
|
|
222
246
|
!last && /* @__PURE__ */ jsx(ArrowRight, { "aria-hidden": true })
|
|
223
247
|
]
|
|
224
248
|
}
|
|
225
|
-
),
|
|
226
|
-
/* @__PURE__ */ jsx(
|
|
227
|
-
Button,
|
|
228
|
-
{
|
|
229
|
-
type: "button",
|
|
230
|
-
variant: "link",
|
|
231
|
-
size: "sm",
|
|
232
|
-
className: "ml-auto min-h-11",
|
|
233
|
-
onClick: onClose,
|
|
234
|
-
children: labels.skip
|
|
235
|
-
}
|
|
236
249
|
)
|
|
237
250
|
] })
|
|
238
251
|
]
|
|
@@ -28,7 +28,7 @@ declare const CommandInput: React.ForwardRefExoticComponent<Omit<Omit<Pick<Pick<
|
|
|
28
28
|
ref?: React.Ref<HTMLInputElement>;
|
|
29
29
|
} & {
|
|
30
30
|
asChild?: boolean;
|
|
31
|
-
}, "asChild" | "key" | keyof React.InputHTMLAttributes<HTMLInputElement>>, "
|
|
31
|
+
}, "asChild" | "key" | keyof React.InputHTMLAttributes<HTMLInputElement>>, "value" | "onChange" | "type"> & {
|
|
32
32
|
value?: string;
|
|
33
33
|
onValueChange?: (search: string) => void;
|
|
34
34
|
} & React.RefAttributes<HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
@@ -64,7 +64,7 @@ declare const CommandGroup: React.ForwardRefExoticComponent<Omit<{
|
|
|
64
64
|
ref?: React.Ref<HTMLDivElement>;
|
|
65
65
|
} & {
|
|
66
66
|
asChild?: boolean;
|
|
67
|
-
}, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "
|
|
67
|
+
}, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "value" | "heading"> & {
|
|
68
68
|
heading?: React.ReactNode;
|
|
69
69
|
value?: string;
|
|
70
70
|
forceMount?: boolean;
|
|
@@ -82,7 +82,7 @@ declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
|
|
|
82
82
|
ref?: React.Ref<HTMLDivElement>;
|
|
83
83
|
} & {
|
|
84
84
|
asChild?: boolean;
|
|
85
|
-
}, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "
|
|
85
|
+
}, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "value" | "onSelect" | "disabled"> & {
|
|
86
86
|
disabled?: boolean;
|
|
87
87
|
onSelect?: (value: string) => void;
|
|
88
88
|
value?: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { MenuConceptPreview, MenuLinkComponent, MenuLinkProps } from './menu-types.js';
|
|
3
3
|
import 'react';
|
|
4
|
-
import '../place-types-
|
|
4
|
+
import '../place-types-DCVqWmk_.js';
|
|
5
5
|
import '../lib/grade.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import 'react/jsx-runtime';
|
|
2
2
|
import '../lib/grade.js';
|
|
3
|
-
export { G as GradeAtom, h as GradeAtomLabels, i as GradeAtomProps, j as GradeAtomSize } from '../place-types-
|
|
3
|
+
export { G as GradeAtom, h as GradeAtomLabels, i as GradeAtomProps, j as GradeAtomSize } from '../place-types-DCVqWmk_.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { MenuVenueSignature, MenuLinkComponent, MenuLinkProps } from './menu-types.js';
|
|
4
|
-
import { P as PlacePreview, C as CitedText, a as PlaceGradeDimensions } from '../place-types-
|
|
4
|
+
import { P as PlacePreview, C as CitedText, a as PlaceGradeDimensions } from '../place-types-DCVqWmk_.js';
|
|
5
5
|
import { VenueGradeDimensionKey } from './venue-grade-dimensions.js';
|
|
6
6
|
import '../lib/grade.js';
|
|
7
7
|
|
|
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { MenuKitchenListLabels } from './menu-kitchen-list.js';
|
|
3
3
|
import { MenuFamilyBlockPreview, MenuLinkComponent, MenuLinkProps } from './menu-types.js';
|
|
4
4
|
import 'react';
|
|
5
|
-
import '../place-types-
|
|
5
|
+
import '../place-types-DCVqWmk_.js';
|
|
6
6
|
import '../lib/grade.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { MenuFamilyPreview, MenuLinkComponent, MenuLinkProps } from './menu-types.js';
|
|
3
3
|
import 'react';
|
|
4
|
-
import '../place-types-
|
|
4
|
+
import '../place-types-DCVqWmk_.js';
|
|
5
5
|
import '../lib/grade.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { MenuIndexEntry, MenuLinkComponent } from './menu-types.js';
|
|
3
3
|
import 'react';
|
|
4
|
-
import '../place-types-
|
|
4
|
+
import '../place-types-DCVqWmk_.js';
|
|
5
5
|
import '../lib/grade.js';
|
|
6
6
|
|
|
7
7
|
type MenuIndexHeaderProps = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { MenuIndexEntry, MenuLinkComponent, MenuLinkProps } from './menu-types.js';
|
|
3
3
|
import 'react';
|
|
4
|
-
import '../place-types-
|
|
4
|
+
import '../place-types-DCVqWmk_.js';
|
|
5
5
|
import '../lib/grade.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
3
|
import { MenuItemPreview, MenuLinkComponent, MenuLinkProps } from './menu-types.js';
|
|
4
|
-
import '../place-types-
|
|
4
|
+
import '../place-types-DCVqWmk_.js';
|
|
5
5
|
import '../lib/grade.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { MenuKitchenPreview, MenuLinkComponent, MenuLinkProps } from './menu-types.js';
|
|
3
3
|
import 'react';
|
|
4
|
-
import '../place-types-
|
|
4
|
+
import '../place-types-DCVqWmk_.js';
|
|
5
5
|
import '../lib/grade.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MenuFamilyBlockPreview, MenuConceptPreview, MenuFamilyPreview, MenuFilterChip, MenuIndexEntry, MenuIntentFigure, MenuItemPreview, MenuKitchenPreview, MenuLoosenOption, QaItem, MenuVenuePreview } from './menu-types.js';
|
|
2
2
|
import { DoorwayTile } from './doorway-tiles.js';
|
|
3
|
-
import { P as PlacePreview } from '../place-types-
|
|
3
|
+
import { P as PlacePreview } from '../place-types-DCVqWmk_.js';
|
|
4
4
|
import 'react';
|
|
5
5
|
import 'react/jsx-runtime';
|
|
6
6
|
import '../lib/grade.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComponentType, CSSProperties, ReactNode } from 'react';
|
|
2
|
-
import { M as MenuSizeAndPrice, P as PlacePreview } from '../place-types-
|
|
2
|
+
import { M as MenuSizeAndPrice, P as PlacePreview } from '../place-types-DCVqWmk_.js';
|
|
3
3
|
import 'react/jsx-runtime';
|
|
4
4
|
import '../lib/grade.js';
|
|
5
5
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { MenuVenuePreview, MenuLinkComponent, MenuLinkProps } from './menu-types.js';
|
|
3
3
|
import 'react';
|
|
4
|
-
import '../place-types-
|
|
4
|
+
import '../place-types-DCVqWmk_.js';
|
|
5
5
|
import '../lib/grade.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { P as PlacePreview, b as PlaceAboutTabLabels, c as PlaceLinkKind } from '../place-types-
|
|
2
|
+
import { P as PlacePreview, b as PlaceAboutTabLabels, c as PlaceLinkKind } from '../place-types-DCVqWmk_.js';
|
|
3
3
|
import '../lib/grade.js';
|
|
4
4
|
|
|
5
5
|
interface PlaceAboutTabProps {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as React$1 from 'react';
|
|
3
3
|
import { ReactNode, MouseEvent } from 'react';
|
|
4
|
-
import { P as PlacePreview, d as PlaceCardLabels } from '../place-types-
|
|
4
|
+
import { P as PlacePreview, d as PlaceCardLabels } from '../place-types-DCVqWmk_.js';
|
|
5
5
|
import '../lib/grade.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -56,6 +56,10 @@ function PriceLevel({ level, label }) {
|
|
|
56
56
|
/* @__PURE__ */ jsx("span", { className: "opacity-30", children: "$".repeat(4 - filled) })
|
|
57
57
|
] });
|
|
58
58
|
}
|
|
59
|
+
function launchYear(launchedAt) {
|
|
60
|
+
const match = launchedAt ? /^(\d{4})-\d{2}$/.exec(launchedAt) : null;
|
|
61
|
+
return match ? Number(match[1]) : void 0;
|
|
62
|
+
}
|
|
59
63
|
var STATIC_ROOT_CLASSES = `group relative flex w-full select-none flex-col ${HOVER_MOTION} ${HOVER_LIFT_GRID_GROUP}`;
|
|
60
64
|
var ROOT_CLASSES = `${STATIC_ROOT_CLASSES} cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:rounded-xl`;
|
|
61
65
|
var DEFAULT_SIZES = "(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw";
|
|
@@ -72,7 +76,7 @@ var PlaceCard = memo(function PlaceCard2({
|
|
|
72
76
|
photoOverlay,
|
|
73
77
|
className
|
|
74
78
|
}) {
|
|
75
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
79
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
76
80
|
const [imgError, setImgError] = useState(false);
|
|
77
81
|
const MotionLink = useMemo(() => motion.create(LinkComponent), [LinkComponent]);
|
|
78
82
|
const coverUrl = imgError ? void 0 : place.cover_url;
|
|
@@ -81,6 +85,8 @@ var PlaceCard = memo(function PlaceCard2({
|
|
|
81
85
|
const neighbourhood = (_e = (_d = place.areas) == null ? void 0 : _d[0]) == null ? void 0 : _e.name;
|
|
82
86
|
const priceLevel = (_h = (_f = place.price_dishes) == null ? void 0 : _f.price_score) != null ? _h : (_g = place.price_drinks) == null ? void 0 : _g.price_score;
|
|
83
87
|
const showPrice = priceLevel !== void 0 && priceLevel > 0;
|
|
88
|
+
const year = labels.established ? launchYear(place.launched_at) : void 0;
|
|
89
|
+
const established = year !== void 0 ? (_i = labels.established) == null ? void 0 : _i.call(labels, year) : void 0;
|
|
84
90
|
const ariaLabel = labels.viewDetails(place.name);
|
|
85
91
|
const handleKeyDown = (e) => {
|
|
86
92
|
if (e.key === "Enter" || e.key === " ") {
|
|
@@ -145,10 +151,12 @@ var PlaceCard = memo(function PlaceCard2({
|
|
|
145
151
|
/* @__PURE__ */ jsx(HeadlineRating, { place, labels })
|
|
146
152
|
] }),
|
|
147
153
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
148
|
-
(cuisine || showPrice) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
149
|
-
cuisine && /* @__PURE__ */ jsx("span", { className: "capitalize", children: cuisine }),
|
|
150
|
-
cuisine && showPrice && /* @__PURE__ */ jsx("span", { className: "text-border", children: "\xB7" }),
|
|
151
|
-
showPrice && /* @__PURE__ */ jsx(PriceLevel, { level: priceLevel, label: labels.priceLevel(priceLevel) })
|
|
154
|
+
(cuisine || showPrice || established) && /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
155
|
+
cuisine && /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate capitalize", children: cuisine }),
|
|
156
|
+
cuisine && showPrice && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-border", children: "\xB7" }),
|
|
157
|
+
showPrice && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: /* @__PURE__ */ jsx(PriceLevel, { level: priceLevel, label: labels.priceLevel(priceLevel) }) }),
|
|
158
|
+
established && (cuisine || showPrice) && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-border", children: "\xB7" }),
|
|
159
|
+
established && /* @__PURE__ */ jsx("span", { className: "shrink-0 whitespace-nowrap", children: established })
|
|
152
160
|
] }),
|
|
153
161
|
distance !== void 0 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
154
162
|
/* @__PURE__ */ jsx(MapPin, { className: "h-3 w-3 shrink-0", "aria-hidden": true }),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { P as PlacePreview, e as PlaceDetailsMobileLabels } from '../place-types-
|
|
2
|
+
import { P as PlacePreview, e as PlaceDetailsMobileLabels } from '../place-types-DCVqWmk_.js';
|
|
3
3
|
import '../lib/grade.js';
|
|
4
4
|
|
|
5
5
|
interface PlaceDetailsMobileProps {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { f as PlaceSchedule, g as PlaceScheduleWeekLabels } from '../place-types-
|
|
2
|
+
import { f as PlaceSchedule, g as PlaceScheduleWeekLabels } from '../place-types-DCVqWmk_.js';
|
|
3
3
|
import '../lib/grade.js';
|
|
4
4
|
|
|
5
5
|
interface PlaceScheduleWeekProps {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { C as CitedText, k as CitedValue, M as MenuSizeAndPrice, b as PlaceAboutTabLabels, d as PlaceCardLabels, e as PlaceDetailsMobileLabels, l as PlaceGrade, a as PlaceGradeDimensions, m as PlaceHourBlock, c as PlaceLinkKind, n as PlaceMustTry, P as PlacePreview, o as PlacePriceRange, p as PlaceReviewsDigest, f as PlaceSchedule, g as PlaceScheduleWeekLabels, W as WeekdayKey } from '../place-types-
|
|
1
|
+
export { C as CitedText, k as CitedValue, M as MenuSizeAndPrice, b as PlaceAboutTabLabels, d as PlaceCardLabels, e as PlaceDetailsMobileLabels, l as PlaceGrade, a as PlaceGradeDimensions, m as PlaceHourBlock, c as PlaceLinkKind, n as PlaceMustTry, P as PlacePreview, o as PlacePriceRange, p as PlaceReviewsDigest, f as PlaceSchedule, g as PlaceScheduleWeekLabels, W as WeekdayKey } from '../place-types-DCVqWmk_.js';
|
|
2
2
|
import 'react/jsx-runtime';
|
|
3
3
|
import '../lib/grade.js';
|
|
@@ -4,11 +4,11 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
4
4
|
|
|
5
5
|
declare const spinnerVariants: (props?: ({
|
|
6
6
|
size?: "default" | "xs" | "sm" | "lg" | "xl" | null | undefined;
|
|
7
|
-
tone?: "
|
|
7
|
+
tone?: "inherit" | "primary" | "default" | "destructive" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
declare const Spinner: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & VariantProps<(props?: ({
|
|
10
10
|
size?: "default" | "xs" | "sm" | "lg" | "xl" | null | undefined;
|
|
11
|
-
tone?: "
|
|
11
|
+
tone?: "inherit" | "primary" | "default" | "destructive" | null | undefined;
|
|
12
12
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & {
|
|
13
13
|
/** Visually-hidden label for screen readers. Defaults to "Loading". */
|
|
14
14
|
label?: string;
|
package/dist/components/tag.d.ts
CHANGED
|
@@ -3,11 +3,11 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const tagVariants: (props?: ({
|
|
6
|
-
variant?: "primary" | "
|
|
6
|
+
variant?: "primary" | "success" | "warning" | "default" | "destructive" | "outline" | "quiet" | null | undefined;
|
|
7
7
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
declare const Tag: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & VariantProps<(props?: ({
|
|
10
|
-
variant?: "primary" | "
|
|
10
|
+
variant?: "primary" | "success" | "warning" | "default" | "destructive" | "outline" | "quiet" | null | undefined;
|
|
11
11
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
12
12
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & {
|
|
13
13
|
onRemove?: () => void;
|
|
@@ -22,8 +22,8 @@ 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?: "
|
|
26
|
-
color?: "
|
|
25
|
+
variant?: "body" | "small" | "display" | "h2" | "h3" | "label" | "caption" | "h1" | "h4" | "body-lg" | "body-sm" | "overline" | null | undefined;
|
|
26
|
+
color?: "inherit" | "primary" | "default" | "destructive" | "muted" | "primary-foreground" | null | undefined;
|
|
27
27
|
weight?: "bold" | "medium" | "normal" | "semibold" | null | undefined;
|
|
28
28
|
leading?: "none" | "normal" | "tight" | "snug" | "relaxed" | "loose" | null | undefined;
|
|
29
29
|
tracking?: "normal" | "tight" | "wide" | "wider" | null | undefined;
|
|
@@ -11,7 +11,7 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
11
11
|
* `data-[state=on]:` utilities sort after `hover:` and still win while on.
|
|
12
12
|
*/
|
|
13
13
|
declare const toggleVariants: (props?: ({
|
|
14
|
-
variant?: "
|
|
14
|
+
variant?: "tab" | "default" | "outline" | "chip" | "segmented" | null | undefined;
|
|
15
15
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
16
16
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
17
17
|
/**
|
|
@@ -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-
|
|
5
|
+
import '../place-types-DCVqWmk_.js';
|
|
6
6
|
import '../lib/grade.js';
|
|
7
7
|
|
|
8
8
|
type TopComparisonLabels = {
|
|
@@ -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-
|
|
6
|
+
import '../place-types-DCVqWmk_.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-
|
|
5
|
+
import '../place-types-DCVqWmk_.js';
|
|
6
6
|
import '../lib/grade.js';
|
|
7
7
|
|
|
8
8
|
type TopRankingHeroProps = {
|
|
@@ -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-
|
|
3
|
+
import { P as PlacePreview } from '../place-types-DCVqWmk_.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
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bearmenu/ui",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.49",
|
|
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
|
-
"./
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"./hooks
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"./lib
|
|
29
|
-
|
|
30
|
-
|
|
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
|
+
}
|
|
@@ -127,7 +127,7 @@ describe("CoachMarks", () => {
|
|
|
127
127
|
it("Skip and Escape close; the dimmed page does not", () => {
|
|
128
128
|
const onClose = vi.fn();
|
|
129
129
|
render(<Page onClose={onClose} />);
|
|
130
|
-
fireEvent.click(screen.
|
|
130
|
+
fireEvent.click(screen.getByRole("button", { name: "Skip" }));
|
|
131
131
|
fireEvent.keyDown(window, { key: "Escape" });
|
|
132
132
|
expect(onClose).toHaveBeenCalledTimes(2);
|
|
133
133
|
expect(screen.getAllByRole("button", { name: "Skip" })).toHaveLength(1);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
5
|
-
import { ArrowRight, Lightbulb } from "lucide-react";
|
|
5
|
+
import { ArrowRight, Lightbulb, X } from "lucide-react";
|
|
6
6
|
import { cn } from "../lib/utils";
|
|
7
7
|
import { Button } from "./button";
|
|
8
8
|
|
|
@@ -86,6 +86,7 @@ export type CoachMarksLabels = {
|
|
|
86
86
|
next: string;
|
|
87
87
|
/** The last stop's forward action, e.g. "Done". */
|
|
88
88
|
done: string;
|
|
89
|
+
/** The corner X's accessible name, e.g. "Skip tour"; not drawn as text. */
|
|
89
90
|
skip: string;
|
|
90
91
|
};
|
|
91
92
|
|
|
@@ -374,15 +375,35 @@ export function CoachMarks({
|
|
|
374
375
|
style={{ left: caretLeft }}
|
|
375
376
|
/>
|
|
376
377
|
)}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
378
|
+
{/* Skip is chrome, not a step action: the corner X keeps the footer
|
|
379
|
+
to Back and Next, which fit the callout in any locale. */}
|
|
380
|
+
<div className="flex items-center justify-between gap-2">
|
|
381
|
+
<span className="inline-flex items-center gap-1.5 rounded-full bg-[oklch(0.82_0.15_85)] px-2.5 py-1 text-xs font-extrabold uppercase tracking-[0.08em] text-[oklch(0.26_0.03_60)]">
|
|
382
|
+
<Lightbulb className="h-3 w-3" aria-hidden />
|
|
383
|
+
{labels.progress(index + 1, available.length)}
|
|
384
|
+
</span>
|
|
385
|
+
<Button
|
|
386
|
+
type="button"
|
|
387
|
+
variant="ghost"
|
|
388
|
+
size="icon"
|
|
389
|
+
className="-my-2.5 -mr-2.5 shrink-0 text-muted-foreground hover:text-foreground"
|
|
390
|
+
aria-label={labels.skip}
|
|
391
|
+
onClick={onClose}
|
|
392
|
+
>
|
|
393
|
+
<X className="h-4 w-4" aria-hidden />
|
|
394
|
+
</Button>
|
|
395
|
+
</div>
|
|
381
396
|
<p className="mt-3 text-base font-semibold leading-snug">{current.title}</p>
|
|
382
397
|
<p className="mt-1.5 text-sm leading-relaxed text-muted-foreground">{current.body}</p>
|
|
383
|
-
<div className="mt-4 flex items-center gap-2">
|
|
398
|
+
<div className="mt-4 flex flex-wrap items-center justify-end gap-2">
|
|
384
399
|
{index > 0 && (
|
|
385
|
-
<Button
|
|
400
|
+
<Button
|
|
401
|
+
type="button"
|
|
402
|
+
variant="ghost"
|
|
403
|
+
size="pill"
|
|
404
|
+
className="mr-auto"
|
|
405
|
+
onClick={() => setIndex(index - 1)}
|
|
406
|
+
>
|
|
386
407
|
{labels.back}
|
|
387
408
|
</Button>
|
|
388
409
|
)}
|
|
@@ -394,15 +415,6 @@ export function CoachMarks({
|
|
|
394
415
|
{last ? labels.done : labels.next}
|
|
395
416
|
{!last && <ArrowRight aria-hidden />}
|
|
396
417
|
</Button>
|
|
397
|
-
<Button
|
|
398
|
-
type="button"
|
|
399
|
-
variant="link"
|
|
400
|
-
size="sm"
|
|
401
|
-
className="ml-auto min-h-11"
|
|
402
|
-
onClick={onClose}
|
|
403
|
-
>
|
|
404
|
-
{labels.skip}
|
|
405
|
-
</Button>
|
|
406
418
|
</div>
|
|
407
419
|
</div>
|
|
408
420
|
</div>,
|
|
@@ -10,6 +10,7 @@ const labels: PlaceCardLabels = {
|
|
|
10
10
|
closed: "Closed",
|
|
11
11
|
viewDetails: (name) => `View details for ${name}`,
|
|
12
12
|
priceLevel: (level) => `Price level ${level} of 4`,
|
|
13
|
+
established: (year) => String(year),
|
|
13
14
|
grade: {
|
|
14
15
|
soft: "Worth exploring",
|
|
15
16
|
bands: {
|
|
@@ -35,6 +36,7 @@ const basePlace: PlacePreview = {
|
|
|
35
36
|
price_dishes: { price_range_low: 35, price_range_high: 90, price_score: 2 },
|
|
36
37
|
reviews_digest: { grade: { overall: 8.4 } },
|
|
37
38
|
cover_url: "https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=800&q=80",
|
|
39
|
+
launched_at: "2020-02",
|
|
38
40
|
};
|
|
39
41
|
|
|
40
42
|
const meta = {
|
|
@@ -101,6 +103,40 @@ export const WithFooter: Story = {
|
|
|
101
103
|
},
|
|
102
104
|
};
|
|
103
105
|
|
|
106
|
+
/**
|
|
107
|
+
* The launch year closes the meta line, bare — fe's copy; `labels.established`
|
|
108
|
+
* may spell it out ("Est. 2020") where there is room. It is the backend's
|
|
109
|
+
* earliest-review estimate (`launched_at`, `YYYY-MM`). No year without the
|
|
110
|
+
* label or without a well-formed `launched_at`.
|
|
111
|
+
*/
|
|
112
|
+
export const Established: Story = {
|
|
113
|
+
args: { place: { ...basePlace, launched_at: "2012-09" } },
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/** 220px rail with a long cuisine and full price: the cuisine gives way, price and year never do. */
|
|
117
|
+
export const EstablishedNarrowRail: Story = {
|
|
118
|
+
args: {
|
|
119
|
+
place: { ...basePlace, cuisines: ["mediterranean"], price_dishes: { price_score: 4 } },
|
|
120
|
+
},
|
|
121
|
+
decorators: [
|
|
122
|
+
(Story) => (
|
|
123
|
+
<div className="w-[220px]">
|
|
124
|
+
<Story />
|
|
125
|
+
</div>
|
|
126
|
+
),
|
|
127
|
+
],
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/** Spelled out by the label, for a consumer with room for the word. */
|
|
131
|
+
export const EstablishedWithLabel: Story = {
|
|
132
|
+
args: { labels: { ...labels, established: (year) => `Est. ${year}` } },
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/** The year alone still gets a meta line: no cuisine, no price signal. */
|
|
136
|
+
export const EstablishedOnly: Story = {
|
|
137
|
+
args: { place: { ...basePlace, cuisines: undefined, price_dishes: undefined } },
|
|
138
|
+
};
|
|
139
|
+
|
|
104
140
|
export const Minimal: Story = {
|
|
105
141
|
args: { place: { id: "2", slug: "tiny", name: "The Tiny Spot" } },
|
|
106
142
|
};
|
|
@@ -9,6 +9,7 @@ const LABELS: PlaceCardLabels = {
|
|
|
9
9
|
closed: "Closed",
|
|
10
10
|
viewDetails: (name) => `View details for ${name}`,
|
|
11
11
|
priceLevel: (level) => `Price level ${level} of 4`,
|
|
12
|
+
established: (year) => `Est. ${year}`,
|
|
12
13
|
grade: {
|
|
13
14
|
soft: "Worth exploring",
|
|
14
15
|
bands: {
|
|
@@ -104,6 +105,34 @@ describe("PlaceCard", () => {
|
|
|
104
105
|
expect(screen.getByLabelText("Price level 2 of 4")).toBeInTheDocument();
|
|
105
106
|
});
|
|
106
107
|
|
|
108
|
+
it("closes the meta line with the launch year", () => {
|
|
109
|
+
render(
|
|
110
|
+
<PlaceCard
|
|
111
|
+
place={makePlace({ cuisines: ["italian"], launched_at: "2020-02" })}
|
|
112
|
+
labels={LABELS}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
expect(screen.getByText("Est. 2020")).toBeInTheDocument();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("shows the launch year on its own when there is no cuisine or price", () => {
|
|
119
|
+
const { container } = render(
|
|
120
|
+
<PlaceCard place={makePlace({ launched_at: "2012-09" })} labels={LABELS} />
|
|
121
|
+
);
|
|
122
|
+
expect(screen.getByText("Est. 2012")).toBeInTheDocument();
|
|
123
|
+
expect(container).not.toHaveTextContent("·");
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("shows no year without the label or a well-formed launched_at", () => {
|
|
127
|
+
const { established: _omit, ...withoutEstablished } = LABELS;
|
|
128
|
+
const { rerender } = render(
|
|
129
|
+
<PlaceCard place={makePlace({ launched_at: "2020-02" })} labels={withoutEstablished} />
|
|
130
|
+
);
|
|
131
|
+
expect(screen.queryByText(/2020/)).not.toBeInTheDocument();
|
|
132
|
+
rerender(<PlaceCard place={makePlace({ launched_at: "2020" })} labels={LABELS} />);
|
|
133
|
+
expect(screen.queryByText(/Est\./)).not.toBeInTheDocument();
|
|
134
|
+
});
|
|
135
|
+
|
|
107
136
|
it("clamps an out-of-range price level instead of throwing", () => {
|
|
108
137
|
render(<PlaceCard place={makePlace({ price_drinks: { price_score: 7 } })} labels={LABELS} />);
|
|
109
138
|
expect(screen.getByLabelText("Price level 7 of 4")).toHaveTextContent("$$$$");
|
|
@@ -169,6 +169,12 @@ function PriceLevel({ level, label }: { level: number; label: string }) {
|
|
|
169
169
|
);
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
/** The year out of the schema's `YYYY-MM`; anything else shows no year. */
|
|
173
|
+
function launchYear(launchedAt: string | undefined): number | undefined {
|
|
174
|
+
const match = launchedAt ? /^(\d{4})-\d{2}$/.exec(launchedAt) : null;
|
|
175
|
+
return match ? Number(match[1]) : undefined;
|
|
176
|
+
}
|
|
177
|
+
|
|
172
178
|
const STATIC_ROOT_CLASSES = `group relative flex w-full select-none flex-col ${HOVER_MOTION} ${HOVER_LIFT_GRID_GROUP}`;
|
|
173
179
|
const ROOT_CLASSES = `${STATIC_ROOT_CLASSES} cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:rounded-xl`;
|
|
174
180
|
|
|
@@ -202,6 +208,8 @@ export const PlaceCard = memo(function PlaceCard({
|
|
|
202
208
|
const neighbourhood = place.areas?.[0]?.name;
|
|
203
209
|
const priceLevel = place.price_dishes?.price_score ?? place.price_drinks?.price_score;
|
|
204
210
|
const showPrice = priceLevel !== undefined && priceLevel > 0;
|
|
211
|
+
const year = labels.established ? launchYear(place.launched_at) : undefined;
|
|
212
|
+
const established = year !== undefined ? labels.established?.(year) : undefined;
|
|
205
213
|
const ariaLabel = labels.viewDetails(place.name);
|
|
206
214
|
|
|
207
215
|
const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
|
|
@@ -277,11 +285,22 @@ export const PlaceCard = memo(function PlaceCard({
|
|
|
277
285
|
</div>
|
|
278
286
|
|
|
279
287
|
<div className="flex flex-col gap-0.5">
|
|
280
|
-
{
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
288
|
+
{/* Cuisine · price · launch year. At rail width the three can
|
|
289
|
+
outrun the card, so the cuisine is the part that gives way: the
|
|
290
|
+
price glyphs and the year are short and fixed. */}
|
|
291
|
+
{(cuisine || showPrice || established) && (
|
|
292
|
+
<div className="flex min-w-0 items-center gap-1.5 text-xs text-muted-foreground">
|
|
293
|
+
{cuisine && <span className="min-w-0 truncate capitalize">{cuisine}</span>}
|
|
294
|
+
{cuisine && showPrice && <span className="shrink-0 text-border">·</span>}
|
|
295
|
+
{showPrice && (
|
|
296
|
+
<span className="shrink-0">
|
|
297
|
+
<PriceLevel level={priceLevel} label={labels.priceLevel(priceLevel)} />
|
|
298
|
+
</span>
|
|
299
|
+
)}
|
|
300
|
+
{established && (cuisine || showPrice) && (
|
|
301
|
+
<span className="shrink-0 text-border">·</span>
|
|
302
|
+
)}
|
|
303
|
+
{established && <span className="shrink-0 whitespace-nowrap">{established}</span>}
|
|
285
304
|
</div>
|
|
286
305
|
)}
|
|
287
306
|
|
|
@@ -58,6 +58,12 @@ export type PlacePreview = {
|
|
|
58
58
|
* bare storage key straight to `next/image`'s loader).
|
|
59
59
|
*/
|
|
60
60
|
cover_url?: string
|
|
61
|
+
/**
|
|
62
|
+
* Year and month the place launched (`YYYY-MM`), as the schema ships it.
|
|
63
|
+
* The backend approximates it from the earliest review it holds, so it is a
|
|
64
|
+
* floor rather than a founding date. `<PlaceCard>` shows the year only.
|
|
65
|
+
*/
|
|
66
|
+
launched_at?: string
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
export type PlaceHourBlock = { opens_at: number; closes_at: number }
|
|
@@ -193,6 +199,11 @@ export type PlaceCardLabels = {
|
|
|
193
199
|
viewDetails: (name: string) => string
|
|
194
200
|
/** Accessible name of the `$` price glyphs, e.g. "Price level 2 of 4". */
|
|
195
201
|
priceLevel: (level: number) => string
|
|
202
|
+
/**
|
|
203
|
+
* The launch year on the meta line, e.g. "Est. 2020" / "Din 2020". Optional:
|
|
204
|
+
* without it the card shows no year even when `launched_at` is set.
|
|
205
|
+
*/
|
|
206
|
+
established?: (year: number) => string
|
|
196
207
|
grade: GradeAtomLabels
|
|
197
208
|
}
|
|
198
209
|
|