@bearmenu/ui 0.8.51 → 0.8.53
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-GIJGVFGC.js +177 -0
- package/dist/chunk-H4ORZT2D.js +14 -0
- package/dist/chunk-RKNPPYRU.js +86 -0
- package/dist/{chunk-S5GDARLW.js → chunk-WY2FP76J.js} +28 -5
- package/dist/components/category-deck.d.ts +6 -1
- package/dist/components/category-deck.js +39 -35
- package/dist/components/event-card.d.ts +7 -0
- package/dist/components/event-card.js +9 -0
- package/dist/components/event-compact-row.d.ts +6 -0
- package/dist/components/event-compact-row.js +5 -3
- package/dist/components/event-hub-hero.d.ts +5 -0
- package/dist/components/event-hub-hero.js +14 -3
- package/dist/components/event-list-row-wide.d.ts +6 -0
- package/dist/components/event-list-row-wide.js +5 -3
- package/dist/components/event-tonight-strip.d.ts +3 -1
- package/dist/components/event-tonight-strip.js +3 -2
- package/dist/components/facet-group.d.ts +9 -2
- package/dist/components/facet-group.js +108 -10
- package/dist/components/featured-rail-item.d.ts +3 -1
- package/dist/components/featured-rail-item.js +3 -1
- package/dist/components/filter-option-chip.d.ts +15 -0
- package/dist/components/filter-option-chip.js +3 -0
- package/dist/components/filter-option-group.d.ts +37 -0
- package/dist/components/filter-option-group.js +10 -0
- package/dist/components/filter-panel-footer.d.ts +15 -0
- package/dist/components/filter-panel-footer.js +63 -0
- package/dist/components/kitchen-dossier.d.ts +7 -1
- package/dist/components/kitchen-dossier.js +2 -1
- package/dist/components/menu-hub-hero.d.ts +7 -1
- package/dist/components/menu-hub-hero.js +2 -0
- package/dist/components/place-card.d.ts +7 -0
- package/dist/components/place-card.js +11 -3
- package/dist/components/poster-stack.d.ts +2 -0
- package/dist/components/poster-stack.js +2 -1
- package/dist/components/section-header.d.ts +6 -1
- package/dist/components/section-header.js +4 -2
- package/dist/components/timeline-day.js +1 -1
- package/dist/components/timeline-hour.d.ts +13 -1
- package/dist/components/timeline-hour.js +1 -1
- package/package.json +6 -6
- package/src/components/category-deck.tsx +11 -0
- package/src/components/event-card.test.tsx +6 -0
- package/src/components/event-card.tsx +17 -0
- package/src/components/event-compact-row.tsx +34 -24
- package/src/components/event-hub-hero.tsx +15 -1
- package/src/components/event-list-row-wide.tsx +25 -15
- package/src/components/event-tonight-strip.test.tsx +12 -0
- package/src/components/event-tonight-strip.tsx +8 -1
- package/src/components/facet-group.tsx +153 -54
- package/src/components/featured-rail-item.tsx +5 -0
- package/src/components/filter-option-chip.test.tsx +50 -0
- package/src/components/filter-option-chip.tsx +81 -0
- package/src/components/filter-option-group.stories.tsx +250 -0
- package/src/components/filter-option-group.test.tsx +100 -0
- package/src/components/filter-option-group.tsx +231 -0
- package/src/components/filter-panel-footer.tsx +63 -0
- package/src/components/kitchen-dossier.tsx +14 -1
- package/src/components/menu-hub-hero.tsx +13 -0
- package/src/components/place-card.stories.tsx +10 -0
- package/src/components/place-card.test.tsx +31 -0
- package/src/components/place-card.tsx +22 -6
- package/src/components/poster-stack.tsx +3 -0
- package/src/components/section-header.tsx +8 -1
- package/src/components/timeline-day.stories.tsx +30 -0
- package/src/components/timeline-day.test.tsx +24 -0
- package/src/components/timeline-hour.tsx +40 -6
- package/src/lib/poster-overlay-frame.tsx +26 -0
|
@@ -3,7 +3,7 @@ import { cn } from '../chunk-FEK5XGZW.js';
|
|
|
3
3
|
import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { Clock, CalendarDays, ChevronRight } from 'lucide-react';
|
|
6
|
-
import {
|
|
6
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
7
|
|
|
8
8
|
function DefaultLink(_a) {
|
|
9
9
|
var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
|
|
@@ -16,10 +16,11 @@ function EventTonightStrip({
|
|
|
16
16
|
actionLabel,
|
|
17
17
|
href,
|
|
18
18
|
linkComponent: LinkComponent = DefaultLink,
|
|
19
|
+
liveIndicator,
|
|
19
20
|
className
|
|
20
21
|
}) {
|
|
21
22
|
const interactive = !!href;
|
|
22
|
-
const mark = tone === "live" ? /* @__PURE__ */ jsxs("span", { className: "relative flex h-2.5 w-2.5", "aria-hidden": true, children: [
|
|
23
|
+
const mark = tone === "live" && liveIndicator ? /* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 items-center justify-center", "aria-hidden": true, children: liveIndicator }) : tone === "live" ? /* @__PURE__ */ jsxs("span", { className: "relative flex h-2.5 w-2.5", "aria-hidden": true, children: [
|
|
23
24
|
/* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full rounded-full bg-success/40 motion-live-pulse motion-reduce:animate-none" }),
|
|
24
25
|
/* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2.5 w-2.5 rounded-full bg-success" })
|
|
25
26
|
] }) : tone === "tonight" ? /* @__PURE__ */ jsx(Clock, { className: "h-4 w-4 text-muted-foreground", "aria-hidden": true }) : /* @__PURE__ */ jsx(
|
|
@@ -58,6 +58,12 @@ type FacetGroupProps = Omit<ComponentPropsWithoutRef<"fieldset">, "title" | "chi
|
|
|
58
58
|
*/
|
|
59
59
|
name?: string;
|
|
60
60
|
size?: FacetGroupSize;
|
|
61
|
+
/** Wrapping native-input chips for filter panels. Rows remain the default. */
|
|
62
|
+
layout?: "rows" | "chips";
|
|
63
|
+
/** Optional bounded chip list; selected options always stay visible. */
|
|
64
|
+
visibleLimit?: number;
|
|
65
|
+
showAllLabel?: string | ((count: number) => string);
|
|
66
|
+
showLessLabel?: string;
|
|
61
67
|
/**
|
|
62
68
|
* Turns the legend into a disclosure toggle for this group's options.
|
|
63
69
|
*
|
|
@@ -84,7 +90,7 @@ type FacetGroupProps = Omit<ComponentPropsWithoutRef<"fieldset">, "title" | "chi
|
|
|
84
90
|
moreExpanded?: boolean;
|
|
85
91
|
className?: string;
|
|
86
92
|
};
|
|
87
|
-
declare function FacetGroup({ title, icon: Icon, options, selection, name, size, collapsible, defaultOpen, onToggle, moreLabel, onMore, moreExpanded, className, ...rest }: FacetGroupProps): react_jsx_runtime.JSX.Element;
|
|
93
|
+
declare function FacetGroup({ title, icon: Icon, options, selection, name, size, layout, visibleLimit, showAllLabel, showLessLabel, collapsible, defaultOpen, onToggle, moreLabel, onMore, moreExpanded, className, ...rest }: FacetGroupProps): react_jsx_runtime.JSX.Element;
|
|
88
94
|
type FacetGroupSkeletonProps = {
|
|
89
95
|
/** How many option rows to draw — match the expected/last-known option count. */
|
|
90
96
|
optionCount?: number;
|
|
@@ -92,9 +98,10 @@ type FacetGroupSkeletonProps = {
|
|
|
92
98
|
showMore?: boolean;
|
|
93
99
|
/** Must match the `<FacetGroup>` it stands in for, or rows shift when data lands. */
|
|
94
100
|
size?: FacetGroupSize;
|
|
101
|
+
layout?: "rows" | "chips";
|
|
95
102
|
className?: string;
|
|
96
103
|
};
|
|
97
104
|
/** Mirrors `<FacetGroup>`'s geometry exactly so nothing shifts when data lands. */
|
|
98
|
-
declare function FacetGroupSkeleton({ optionCount, showMore, size, className, }: FacetGroupSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
105
|
+
declare function FacetGroupSkeleton({ optionCount, showMore, size, className, layout, }: FacetGroupSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
99
106
|
|
|
100
107
|
export { FacetGroup, type FacetGroupProps, type FacetGroupSelection, type FacetGroupSize, FacetGroupSkeleton, type FacetGroupSkeletonProps, type FacetOption };
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
import { FilterOptionGroup } from '../chunk-GIJGVFGC.js';
|
|
2
|
+
import '../chunk-RKNPPYRU.js';
|
|
3
|
+
import '../chunk-NWZGSLPU.js';
|
|
1
4
|
import { Skeleton } from '../chunk-XBBEX4SF.js';
|
|
5
|
+
import { Button } from '../chunk-GHKTVHQG.js';
|
|
6
|
+
import '../chunk-RIH2IS7X.js';
|
|
7
|
+
import '../chunk-5YNIQ2BL.js';
|
|
8
|
+
import '../chunk-ZLMRVBD7.js';
|
|
9
|
+
import '../chunk-RYPPN2GZ.js';
|
|
2
10
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
3
11
|
import { __objRest, __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
|
|
4
12
|
import { useId, useState } from 'react';
|
|
5
13
|
import { ChevronDown, Check } from 'lucide-react';
|
|
6
|
-
import {
|
|
14
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
7
15
|
|
|
8
16
|
var ROW_SIZE = {
|
|
9
17
|
comfortable: "-mx-2 min-h-11 rounded-lg px-2",
|
|
@@ -21,6 +29,10 @@ function FacetGroup(_a) {
|
|
|
21
29
|
selection = "multiple",
|
|
22
30
|
name,
|
|
23
31
|
size = "comfortable",
|
|
32
|
+
layout = "rows",
|
|
33
|
+
visibleLimit,
|
|
34
|
+
showAllLabel,
|
|
35
|
+
showLessLabel,
|
|
24
36
|
collapsible = false,
|
|
25
37
|
defaultOpen = true,
|
|
26
38
|
onToggle,
|
|
@@ -35,6 +47,10 @@ function FacetGroup(_a) {
|
|
|
35
47
|
"selection",
|
|
36
48
|
"name",
|
|
37
49
|
"size",
|
|
50
|
+
"layout",
|
|
51
|
+
"visibleLimit",
|
|
52
|
+
"showAllLabel",
|
|
53
|
+
"showLessLabel",
|
|
38
54
|
"collapsible",
|
|
39
55
|
"defaultOpen",
|
|
40
56
|
"onToggle",
|
|
@@ -50,6 +66,48 @@ function FacetGroup(_a) {
|
|
|
50
66
|
const setOpen = setIsOpen;
|
|
51
67
|
const fallbackName = useId();
|
|
52
68
|
const groupName = name != null ? name : fallbackName;
|
|
69
|
+
if (layout === "chips") {
|
|
70
|
+
const value = options.filter((option) => option.checked).map((option) => option.id);
|
|
71
|
+
return /* @__PURE__ */ jsx(
|
|
72
|
+
FilterOptionGroup,
|
|
73
|
+
{
|
|
74
|
+
title,
|
|
75
|
+
options: options.map((option) => __spreadProps(__spreadValues({}, option), { value: option.id })),
|
|
76
|
+
value,
|
|
77
|
+
selection,
|
|
78
|
+
name: groupName,
|
|
79
|
+
defaultOpen,
|
|
80
|
+
collapsible,
|
|
81
|
+
divider: false,
|
|
82
|
+
visibleLimit,
|
|
83
|
+
showAllLabel,
|
|
84
|
+
showLessLabel,
|
|
85
|
+
disabled: rest.disabled,
|
|
86
|
+
className,
|
|
87
|
+
onValueChange: (next) => {
|
|
88
|
+
if (selection === "single") {
|
|
89
|
+
if (next[0] != null) onToggle == null ? void 0 : onToggle(String(next[0]), true);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
for (const option of options) {
|
|
93
|
+
const checked = next.includes(option.id);
|
|
94
|
+
if (checked !== !!option.checked) onToggle == null ? void 0 : onToggle(option.id, checked);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
footer: moreLabel && /* @__PURE__ */ jsx(
|
|
98
|
+
Button,
|
|
99
|
+
{
|
|
100
|
+
type: "button",
|
|
101
|
+
variant: "link",
|
|
102
|
+
className: "min-h-11 px-0",
|
|
103
|
+
onClick: onMore,
|
|
104
|
+
"aria-expanded": moreExpanded,
|
|
105
|
+
children: moreLabel
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
}
|
|
53
111
|
return (
|
|
54
112
|
// NO SEPARATOR OF ITS OWN. This drew `<Separator className="absolute
|
|
55
113
|
// inset-x-0 top-0" />`, which looked like a rule above each group and was
|
|
@@ -98,7 +156,14 @@ function FacetGroup(_a) {
|
|
|
98
156
|
open ? "mb-[11px]" : "mb-0"
|
|
99
157
|
),
|
|
100
158
|
children: [
|
|
101
|
-
Icon && /* @__PURE__ */ jsx(
|
|
159
|
+
Icon && /* @__PURE__ */ jsx(
|
|
160
|
+
Icon,
|
|
161
|
+
{
|
|
162
|
+
"aria-hidden": true,
|
|
163
|
+
className: "size-3.5 shrink-0",
|
|
164
|
+
strokeWidth: 2.25
|
|
165
|
+
}
|
|
166
|
+
),
|
|
102
167
|
title,
|
|
103
168
|
/* @__PURE__ */ jsx(
|
|
104
169
|
ChevronDown,
|
|
@@ -114,7 +179,14 @@ function FacetGroup(_a) {
|
|
|
114
179
|
}
|
|
115
180
|
)
|
|
116
181
|
) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
|
|
117
|
-
Icon && /* @__PURE__ */ jsx(
|
|
182
|
+
Icon && /* @__PURE__ */ jsx(
|
|
183
|
+
Icon,
|
|
184
|
+
{
|
|
185
|
+
"aria-hidden": true,
|
|
186
|
+
className: "size-3.5 shrink-0",
|
|
187
|
+
strokeWidth: 2.25
|
|
188
|
+
}
|
|
189
|
+
),
|
|
118
190
|
title
|
|
119
191
|
] })
|
|
120
192
|
}
|
|
@@ -164,7 +236,13 @@ function FacetGroup(_a) {
|
|
|
164
236
|
"peer-focus-visible:ring-2 peer-focus-visible:ring-ring peer-focus-visible:ring-offset-2",
|
|
165
237
|
checked ? "border-primary bg-primary" : "border-border bg-background"
|
|
166
238
|
),
|
|
167
|
-
children: checked && (isSingle ? /* @__PURE__ */ jsx("span", { className: "size-[7px] rounded-full bg-primary-foreground" }) : /* @__PURE__ */ jsx(
|
|
239
|
+
children: checked && (isSingle ? /* @__PURE__ */ jsx("span", { className: "size-[7px] rounded-full bg-primary-foreground" }) : /* @__PURE__ */ jsx(
|
|
240
|
+
Check,
|
|
241
|
+
{
|
|
242
|
+
className: "h-[11px] w-[11px] text-primary-foreground",
|
|
243
|
+
strokeWidth: 3
|
|
244
|
+
}
|
|
245
|
+
))
|
|
168
246
|
}
|
|
169
247
|
),
|
|
170
248
|
/* @__PURE__ */ jsx(
|
|
@@ -205,18 +283,38 @@ function FacetGroupSkeleton({
|
|
|
205
283
|
optionCount = 4,
|
|
206
284
|
showMore,
|
|
207
285
|
size = "comfortable",
|
|
208
|
-
className
|
|
286
|
+
className,
|
|
287
|
+
layout = "rows"
|
|
209
288
|
}) {
|
|
289
|
+
if (layout === "chips")
|
|
290
|
+
return /* @__PURE__ */ jsxs("div", { "aria-hidden": "true", className: cn("py-3", className), children: [
|
|
291
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "mb-4 h-4 w-24" }),
|
|
292
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: Array.from({ length: optionCount }, (_, index) => /* @__PURE__ */ jsx(
|
|
293
|
+
Skeleton,
|
|
294
|
+
{
|
|
295
|
+
className: cn("h-11 rounded-2xl", index % 2 ? "w-28" : "w-24")
|
|
296
|
+
},
|
|
297
|
+
index
|
|
298
|
+
)) }),
|
|
299
|
+
showMore && /* @__PURE__ */ jsx(Skeleton, { className: "mt-3 h-4 w-20" })
|
|
300
|
+
] });
|
|
210
301
|
return (
|
|
211
302
|
// Matches the live group: no rule of its own, `py-3`, and the row gap keyed
|
|
212
303
|
// to the same density — or the panel shifts on load by the difference.
|
|
213
304
|
/* @__PURE__ */ jsxs("div", { "aria-hidden": "true", className: cn("py-3", className), children: [
|
|
214
305
|
/* @__PURE__ */ jsx(Skeleton, { className: "mb-[11px] h-3 w-20" }),
|
|
215
|
-
/* @__PURE__ */ jsx("div", { className: cn("flex flex-col", ROW_GAP[size]), children: Array.from({ length: optionCount }).map((_, index) => /* @__PURE__ */ jsxs(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
306
|
+
/* @__PURE__ */ jsx("div", { className: cn("flex flex-col", ROW_GAP[size]), children: Array.from({ length: optionCount }).map((_, index) => /* @__PURE__ */ jsxs(
|
|
307
|
+
"div",
|
|
308
|
+
{
|
|
309
|
+
className: cn("flex items-center gap-[9px]", ROW_SIZE[size]),
|
|
310
|
+
children: [
|
|
311
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4 rounded-[5px]" }),
|
|
312
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-24" }),
|
|
313
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "ml-auto h-3 w-5" })
|
|
314
|
+
]
|
|
315
|
+
},
|
|
316
|
+
index
|
|
317
|
+
)) }),
|
|
220
318
|
showMore && /* @__PURE__ */ jsx(Skeleton, { className: "mt-[11px] h-3 w-16" })
|
|
221
319
|
] })
|
|
222
320
|
);
|
|
@@ -24,6 +24,8 @@ type FeaturedRailItemProps = {
|
|
|
24
24
|
note: string;
|
|
25
25
|
/** Top-left overlay pill. Include its icon. */
|
|
26
26
|
tagLabel?: React.ReactNode;
|
|
27
|
+
/** Decorative overlay inside the poster box (`relative`, clipping): an absolutely positioned, `aria-hidden` ornament. */
|
|
28
|
+
posterOverlay?: React.ReactNode;
|
|
27
29
|
posterUrl?: string;
|
|
28
30
|
href?: string;
|
|
29
31
|
/** Defaults to a plain `<a>`. Pass `next/link` in a Next app. */
|
|
@@ -33,7 +35,7 @@ type FeaturedRailItemProps = {
|
|
|
33
35
|
/** Rendered instead of the poster when it's absent or failed to load. Defaults to `<EventPosterFallback />`. */
|
|
34
36
|
fallback?: ReactNode;
|
|
35
37
|
};
|
|
36
|
-
declare function FeaturedRailItem({ title, venue, note, tagLabel, posterUrl, href, linkComponent: LinkComponent, onClick, className, fallback, }: FeaturedRailItemProps): react_jsx_runtime.JSX.Element;
|
|
38
|
+
declare function FeaturedRailItem({ title, venue, note, tagLabel, posterOverlay, posterUrl, href, linkComponent: LinkComponent, onClick, className, fallback, }: FeaturedRailItemProps): react_jsx_runtime.JSX.Element;
|
|
37
39
|
type FeaturedRailItemSkeletonProps = {
|
|
38
40
|
className?: string;
|
|
39
41
|
};
|
|
@@ -14,6 +14,7 @@ function FeaturedRailItem({
|
|
|
14
14
|
venue,
|
|
15
15
|
note,
|
|
16
16
|
tagLabel,
|
|
17
|
+
posterOverlay,
|
|
17
18
|
posterUrl,
|
|
18
19
|
href,
|
|
19
20
|
linkComponent: LinkComponent = DefaultLink,
|
|
@@ -40,7 +41,8 @@ function FeaturedRailItem({
|
|
|
40
41
|
}
|
|
41
42
|
)
|
|
42
43
|
) : fallback,
|
|
43
|
-
tagLabel && /* @__PURE__ */ jsx("div", { className: "absolute inset-x-2 top-2 flex items-start", children: /* @__PURE__ */ jsx("span", { className: "inline-flex h-6 max-w-full items-center gap-1 rounded-full bg-black/55 px-2 text-[11px] font-semibold text-white", children: tagLabel }) })
|
|
44
|
+
tagLabel && /* @__PURE__ */ jsx("div", { className: "absolute inset-x-2 top-2 flex items-start", children: /* @__PURE__ */ jsx("span", { className: "inline-flex h-6 max-w-full items-center gap-1 rounded-full bg-black/55 px-2 text-[11px] font-semibold text-white", children: tagLabel }) }),
|
|
45
|
+
posterOverlay
|
|
44
46
|
] }),
|
|
45
47
|
/* @__PURE__ */ jsxs("div", { className: "px-0.5 pt-2.5", children: [
|
|
46
48
|
/* @__PURE__ */ jsx("h3", { className: "text-[13.5px] font-bold leading-[1.3]", children: title }),
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type FilterOptionChipProps = Omit<ComponentPropsWithoutRef<"input">, "type" | "children" | "size"> & {
|
|
5
|
+
label: string;
|
|
6
|
+
/** Radios in one group must share a name. */
|
|
7
|
+
type?: "checkbox" | "radio";
|
|
8
|
+
/** Omit while counts are unresolved. Zero is a valid, selectable count. */
|
|
9
|
+
count?: number | null;
|
|
10
|
+
icon?: ReactNode;
|
|
11
|
+
};
|
|
12
|
+
/** A wrapping filter option with native selection and keyboard semantics. */
|
|
13
|
+
declare function FilterOptionChip({ label, type, count, icon, className, id, disabled, ...input }: FilterOptionChipProps): react_jsx_runtime.JSX.Element;
|
|
14
|
+
|
|
15
|
+
export { FilterOptionChip, type FilterOptionChipProps };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type FilterOptionValue = string | number;
|
|
5
|
+
type FilterOptionGroupProps = {
|
|
6
|
+
title: string;
|
|
7
|
+
options: {
|
|
8
|
+
value: FilterOptionValue;
|
|
9
|
+
label: string;
|
|
10
|
+
count?: number | null;
|
|
11
|
+
icon?: ReactNode;
|
|
12
|
+
section?: string;
|
|
13
|
+
}[];
|
|
14
|
+
value: FilterOptionValue[];
|
|
15
|
+
onValueChange: (value: FilterOptionValue[]) => void;
|
|
16
|
+
selection?: "multiple" | "single";
|
|
17
|
+
name?: string;
|
|
18
|
+
defaultOpen?: boolean;
|
|
19
|
+
collapsible?: boolean;
|
|
20
|
+
visibleLimit?: number;
|
|
21
|
+
showAllLabel?: string | ((count: number) => string);
|
|
22
|
+
showLessLabel?: string;
|
|
23
|
+
/** Extra controls or a selection explanation, before the options. */
|
|
24
|
+
children?: ReactNode;
|
|
25
|
+
footer?: ReactNode;
|
|
26
|
+
clearLabel?: string;
|
|
27
|
+
onClear?: () => void;
|
|
28
|
+
/** Omit neutral choices from the active summary without changing radio selection. */
|
|
29
|
+
summaryValues?: FilterOptionValue[];
|
|
30
|
+
className?: string;
|
|
31
|
+
divider?: boolean;
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
};
|
|
34
|
+
/** Presentation only: callers own filter rules, URL state, counts and translations. */
|
|
35
|
+
declare function FilterOptionGroup({ title, options, value, onValueChange, selection, name, defaultOpen, collapsible, visibleLimit, showAllLabel, showLessLabel, children, footer, clearLabel, onClear, summaryValues, className, divider, disabled, }: FilterOptionGroupProps): react_jsx_runtime.JSX.Element;
|
|
36
|
+
|
|
37
|
+
export { FilterOptionGroup, type FilterOptionGroupProps, type FilterOptionValue };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { FilterOptionGroup } from '../chunk-GIJGVFGC.js';
|
|
2
|
+
import '../chunk-RKNPPYRU.js';
|
|
3
|
+
import '../chunk-NWZGSLPU.js';
|
|
4
|
+
import '../chunk-GHKTVHQG.js';
|
|
5
|
+
import '../chunk-RIH2IS7X.js';
|
|
6
|
+
import '../chunk-5YNIQ2BL.js';
|
|
7
|
+
import '../chunk-ZLMRVBD7.js';
|
|
8
|
+
import '../chunk-RYPPN2GZ.js';
|
|
9
|
+
import '../chunk-FEK5XGZW.js';
|
|
10
|
+
import '../chunk-MMUBH76A.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
type FilterPanelFooterProps = {
|
|
4
|
+
resetLabel: string;
|
|
5
|
+
resultsLabel: string;
|
|
6
|
+
onReset: () => void;
|
|
7
|
+
onResults: () => void;
|
|
8
|
+
canReset: boolean;
|
|
9
|
+
pending?: boolean;
|
|
10
|
+
resetHint?: string;
|
|
11
|
+
};
|
|
12
|
+
/** Persistent actions belong outside the panel's scroll container. */
|
|
13
|
+
declare function FilterPanelFooter({ resetLabel, resultsLabel, onReset, onResults, canReset, pending, resetHint, }: FilterPanelFooterProps): react_jsx_runtime.JSX.Element;
|
|
14
|
+
|
|
15
|
+
export { FilterPanelFooter, type FilterPanelFooterProps };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Button } from '../chunk-GHKTVHQG.js';
|
|
2
|
+
import '../chunk-RIH2IS7X.js';
|
|
3
|
+
import '../chunk-5YNIQ2BL.js';
|
|
4
|
+
import { Text } from '../chunk-ZLMRVBD7.js';
|
|
5
|
+
import '../chunk-FEK5XGZW.js';
|
|
6
|
+
import '../chunk-MMUBH76A.js';
|
|
7
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
function FilterPanelFooter({
|
|
10
|
+
resetLabel,
|
|
11
|
+
resultsLabel,
|
|
12
|
+
onReset,
|
|
13
|
+
onResults,
|
|
14
|
+
canReset,
|
|
15
|
+
pending,
|
|
16
|
+
resetHint
|
|
17
|
+
}) {
|
|
18
|
+
return /* @__PURE__ */ jsxs(
|
|
19
|
+
"footer",
|
|
20
|
+
{
|
|
21
|
+
className: "shrink-0 border-t border-border bg-card px-4 pt-3 pb-[max(1rem,env(safe-area-inset-bottom))]",
|
|
22
|
+
"data-slot": "filter-panel-footer",
|
|
23
|
+
children: [
|
|
24
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
25
|
+
/* @__PURE__ */ jsx(
|
|
26
|
+
Button,
|
|
27
|
+
{
|
|
28
|
+
type: "button",
|
|
29
|
+
variant: "outline",
|
|
30
|
+
className: "min-h-11 h-auto flex-1 whitespace-normal py-2",
|
|
31
|
+
disabled: !canReset,
|
|
32
|
+
onClick: onReset,
|
|
33
|
+
children: resetLabel
|
|
34
|
+
}
|
|
35
|
+
),
|
|
36
|
+
/* @__PURE__ */ jsx(
|
|
37
|
+
Button,
|
|
38
|
+
{
|
|
39
|
+
type: "button",
|
|
40
|
+
className: "min-h-11 h-auto flex-[2] whitespace-normal py-2",
|
|
41
|
+
disabled: pending,
|
|
42
|
+
"aria-busy": pending || void 0,
|
|
43
|
+
onClick: onResults,
|
|
44
|
+
children: resultsLabel
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
] }),
|
|
48
|
+
resetHint && /* @__PURE__ */ jsx(
|
|
49
|
+
Text,
|
|
50
|
+
{
|
|
51
|
+
as: "p",
|
|
52
|
+
variant: "caption",
|
|
53
|
+
color: "muted",
|
|
54
|
+
className: "mt-2 leading-relaxed",
|
|
55
|
+
children: resetHint
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { FilterPanelFooter };
|
|
@@ -83,9 +83,15 @@ type KitchenDossierProps = {
|
|
|
83
83
|
partDurationMs?: number;
|
|
84
84
|
/** The foot's action — pass a rendered link or button. */
|
|
85
85
|
action?: ReactNode;
|
|
86
|
+
/**
|
|
87
|
+
* Drawn in place of the open-until pill's dot, in the dot's slot (roughly
|
|
88
|
+
* 16-22px square). Decorative and `aria-hidden`; only rendered with
|
|
89
|
+
* `labels.openUntil`.
|
|
90
|
+
*/
|
|
91
|
+
openIndicator?: ReactNode;
|
|
86
92
|
linkComponent?: MenuLinkComponent;
|
|
87
93
|
className?: string;
|
|
88
94
|
};
|
|
89
|
-
declare function KitchenDossier({ place, href, meta, signature, quotes, grade, labels, formatPrice, formatScore, partDurationMs, action, linkComponent: LinkComponent, className, }: KitchenDossierProps): react_jsx_runtime.JSX.Element;
|
|
95
|
+
declare function KitchenDossier({ place, href, meta, signature, quotes, grade, labels, formatPrice, formatScore, partDurationMs, action, openIndicator, linkComponent: LinkComponent, className, }: KitchenDossierProps): react_jsx_runtime.JSX.Element;
|
|
90
96
|
|
|
91
97
|
export { KitchenDossier, type KitchenDossierLabels, type KitchenDossierLinkProps, type KitchenDossierProps };
|
|
@@ -32,6 +32,7 @@ function KitchenDossier({
|
|
|
32
32
|
formatScore,
|
|
33
33
|
partDurationMs,
|
|
34
34
|
action,
|
|
35
|
+
openIndicator,
|
|
35
36
|
linkComponent: LinkComponent = DefaultLink,
|
|
36
37
|
className
|
|
37
38
|
}) {
|
|
@@ -129,7 +130,7 @@ function KitchenDossier({
|
|
|
129
130
|
}
|
|
130
131
|
),
|
|
131
132
|
/* @__PURE__ */ jsx("div", { className: "relative min-h-[184px] flex-1", children: labels.openUntil && /* @__PURE__ */ jsxs("span", { className: "absolute left-0 top-3 inline-flex h-[30px] items-center gap-[7px] rounded-full bg-[oklch(0.16_0.012_55_/_0.78)] px-3 text-[11.5px] font-bold text-white", children: [
|
|
132
|
-
/* @__PURE__ */ jsx("i", { className: "h-[7px] w-[7px] rounded-full bg-success", "aria-hidden": true }),
|
|
133
|
+
openIndicator ? /* @__PURE__ */ jsx("span", { className: "flex shrink-0 items-center justify-center", "aria-hidden": true, children: openIndicator }) : /* @__PURE__ */ jsx("i", { className: "h-[7px] w-[7px] rounded-full bg-success", "aria-hidden": true }),
|
|
133
134
|
labels.openUntil
|
|
134
135
|
] }) }),
|
|
135
136
|
/* @__PURE__ */ jsxs("div", { className: "relative flex flex-col gap-3.5", children: [
|
|
@@ -64,8 +64,14 @@ type MenuHubHeroProps = {
|
|
|
64
64
|
* `h2` so the document has one h1, not two.
|
|
65
65
|
*/
|
|
66
66
|
headingLevel?: "h1" | "h2";
|
|
67
|
+
/**
|
|
68
|
+
* A decorative layer over the photographs and their scrim, under the text:
|
|
69
|
+
* fill the banner with `absolute inset-0`. Clipped by the banner's rounded
|
|
70
|
+
* edge. Decorative and `aria-hidden`.
|
|
71
|
+
*/
|
|
72
|
+
sceneOverlay?: React.ReactNode;
|
|
67
73
|
className?: string;
|
|
68
74
|
};
|
|
69
|
-
declare function MenuHubHero({ kicker, kickerIcon, headline, body, figures, proof, proofIcon, action, backgroundUrl, tileUrls, headingLevel: Heading, className, }: MenuHubHeroProps): react_jsx_runtime.JSX.Element;
|
|
75
|
+
declare function MenuHubHero({ kicker, kickerIcon, headline, body, figures, proof, proofIcon, action, backgroundUrl, tileUrls, headingLevel: Heading, sceneOverlay, className, }: MenuHubHeroProps): react_jsx_runtime.JSX.Element;
|
|
70
76
|
|
|
71
77
|
export { MenuHubHero, type MenuHubHeroFigure, type MenuHubHeroProps };
|
|
@@ -16,6 +16,7 @@ function MenuHubHero({
|
|
|
16
16
|
backgroundUrl,
|
|
17
17
|
tileUrls,
|
|
18
18
|
headingLevel: Heading = "h1",
|
|
19
|
+
sceneOverlay,
|
|
19
20
|
className
|
|
20
21
|
}) {
|
|
21
22
|
return /* @__PURE__ */ jsxs(
|
|
@@ -81,6 +82,7 @@ function MenuHubHero({
|
|
|
81
82
|
)
|
|
82
83
|
}
|
|
83
84
|
),
|
|
85
|
+
sceneOverlay && /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "pointer-events-none absolute inset-0", children: sceneOverlay }),
|
|
84
86
|
/* @__PURE__ */ jsxs("div", { className: "relative z-[1] flex w-full flex-col justify-center gap-3 p-5 text-white lg:gap-4 lg:px-12 lg:py-11", children: [
|
|
85
87
|
kicker && /* @__PURE__ */ jsxs("span", { className: "inline-flex w-max items-center gap-[7px] rounded-full bg-white/15 px-3 py-1.5 text-[11px] font-extrabold tracking-[0.11em]", children: [
|
|
86
88
|
kickerIcon,
|
|
@@ -81,6 +81,13 @@ type PlaceCardProps = {
|
|
|
81
81
|
* trending badge on the API's `trending` flag).
|
|
82
82
|
*/
|
|
83
83
|
photoOverlay?: ReactNode;
|
|
84
|
+
/**
|
|
85
|
+
* Drawn in place of the green open-now dot, in the dot's top-right slot
|
|
86
|
+
* (roughly 16-20px square). Decorative: it is only rendered when
|
|
87
|
+
* `place.open_now === true` and should be `aria-hidden`. The closed badge is
|
|
88
|
+
* untouched.
|
|
89
|
+
*/
|
|
90
|
+
openIndicator?: ReactNode;
|
|
84
91
|
className?: string;
|
|
85
92
|
};
|
|
86
93
|
declare const PlaceCard: React$1.NamedExoticComponent<PlaceCardProps>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { HOVER_IMAGE_MOTION, HOVER_IMAGE_WRAPPER, HOVER_MOTION, HOVER_LIFT_GRID_GROUP } from '../chunk-XCB3F6SF.js';
|
|
1
2
|
import { NEUTRAL_ICON_FILTER } from '../chunk-LQWGZIYA.js';
|
|
2
3
|
import { OVERLAY_PILL } from '../chunk-EZG2NELX.js';
|
|
3
|
-
import { HOVER_IMAGE_MOTION, HOVER_IMAGE_WRAPPER, HOVER_MOTION, HOVER_LIFT_GRID_GROUP } from '../chunk-XCB3F6SF.js';
|
|
4
4
|
import { GradeAtom } from '../chunk-YE4ZQUTI.js';
|
|
5
5
|
import { showsGradeAtom } from '../chunk-I5V446BX.js';
|
|
6
6
|
import { Separator } from '../chunk-NWZGSLPU.js';
|
|
@@ -74,6 +74,7 @@ var PlaceCard = memo(function PlaceCard2({
|
|
|
74
74
|
onOpen,
|
|
75
75
|
footer,
|
|
76
76
|
photoOverlay,
|
|
77
|
+
openIndicator,
|
|
77
78
|
className
|
|
78
79
|
}) {
|
|
79
80
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
@@ -132,13 +133,20 @@ var PlaceCard = memo(function PlaceCard2({
|
|
|
132
133
|
}
|
|
133
134
|
) })
|
|
134
135
|
),
|
|
135
|
-
place.open_now === true && /* @__PURE__ */ jsx(
|
|
136
|
+
place.open_now === true && (openIndicator ? /* @__PURE__ */ jsx(
|
|
137
|
+
"span",
|
|
138
|
+
{
|
|
139
|
+
className: "pointer-events-none absolute right-2 top-2 flex items-center justify-center",
|
|
140
|
+
"aria-hidden": true,
|
|
141
|
+
children: openIndicator
|
|
142
|
+
}
|
|
143
|
+
) : /* @__PURE__ */ jsx(
|
|
136
144
|
"span",
|
|
137
145
|
{
|
|
138
146
|
className: "absolute right-2.5 top-2.5 h-2 w-2 rounded-full bg-green-500 ring-2 ring-white/70",
|
|
139
147
|
"aria-hidden": true
|
|
140
148
|
}
|
|
141
|
-
),
|
|
149
|
+
)),
|
|
142
150
|
place.open_now === false && /* `Badge variant="overlay"` + the shared cover geometry: this pill and
|
|
143
151
|
the caller's `photoOverlay` sit on the same photo and must match. */
|
|
144
152
|
/* @__PURE__ */ jsx(Badge, { variant: "overlay", className: cn(OVERLAY_PILL, "absolute right-2 top-2"), children: labels.closed })
|
|
@@ -50,6 +50,8 @@ type PosterStackPoster = {
|
|
|
50
50
|
caption?: string;
|
|
51
51
|
/** Rendered when `src` is absent or fails. Defaults to `<EventPosterFallback />`. */
|
|
52
52
|
fallback?: React.ReactNode;
|
|
53
|
+
/** Decorative overlay on the poster face (it tilts and floats with the poster): an absolutely positioned, `aria-hidden` ornament. */
|
|
54
|
+
overlay?: React.ReactNode;
|
|
53
55
|
/** Load now at high priority instead of lazily. For the poster that is the
|
|
54
56
|
* page's LCP element; every other poster stays lazy. */
|
|
55
57
|
eager?: boolean;
|
|
@@ -96,7 +96,8 @@ function PosterStack({
|
|
|
96
96
|
}
|
|
97
97
|
)
|
|
98
98
|
) : (_a = poster.fallback) != null ? _a : /* @__PURE__ */ jsx(EventPosterFallback, {}),
|
|
99
|
-
poster.caption && /* @__PURE__ */ jsx("span", { className: "absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/70 to-transparent px-2 pb-2 pt-6", children: /* @__PURE__ */ jsx("span", { className: "line-clamp-2 text-[11px] font-semibold leading-[1.25] text-white md:text-[12.5px]", children: poster.caption }) })
|
|
99
|
+
poster.caption && /* @__PURE__ */ jsx("span", { className: "absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/70 to-transparent px-2 pb-2 pt-6", children: /* @__PURE__ */ jsx("span", { className: "line-clamp-2 text-[11px] font-semibold leading-[1.25] text-white md:text-[12.5px]", children: poster.caption }) }),
|
|
100
|
+
poster.overlay
|
|
100
101
|
] });
|
|
101
102
|
return /* @__PURE__ */ jsx(
|
|
102
103
|
"div",
|
|
@@ -56,9 +56,14 @@ type SectionHeaderProps = {
|
|
|
56
56
|
* behaviour; it only holds the slot.
|
|
57
57
|
*/
|
|
58
58
|
trailing?: React.ReactNode;
|
|
59
|
+
/**
|
|
60
|
+
* Absolute decoration anchored to the title group's own box. Takes no
|
|
61
|
+
* layout; the group is `relative` for it. Decorative and `aria-hidden`.
|
|
62
|
+
*/
|
|
63
|
+
titleAdornment?: React.ReactNode;
|
|
59
64
|
className?: string;
|
|
60
65
|
};
|
|
61
|
-
declare function SectionHeader({ title, count, subtitle, action, actionHref, actionTone, subtitleFrom, linkComponent: LinkComponent, onAction, as: Heading, trailing, className, }: SectionHeaderProps): react_jsx_runtime.JSX.Element;
|
|
66
|
+
declare function SectionHeader({ title, count, subtitle, action, actionHref, actionTone, subtitleFrom, linkComponent: LinkComponent, onAction, as: Heading, trailing, titleAdornment, className, }: SectionHeaderProps): react_jsx_runtime.JSX.Element;
|
|
62
67
|
type SectionHeaderSkeletonProps = {
|
|
63
68
|
/** Shows the inline count placeholder, matching `SectionHeaderProps["count"]`. */
|
|
64
69
|
showCount?: boolean;
|
|
@@ -32,15 +32,17 @@ function SectionHeader({
|
|
|
32
32
|
onAction,
|
|
33
33
|
as: Heading = "h2",
|
|
34
34
|
trailing,
|
|
35
|
+
titleAdornment,
|
|
35
36
|
className
|
|
36
37
|
}) {
|
|
37
38
|
const actionIcon = /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5", "aria-hidden": true });
|
|
38
39
|
const actionClasses = cn(ACTION_BASE_CLASSES, ACTION_TONE_CLASSES[actionTone]);
|
|
39
40
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col mb-3.5", className), children: [
|
|
40
41
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
41
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-baseline", children: [
|
|
42
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex min-w-0 items-baseline", children: [
|
|
42
43
|
/* @__PURE__ */ jsx(Heading, { className: "truncate text-[17px] font-bold tracking-[-0.01em] text-foreground md:text-[18px]", children: title }),
|
|
43
|
-
count !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-1.5 shrink-0 text-[12px] tabular-nums text-muted-foreground lg:ml-0.5", children: count })
|
|
44
|
+
count !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-1.5 shrink-0 text-[12px] tabular-nums text-muted-foreground lg:ml-0.5", children: count }),
|
|
45
|
+
titleAdornment
|
|
44
46
|
] }),
|
|
45
47
|
(action || trailing) && /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-3", children: [
|
|
46
48
|
action && (actionHref ? /* @__PURE__ */ jsxs(LinkComponent, { href: actionHref, className: actionClasses, onClick: onAction, children: [
|