@bearmenu/ui 0.8.7 → 0.8.9
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-637L7XQ3.js → chunk-3TNPSN4D.js} +28 -9
- package/dist/chunk-62ES6N32.js +27 -0
- package/dist/chunk-AHL45DD2.js +145 -0
- package/dist/chunk-AXV5O2IZ.js +58 -0
- package/dist/chunk-IYDH5IU6.js +66 -0
- package/dist/chunk-OPVKL4VS.js +18 -0
- package/dist/chunk-Q6QH52LJ.js +38 -0
- package/dist/chunk-TH6W2PWG.js +213 -0
- package/dist/chunk-THOVPZNN.js +37 -0
- package/dist/chunk-YS6BHKZO.js +92 -0
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/category-deck.js +10 -1
- package/dist/components/command.d.ts +7 -7
- package/dist/components/concept-compare.d.ts +73 -0
- package/dist/components/concept-compare.js +162 -0
- package/dist/components/coverflow.d.ts +11 -3
- package/dist/components/coverflow.js +34 -51
- package/dist/components/date-input.d.ts +1 -1
- package/dist/components/drift-rail.d.ts +24 -10
- package/dist/components/drift-rail.js +1 -1
- package/dist/components/event-card.d.ts +8 -0
- package/dist/components/event-card.js +64 -34
- package/dist/components/event-compact-row.d.ts +33 -6
- package/dist/components/event-compact-row.js +120 -39
- package/dist/components/event-day-header.js +3 -1
- package/dist/components/event-day-separator.d.ts +7 -1
- package/dist/components/event-day-separator.js +3 -2
- package/dist/components/event-detail-panel.d.ts +171 -25
- package/dist/components/event-detail-panel.js +471 -174
- package/dist/components/event-hub-hero.d.ts +25 -4
- package/dist/components/event-hub-hero.js +89 -19
- package/dist/components/event-list-row-wide.js +1 -1
- package/dist/components/event-list-row.d.ts +19 -6
- package/dist/components/event-list-row.js +79 -35
- package/dist/components/hour-band.d.ts +38 -40
- package/dist/components/hour-band.js +55 -27
- package/dist/components/hour-group.js +1 -1
- package/dist/components/hub-surface.d.ts +27 -0
- package/dist/components/hub-surface.js +20 -0
- package/dist/components/menu-family-card.d.ts +59 -0
- package/dist/components/menu-family-card.js +121 -0
- package/dist/components/menu-field.d.ts +57 -0
- package/dist/components/menu-field.js +3 -0
- package/dist/components/menu-hub-hero.d.ts +65 -0
- package/dist/components/menu-hub-hero.js +103 -0
- package/dist/components/menu-intent-tiles.d.ts +31 -0
- package/dist/components/menu-intent-tiles.js +50 -0
- package/dist/components/menu-item.d.ts +127 -0
- package/dist/components/menu-item.js +5 -0
- package/dist/components/menu-mocks.d.ts +55 -0
- package/dist/components/menu-mocks.js +379 -0
- package/dist/components/menu-types.d.ts +245 -0
- package/dist/components/menu-types.js +1 -0
- package/dist/components/motion-icon-set.js +15 -3
- package/dist/components/open-now-list.d.ts +40 -0
- package/dist/components/open-now-list.js +69 -0
- package/dist/components/place-types.d.ts +112 -1
- package/dist/components/poster-tape.js +1 -1
- package/dist/components/poster-wall.d.ts +3 -3
- package/dist/components/poster-wall.js +73 -17
- package/dist/components/ranked-venue-list.d.ts +49 -0
- package/dist/components/ranked-venue-list.js +87 -0
- package/dist/components/section-header.d.ts +16 -1
- package/dist/components/section-header.js +26 -7
- package/dist/components/signature-chip.d.ts +37 -0
- package/dist/components/signature-chip.js +4 -0
- package/dist/components/signature-line-list.d.ts +45 -0
- package/dist/components/signature-line-list.js +99 -0
- package/dist/components/snap-rail.d.ts +54 -0
- package/dist/components/snap-rail.js +109 -0
- package/dist/components/spinner.d.ts +2 -2
- package/dist/components/stat-banner.d.ts +47 -0
- package/dist/components/stat-banner.js +61 -0
- package/dist/components/text.d.ts +3 -3
- package/dist/components/timeline-band.d.ts +20 -2
- package/dist/components/timeline-band.js +1 -1
- package/dist/components/timeline-playhead.d.ts +26 -0
- package/dist/components/timeline-playhead.js +25 -0
- package/dist/components/venue-busyness-strip.d.ts +35 -0
- package/dist/components/venue-busyness-strip.js +37 -0
- package/dist/components/venue-grade-dimensions.d.ts +36 -0
- package/dist/components/venue-grade-dimensions.js +3 -0
- package/dist/components/venue-quotes.d.ts +32 -0
- package/dist/components/venue-quotes.js +3 -0
- package/dist/components/venue-signature-block.d.ts +39 -0
- package/dist/components/venue-signature-block.js +6 -0
- package/dist/components/venue-spotlight.d.ts +74 -0
- package/dist/components/venue-spotlight.js +138 -0
- package/dist/components/venue-wall.d.ts +41 -0
- package/dist/components/venue-wall.js +118 -0
- package/dist/components/weekday-theme-banner.d.ts +70 -0
- package/dist/components/weekday-theme-banner.js +127 -0
- package/dist/components/weekend-panel.d.ts +5 -4
- package/dist/components/weekend-panel.js +85 -71
- package/dist/hooks/use-drag-swipe.d.ts +44 -0
- package/dist/hooks/use-drag-swipe.js +2 -0
- package/dist/hooks/use-media-query.d.ts +17 -0
- package/dist/hooks/use-media-query.js +2 -0
- package/package.json +1 -1
- package/src/components/category-deck.tsx +19 -8
- package/src/components/colour-dictionary.stories.tsx +227 -0
- package/src/components/concept-compare.stories.tsx +104 -0
- package/src/components/concept-compare.tsx +276 -0
- package/src/components/coverflow.test.tsx +28 -1
- package/src/components/coverflow.tsx +37 -43
- package/src/components/drift-rail.tsx +167 -42
- package/src/components/event-card.tsx +55 -10
- package/src/components/event-compact-row.stories.tsx +30 -0
- package/src/components/event-compact-row.test.tsx +49 -0
- package/src/components/event-compact-row.tsx +162 -38
- package/src/components/event-day-header.tsx +3 -1
- package/src/components/event-day-separator.tsx +8 -1
- package/src/components/event-detail-panel.stories.tsx +205 -97
- package/src/components/event-detail-panel.test.tsx +181 -0
- package/src/components/event-detail-panel.tsx +703 -185
- package/src/components/event-hub-hero.stories.tsx +30 -0
- package/src/components/event-hub-hero.tsx +102 -30
- package/src/components/event-list-row.stories.tsx +34 -0
- package/src/components/event-list-row.test.tsx +53 -0
- package/src/components/event-list-row.tsx +135 -87
- package/src/components/hour-band.stories.tsx +28 -5
- package/src/components/hour-band.tsx +90 -70
- package/src/components/hub-surface.stories.tsx +68 -0
- package/src/components/hub-surface.tsx +40 -0
- package/src/components/menu-family-card.stories.tsx +112 -0
- package/src/components/menu-family-card.tsx +211 -0
- package/src/components/menu-field.stories.tsx +74 -0
- package/src/components/menu-field.tsx +199 -0
- package/src/components/menu-hub-hero.stories.tsx +92 -0
- package/src/components/menu-hub-hero.tsx +187 -0
- package/src/components/menu-intent-tiles.stories.tsx +54 -0
- package/src/components/menu-intent-tiles.tsx +76 -0
- package/src/components/menu-item.tsx +416 -0
- package/src/components/menu-mocks.ts +417 -0
- package/src/components/menu-types.ts +259 -0
- package/src/components/motion-icon-set.tsx +30 -3
- package/src/components/open-now-list.stories.tsx +76 -0
- package/src/components/open-now-list.tsx +127 -0
- package/src/components/place-types.ts +112 -0
- package/src/components/poster-wall.test.tsx +28 -0
- package/src/components/poster-wall.tsx +96 -23
- package/src/components/ranked-venue-list.stories.tsx +80 -0
- package/src/components/ranked-venue-list.tsx +177 -0
- package/src/components/section-header.stories.tsx +24 -0
- package/src/components/section-header.test.tsx +28 -0
- package/src/components/section-header.tsx +45 -7
- package/src/components/signature-chip.tsx +77 -0
- package/src/components/signature-line-list.stories.tsx +85 -0
- package/src/components/signature-line-list.tsx +136 -0
- package/src/components/snap-rail.stories.tsx +79 -0
- package/src/components/snap-rail.test.tsx +18 -0
- package/src/components/snap-rail.tsx +148 -0
- package/src/components/stat-banner.stories.tsx +100 -0
- package/src/components/stat-banner.tsx +117 -0
- package/src/components/timeline-band.tsx +52 -12
- package/src/components/timeline-playhead.stories.tsx +30 -0
- package/src/components/timeline-playhead.test.tsx +11 -0
- package/src/components/timeline-playhead.tsx +46 -0
- package/src/components/venue-busyness-strip.stories.tsx +66 -0
- package/src/components/venue-busyness-strip.tsx +64 -0
- package/src/components/venue-grade-dimensions.stories.tsx +83 -0
- package/src/components/venue-grade-dimensions.tsx +91 -0
- package/src/components/venue-quotes.stories.tsx +59 -0
- package/src/components/venue-quotes.tsx +64 -0
- package/src/components/venue-signature-block.stories.tsx +68 -0
- package/src/components/venue-signature-block.tsx +71 -0
- package/src/components/venue-spotlight.stories.tsx +141 -0
- package/src/components/venue-spotlight.tsx +236 -0
- package/src/components/venue-wall.stories.tsx +78 -0
- package/src/components/venue-wall.tsx +185 -0
- package/src/components/weekday-theme-banner.stories.tsx +113 -0
- package/src/components/weekday-theme-banner.tsx +231 -0
- package/src/components/weekend-panel.test.tsx +43 -0
- package/src/components/weekend-panel.tsx +142 -108
- package/src/hooks/use-drag-swipe.test.tsx +66 -0
- package/src/hooks/use-drag-swipe.ts +105 -0
- package/src/hooks/use-media-query.ts +31 -0
- package/dist/chunk-GPH6L4DX.js +0 -55
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { cn } from './chunk-FEK5XGZW.js';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
var GHOST_ROWS = 13;
|
|
5
|
+
var GHOST_CENTRE = (GHOST_ROWS - 1) / 2;
|
|
6
|
+
var ALPHA_PEAK = 0.44;
|
|
7
|
+
var ALPHA_EDGE = 0;
|
|
8
|
+
var FALLOFF_EXPONENT = 3.4;
|
|
9
|
+
var GHOST_LINE_CHARS = 56;
|
|
10
|
+
function hashString(input) {
|
|
11
|
+
let hash = 5381;
|
|
12
|
+
for (let i = 0; i < input.length; i++) hash = hash * 33 ^ input.charCodeAt(i);
|
|
13
|
+
return Math.abs(hash);
|
|
14
|
+
}
|
|
15
|
+
function MenuField({
|
|
16
|
+
name,
|
|
17
|
+
gradient,
|
|
18
|
+
seedKey,
|
|
19
|
+
variant = "repeat",
|
|
20
|
+
className
|
|
21
|
+
}) {
|
|
22
|
+
if (variant === "display") {
|
|
23
|
+
const words = name.trim().split(/\s+/).filter(Boolean);
|
|
24
|
+
const longestWord = Math.max(1, ...words.map((word) => word.length));
|
|
25
|
+
const lineCount = Math.max(1, words.length);
|
|
26
|
+
const byWidth = (96 / (longestWord * 0.62)).toFixed(1);
|
|
27
|
+
const byHeight = (90 / (lineCount * 0.9)).toFixed(1);
|
|
28
|
+
const fontSize = `clamp(9cqw, min(19cqw, ${byWidth}cqw, ${byHeight}cqh), 19cqw)`;
|
|
29
|
+
return /* @__PURE__ */ jsx(
|
|
30
|
+
"div",
|
|
31
|
+
{
|
|
32
|
+
className: cn("relative isolate overflow-hidden", className),
|
|
33
|
+
style: { backgroundImage: gradient, containerType: "size" },
|
|
34
|
+
children: /* @__PURE__ */ jsx(
|
|
35
|
+
"span",
|
|
36
|
+
{
|
|
37
|
+
"aria-hidden": true,
|
|
38
|
+
className: "pointer-events-none absolute inset-0 flex select-none items-center justify-center p-[4cqw] text-center font-black uppercase leading-[0.9] tracking-[-0.03em] text-white/[0.26]",
|
|
39
|
+
style: { fontSize },
|
|
40
|
+
children: name
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
const unit = `${name} \xB7 `;
|
|
47
|
+
const repeats = Math.max(2, Math.ceil(GHOST_LINE_CHARS / Math.max(unit.length, 1)));
|
|
48
|
+
const ghostLine = unit.repeat(repeats);
|
|
49
|
+
const seed = hashString(seedKey != null ? seedKey : name);
|
|
50
|
+
const rows = Array.from({ length: GHOST_ROWS }, (_, row) => {
|
|
51
|
+
const distance = Math.abs(row - GHOST_CENTRE) / GHOST_CENTRE;
|
|
52
|
+
const alpha = ALPHA_EDGE + (ALPHA_PEAK - ALPHA_EDGE) * Math.pow(1 - distance, FALLOFF_EXPONENT);
|
|
53
|
+
return { row, alpha, offset: (seed >> row % 12) % 90 - 45 };
|
|
54
|
+
});
|
|
55
|
+
return /* @__PURE__ */ jsx(
|
|
56
|
+
"div",
|
|
57
|
+
{
|
|
58
|
+
className: cn("relative isolate overflow-hidden", className),
|
|
59
|
+
style: { backgroundImage: gradient },
|
|
60
|
+
children: /* @__PURE__ */ jsx(
|
|
61
|
+
"div",
|
|
62
|
+
{
|
|
63
|
+
"aria-hidden": true,
|
|
64
|
+
className: "pointer-events-none absolute left-1/2 top-1/2 flex h-[180%] w-[180%] -translate-x-1/2 -translate-y-1/2 -rotate-[11deg] select-none flex-col justify-center",
|
|
65
|
+
children: rows.map(({ row, alpha, offset }) => /* @__PURE__ */ jsx(
|
|
66
|
+
"span",
|
|
67
|
+
{
|
|
68
|
+
className: "block whitespace-nowrap text-center text-[15px] font-bold leading-[1.45] tracking-[-0.01em]",
|
|
69
|
+
style: {
|
|
70
|
+
color: `oklch(1 0 0 / ${alpha.toFixed(3)})`,
|
|
71
|
+
// Emboss, both edges scaled by this row's alpha: a dark edge below
|
|
72
|
+
// cuts the letterform into the field, a light edge above lifts its
|
|
73
|
+
// top. The dark edge is kept well under the fill — at parity it
|
|
74
|
+
// ringed every glyph and dragged the type back toward grey, which
|
|
75
|
+
// is the opposite of what the fill is doing.
|
|
76
|
+
textShadow: [
|
|
77
|
+
`0 1px 1px oklch(0 0 0 / ${(alpha * 0.4).toFixed(3)})`,
|
|
78
|
+
`0 -1px 0 oklch(1 0 0 / ${(alpha * 0.4).toFixed(3)})`
|
|
79
|
+
].join(", "),
|
|
80
|
+
transform: `translateX(${offset}px)`
|
|
81
|
+
},
|
|
82
|
+
children: ghostLine
|
|
83
|
+
},
|
|
84
|
+
row
|
|
85
|
+
))
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export { MenuField };
|
|
@@ -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?: "default" | "
|
|
7
|
+
variant?: "default" | "secondary" | "destructive" | "outline" | "overlay" | "glass" | "success" | "warning" | "brown" | null | undefined;
|
|
8
8
|
live?: boolean | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
10
|
interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
|
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "default" | "secondary" | "destructive" | "outline" | "overlay" | "glass" | "brown" | "link" | "ghost" | "antagonist" | null | undefined;
|
|
7
7
|
size?: "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
|
|
8
8
|
fullWidth?: boolean | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
@@ -57,7 +57,10 @@ function CategoryDeck({
|
|
|
57
57
|
{
|
|
58
58
|
className: cn(
|
|
59
59
|
"absolute left-1/2 top-0 aspect-[4/5] w-24 overflow-hidden rounded-[10px] bg-muted",
|
|
60
|
+
// Keyed to --foreground so the shadow is ink in light mode; in
|
|
61
|
+
// dark mode that same 18% is a light halo, so it drops to 7%.
|
|
60
62
|
"shadow-[0_10px_26px_color-mix(in_oklch,var(--foreground)_18%,transparent)]",
|
|
63
|
+
"dark:shadow-[0_10px_26px_color-mix(in_oklch,var(--foreground)_7%,transparent)]",
|
|
61
64
|
"sm:w-[120px]",
|
|
62
65
|
transform.rest,
|
|
63
66
|
transform.spread,
|
|
@@ -86,7 +89,13 @@ function CategoryDeck({
|
|
|
86
89
|
/* @__PURE__ */ jsx("div", { className: "truncate text-[14.5px] font-extrabold tracking-[-0.015em] sm:text-base", children: name }),
|
|
87
90
|
/* @__PURE__ */ jsx("div", { className: "truncate font-mono text-[11.5px] text-muted-foreground", children: meta })
|
|
88
91
|
] }),
|
|
89
|
-
/* @__PURE__ */ jsx(
|
|
92
|
+
/* @__PURE__ */ jsx(
|
|
93
|
+
ChevronRight,
|
|
94
|
+
{
|
|
95
|
+
className: "ml-auto h-4 w-4 shrink-0 text-muted-foreground",
|
|
96
|
+
"aria-hidden": true
|
|
97
|
+
}
|
|
98
|
+
)
|
|
90
99
|
] })
|
|
91
100
|
] });
|
|
92
101
|
const rootClasses = cn(
|
|
@@ -8,7 +8,7 @@ declare const Command: React.ForwardRefExoticComponent<Omit<{
|
|
|
8
8
|
ref?: React.Ref<HTMLDivElement>;
|
|
9
9
|
} & {
|
|
10
10
|
asChild?: boolean;
|
|
11
|
-
}, "key" | keyof React.HTMLAttributes<HTMLDivElement
|
|
11
|
+
}, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>> & {
|
|
12
12
|
label?: string;
|
|
13
13
|
shouldFilter?: boolean;
|
|
14
14
|
filter?: (value: string, search: string, keywords?: string[]) => number;
|
|
@@ -38,7 +38,7 @@ declare const CommandList: React.ForwardRefExoticComponent<Omit<{
|
|
|
38
38
|
ref?: React.Ref<HTMLDivElement>;
|
|
39
39
|
} & {
|
|
40
40
|
asChild?: boolean;
|
|
41
|
-
}, "key" | keyof React.HTMLAttributes<HTMLDivElement
|
|
41
|
+
}, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>> & {
|
|
42
42
|
label?: string;
|
|
43
43
|
} & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
44
44
|
declare const CommandEmpty: React.ForwardRefExoticComponent<Omit<{
|
|
@@ -47,14 +47,14 @@ declare const CommandEmpty: React.ForwardRefExoticComponent<Omit<{
|
|
|
47
47
|
ref?: React.Ref<HTMLDivElement>;
|
|
48
48
|
} & {
|
|
49
49
|
asChild?: boolean;
|
|
50
|
-
}, "key" | keyof React.HTMLAttributes<HTMLDivElement
|
|
50
|
+
}, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>> & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
51
51
|
declare const CommandLoading: React.ForwardRefExoticComponent<Omit<{
|
|
52
52
|
children?: React.ReactNode;
|
|
53
53
|
} & Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
|
|
54
54
|
ref?: React.Ref<HTMLDivElement>;
|
|
55
55
|
} & {
|
|
56
56
|
asChild?: boolean;
|
|
57
|
-
}, "key" | keyof React.HTMLAttributes<HTMLDivElement
|
|
57
|
+
}, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>> & {
|
|
58
58
|
progress?: number;
|
|
59
59
|
label?: string;
|
|
60
60
|
} & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -64,7 +64,7 @@ declare const CommandGroup: React.ForwardRefExoticComponent<Omit<{
|
|
|
64
64
|
ref?: React.Ref<HTMLDivElement>;
|
|
65
65
|
} & {
|
|
66
66
|
asChild?: boolean;
|
|
67
|
-
}, "key" | keyof React.HTMLAttributes<HTMLDivElement
|
|
67
|
+
}, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>>, "heading" | "value"> & {
|
|
68
68
|
heading?: React.ReactNode;
|
|
69
69
|
value?: string;
|
|
70
70
|
forceMount?: boolean;
|
|
@@ -73,7 +73,7 @@ declare const CommandSeparator: React.ForwardRefExoticComponent<Omit<Pick<Pick<R
|
|
|
73
73
|
ref?: React.Ref<HTMLDivElement>;
|
|
74
74
|
} & {
|
|
75
75
|
asChild?: boolean;
|
|
76
|
-
}, "key" | keyof React.HTMLAttributes<HTMLDivElement
|
|
76
|
+
}, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>> & {
|
|
77
77
|
alwaysRender?: boolean;
|
|
78
78
|
} & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
79
79
|
declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
|
|
@@ -82,7 +82,7 @@ declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
|
|
|
82
82
|
ref?: React.Ref<HTMLDivElement>;
|
|
83
83
|
} & {
|
|
84
84
|
asChild?: boolean;
|
|
85
|
-
}, "key" | keyof React.HTMLAttributes<HTMLDivElement
|
|
85
|
+
}, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>>, "onSelect" | "disabled" | "value"> & {
|
|
86
86
|
disabled?: boolean;
|
|
87
87
|
onSelect?: (value: string) => void;
|
|
88
88
|
value?: string;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { MenuItemLabels } from './menu-item.js';
|
|
3
|
+
import { MenuConceptPreview, MenuLinkComponent, MenuLinkProps } from './menu-types.js';
|
|
4
|
+
import 'react';
|
|
5
|
+
import './place-types.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ConceptCompare — one dish or drink across every kitchen that makes it, under
|
|
9
|
+
* whatever name each of them uses.
|
|
10
|
+
*
|
|
11
|
+
* The keystone module: a single menu can list papanași, only a catalogue can
|
|
12
|
+
* say that seventy kitchens make them under fifty different names between 8 and
|
|
13
|
+
* 44 lei. The alias column is what makes it honest — these are not the same row
|
|
14
|
+
* seventy times, they are seventy differently-named rows we matched, and
|
|
15
|
+
* showing each kitchen's own wording is the evidence for that.
|
|
16
|
+
*
|
|
17
|
+
* ## The row is place-led
|
|
18
|
+
*
|
|
19
|
+
* Each row leads with the VENUE PHOTOGRAPH, which is real and licensed. It
|
|
20
|
+
* replaced a price bar, and the trade is not close: the bar measured the one
|
|
21
|
+
* value already printed beside it in words, while the thing a reader is
|
|
22
|
+
* actually choosing between — the restaurant — had no image at all. Five
|
|
23
|
+
* restaurants that disagree about a name is the story; five bars of similar
|
|
24
|
+
* length is not.
|
|
25
|
+
*
|
|
26
|
+
* ## Two layouts, one component
|
|
27
|
+
*
|
|
28
|
+
* From `lg` the row is a table: rank, venue, alias, mentions, price. Below it,
|
|
29
|
+
* the rows become the production `<MenuItem>` — the alias as the name, the
|
|
30
|
+
* venue underneath — because a five-column table does not survive 390px and
|
|
31
|
+
* the item row already solves this exact shape everywhere else in the app.
|
|
32
|
+
*/
|
|
33
|
+
/** @deprecated Alias of `MenuLinkProps`; kept so existing imports keep working. */
|
|
34
|
+
type ConceptCompareLinkProps = MenuLinkProps;
|
|
35
|
+
type ConceptCompareFigure = {
|
|
36
|
+
/** Pre-formatted, e.g. "44". */
|
|
37
|
+
value: string;
|
|
38
|
+
label: string;
|
|
39
|
+
};
|
|
40
|
+
type ConceptCompareLabels = {
|
|
41
|
+
/** Small caps kicker, e.g. "DISH CONCEPT". */
|
|
42
|
+
kind: string;
|
|
43
|
+
/** Column heading over the aliases, e.g. "ON THEIR MENU AS". */
|
|
44
|
+
alias: string;
|
|
45
|
+
/** Under each price, e.g. "per portion". */
|
|
46
|
+
perPortion?: string;
|
|
47
|
+
/** Badge on the lowest-priced row, e.g. "cheapest shown". */
|
|
48
|
+
cheapest?: string;
|
|
49
|
+
};
|
|
50
|
+
type ConceptCompareProps = {
|
|
51
|
+
concept: MenuConceptPreview;
|
|
52
|
+
labels: ConceptCompareLabels;
|
|
53
|
+
/** Passed to the mobile `<MenuItem>` rows. */
|
|
54
|
+
itemLabels: MenuItemLabels;
|
|
55
|
+
formatPrice: (amount: number) => string;
|
|
56
|
+
formatCount?: (value: number) => string;
|
|
57
|
+
/** CSS gradient for the header swatch, when there is no photograph. */
|
|
58
|
+
gradient: string;
|
|
59
|
+
/** A real photograph of the concept, when the matched menu row carries one. */
|
|
60
|
+
imageUrl?: string;
|
|
61
|
+
figures?: ConceptCompareFigure[];
|
|
62
|
+
/** Destination per row, keyed by place slug. */
|
|
63
|
+
hrefs?: Record<string, string>;
|
|
64
|
+
/** The provenance note in the footer. */
|
|
65
|
+
footnote?: string;
|
|
66
|
+
/** Actions in the footer — pass rendered links or buttons. */
|
|
67
|
+
actions?: React.ReactNode;
|
|
68
|
+
linkComponent?: MenuLinkComponent;
|
|
69
|
+
className?: string;
|
|
70
|
+
};
|
|
71
|
+
declare function ConceptCompare({ concept, labels, itemLabels, formatPrice, formatCount, gradient, imageUrl, figures, hrefs, footnote, actions, linkComponent: LinkComponent, className, }: ConceptCompareProps): react_jsx_runtime.JSX.Element;
|
|
72
|
+
|
|
73
|
+
export { ConceptCompare, type ConceptCompareFigure, type ConceptCompareLabels, type ConceptCompareLinkProps, type ConceptCompareProps };
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { MenuItem } from '../chunk-TH6W2PWG.js';
|
|
2
|
+
import '../chunk-Q6QH52LJ.js';
|
|
3
|
+
import { MenuField } from '../chunk-YS6BHKZO.js';
|
|
4
|
+
import '../chunk-UKBNQO6Q.js';
|
|
5
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
6
|
+
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
7
|
+
import { Star, MessageSquare } from 'lucide-react';
|
|
8
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
9
|
+
|
|
10
|
+
function DefaultLink(_a) {
|
|
11
|
+
var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
|
|
12
|
+
return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
|
|
13
|
+
}
|
|
14
|
+
function ConceptCompare({
|
|
15
|
+
concept,
|
|
16
|
+
labels,
|
|
17
|
+
itemLabels,
|
|
18
|
+
formatPrice,
|
|
19
|
+
formatCount,
|
|
20
|
+
gradient,
|
|
21
|
+
imageUrl,
|
|
22
|
+
figures,
|
|
23
|
+
hrefs,
|
|
24
|
+
footnote,
|
|
25
|
+
actions,
|
|
26
|
+
linkComponent: LinkComponent = DefaultLink,
|
|
27
|
+
className
|
|
28
|
+
}) {
|
|
29
|
+
var _a;
|
|
30
|
+
const rows = (_a = concept.rows) != null ? _a : [];
|
|
31
|
+
const cheapest = rows.reduce(
|
|
32
|
+
(lowest, row) => lowest === void 0 || row.price < lowest ? row.price : lowest,
|
|
33
|
+
void 0
|
|
34
|
+
);
|
|
35
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("overflow-hidden rounded-[18px] border border-border bg-card", className), children: [
|
|
36
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 p-4 lg:flex-row lg:items-center lg:gap-6 lg:p-5", children: [
|
|
37
|
+
imageUrl ? (
|
|
38
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
39
|
+
/* @__PURE__ */ jsx(
|
|
40
|
+
"img",
|
|
41
|
+
{
|
|
42
|
+
src: imageUrl,
|
|
43
|
+
alt: "",
|
|
44
|
+
className: "aspect-[16/9] w-full shrink-0 rounded-xl object-cover lg:aspect-auto lg:h-[88px] lg:w-[88px]"
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
) : /* @__PURE__ */ jsx(
|
|
48
|
+
MenuField,
|
|
49
|
+
{
|
|
50
|
+
name: concept.title,
|
|
51
|
+
gradient,
|
|
52
|
+
seedKey: concept.slug,
|
|
53
|
+
className: "aspect-[16/9] w-full shrink-0 rounded-xl lg:aspect-auto lg:h-[88px] lg:w-[88px]"
|
|
54
|
+
}
|
|
55
|
+
),
|
|
56
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
57
|
+
/* @__PURE__ */ jsx("span", { className: "text-[9.5px] font-bold uppercase tracking-[0.12em] text-muted-foreground", children: labels.kind }),
|
|
58
|
+
/* @__PURE__ */ jsx("h3", { className: "mt-1 font-serif text-2xl font-semibold tracking-[-0.02em] lg:text-[30px]", children: concept.title })
|
|
59
|
+
] }),
|
|
60
|
+
figures && figures.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 gap-6 lg:gap-8", children: figures.map((figure) => /* @__PURE__ */ jsxs("div", { className: "text-left lg:text-right", children: [
|
|
61
|
+
/* @__PURE__ */ jsx("div", { className: "text-xl font-extrabold leading-none tracking-[-0.03em] tabular-nums lg:text-2xl", children: figure.value }),
|
|
62
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1 text-[10.5px] text-muted-foreground", children: figure.label })
|
|
63
|
+
] }, figure.label)) })
|
|
64
|
+
] }),
|
|
65
|
+
/* @__PURE__ */ jsx("ul", { className: "border-t border-border lg:hidden", children: rows.map((row) => /* @__PURE__ */ jsx("li", { className: "border-b border-border last:border-b-0", children: /* @__PURE__ */ jsx(
|
|
66
|
+
MenuItem,
|
|
67
|
+
{
|
|
68
|
+
item: {
|
|
69
|
+
id: row.place_slug,
|
|
70
|
+
slug: row.place_slug,
|
|
71
|
+
// The kitchen's OWN wording leads the row — that IS the point
|
|
72
|
+
// of the module.
|
|
73
|
+
name: row.alias,
|
|
74
|
+
kind: concept.kind,
|
|
75
|
+
mentions: row.mentions,
|
|
76
|
+
sizes_and_prices: [{ size: 0, price: row.price }]
|
|
77
|
+
},
|
|
78
|
+
labels: itemLabels,
|
|
79
|
+
formatPrice,
|
|
80
|
+
formatCount,
|
|
81
|
+
venueName: row.place_name,
|
|
82
|
+
href: hrefs == null ? void 0 : hrefs[row.place_slug],
|
|
83
|
+
linkComponent: LinkComponent,
|
|
84
|
+
className: cn(row.price === cheapest && "bg-accent-subtle/40")
|
|
85
|
+
}
|
|
86
|
+
) }, row.place_slug)) }),
|
|
87
|
+
/* @__PURE__ */ jsx("ol", { className: "hidden border-t border-border lg:block", children: rows.map((row, index) => {
|
|
88
|
+
const isCheapest = row.price === cheapest;
|
|
89
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
90
|
+
/* @__PURE__ */ jsx("span", { className: "w-5 shrink-0 text-center text-xs font-bold tabular-nums text-muted-foreground", children: index + 1 }),
|
|
91
|
+
/* @__PURE__ */ jsxs("span", { className: "relative h-10 w-10 shrink-0 overflow-hidden rounded-lg bg-[repeating-linear-gradient(135deg,oklch(0.78_0.018_55)_0_8px,oklch(0.84_0.012_58)_8px_16px)]", children: [
|
|
92
|
+
row.place_thumbnail_url && // eslint-disable-next-line @next/next/no-img-element
|
|
93
|
+
/* @__PURE__ */ jsx(
|
|
94
|
+
"img",
|
|
95
|
+
{
|
|
96
|
+
src: row.place_thumbnail_url,
|
|
97
|
+
alt: "",
|
|
98
|
+
loading: "lazy",
|
|
99
|
+
className: "h-full w-full object-cover"
|
|
100
|
+
}
|
|
101
|
+
),
|
|
102
|
+
row.open_now && /* @__PURE__ */ jsx(
|
|
103
|
+
"i",
|
|
104
|
+
{
|
|
105
|
+
"aria-hidden": true,
|
|
106
|
+
className: "absolute right-0.5 top-0.5 h-[6px] w-[6px] rounded-full bg-[var(--free,currentColor)] ring-2 ring-white/80"
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
] }),
|
|
110
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 w-[200px] shrink-0", children: [
|
|
111
|
+
/* @__PURE__ */ jsx("span", { className: "block truncate text-sm font-bold tracking-[-0.01em]", children: row.place_name }),
|
|
112
|
+
/* @__PURE__ */ jsxs("span", { className: "mt-px flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
|
|
113
|
+
row.rating != null && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
114
|
+
/* @__PURE__ */ jsx(Star, { className: "h-2.5 w-2.5", "aria-hidden": true }),
|
|
115
|
+
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children: row.rating })
|
|
116
|
+
] }),
|
|
117
|
+
row.place_area && /* @__PURE__ */ jsx("span", { className: "truncate", children: row.place_area })
|
|
118
|
+
] })
|
|
119
|
+
] }),
|
|
120
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
|
|
121
|
+
/* @__PURE__ */ jsx("span", { className: "block text-[9.5px] font-bold uppercase tracking-[0.1em] text-muted-foreground", children: labels.alias }),
|
|
122
|
+
/* @__PURE__ */ jsx("span", { className: "block truncate font-serif text-[13px] italic", children: row.alias })
|
|
123
|
+
] }),
|
|
124
|
+
row.mentions != null && row.mentions > 0 && /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-1 text-[11px] tabular-nums text-muted-foreground", children: [
|
|
125
|
+
/* @__PURE__ */ jsx(MessageSquare, { className: "h-[11px] w-[11px]", "aria-hidden": true }),
|
|
126
|
+
row.mentions
|
|
127
|
+
] }),
|
|
128
|
+
/* @__PURE__ */ jsxs("span", { className: "w-[92px] shrink-0 text-right", children: [
|
|
129
|
+
/* @__PURE__ */ jsx(
|
|
130
|
+
"b",
|
|
131
|
+
{
|
|
132
|
+
className: cn(
|
|
133
|
+
"block text-sm font-extrabold tabular-nums",
|
|
134
|
+
isCheapest && "text-[var(--free,currentColor)]"
|
|
135
|
+
),
|
|
136
|
+
children: formatPrice(row.price)
|
|
137
|
+
}
|
|
138
|
+
),
|
|
139
|
+
/* @__PURE__ */ jsx("span", { className: "block text-[10px] text-muted-foreground", children: isCheapest && labels.cheapest ? labels.cheapest : labels.perPortion })
|
|
140
|
+
] })
|
|
141
|
+
] });
|
|
142
|
+
const rowClasses = "flex items-center gap-4 px-5 py-3";
|
|
143
|
+
return /* @__PURE__ */ jsx("li", { className: "border-b border-border last:border-b-0", children: (hrefs == null ? void 0 : hrefs[row.place_slug]) ? /* @__PURE__ */ jsx(
|
|
144
|
+
LinkComponent,
|
|
145
|
+
{
|
|
146
|
+
href: hrefs[row.place_slug],
|
|
147
|
+
className: cn(
|
|
148
|
+
rowClasses,
|
|
149
|
+
"transition-colors hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
|
|
150
|
+
),
|
|
151
|
+
children: content
|
|
152
|
+
}
|
|
153
|
+
) : /* @__PURE__ */ jsx("div", { className: rowClasses, children: content }) }, row.place_slug);
|
|
154
|
+
}) }),
|
|
155
|
+
(footnote || actions) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 p-4", children: [
|
|
156
|
+
footnote && /* @__PURE__ */ jsx("span", { className: "text-[11.5px] text-muted-foreground", children: footnote }),
|
|
157
|
+
actions && /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center gap-2", children: actions })
|
|
158
|
+
] })
|
|
159
|
+
] });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export { ConceptCompare };
|
|
@@ -3,9 +3,17 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
3
3
|
/**
|
|
4
4
|
* Coverflow — the busiest-events browser: a 3D perspective lane with a large
|
|
5
5
|
* lead poster flanked by up to three shrinking, desaturating posters on each
|
|
6
|
-
* side.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* side.
|
|
7
|
+
*
|
|
8
|
+
* NOTHING MOVES ON ITS OWN. The lane used to drift ±40px on a loop; it was
|
|
9
|
+
* removed at product request — a stage that sways is read as a carousel that
|
|
10
|
+
* is about to advance, and the reader waits for it instead of touching it.
|
|
11
|
+
* The stage is driven by the reader: a horizontal drag (touch, pen or mouse)
|
|
12
|
+
* steps the ring one card in the drag's direction and the lane follows the
|
|
13
|
+
* finger a little on the way, so the gesture has weight. The prev/next arrows
|
|
14
|
+
* stay for desktop and keyboard; below `lg` they are hidden so nothing sits
|
|
15
|
+
* over the lead card — the swipe is the control there, and every card is
|
|
16
|
+
* still a focusable, named button for keyboard and screen-reader users.
|
|
9
17
|
*
|
|
10
18
|
* IT IS A RING, NOT A LANE. A card's slot comes from `ringOffset` — the
|
|
11
19
|
* SIGNED SHORTEST WAY ROUND the list, not the raw `index - activeIndex`. With
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { useDragSwipe } from '../chunk-IYDH5IU6.js';
|
|
1
2
|
import { EventPosterFallback } from '../chunk-FDITZ2VM.js';
|
|
2
3
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
3
|
-
import {
|
|
4
|
-
import { useId,
|
|
4
|
+
import { __spreadProps, __spreadValues, __objRest } from '../chunk-3GWWZKX7.js';
|
|
5
|
+
import { useId, useState } from 'react';
|
|
5
6
|
import { ChevronLeft, ChevronRight, Gift } from 'lucide-react';
|
|
6
7
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
7
8
|
|
|
@@ -21,10 +22,8 @@ var COVERFLOW_CARD_FOCUS_CLASS = "focus-visible:outline-none focus-visible:ring-
|
|
|
21
22
|
var COVERFLOW_SIDE_SHADOW_CLASS = "shadow-[0_11px_27px_oklch(0.3_0.02_60/0.22)]";
|
|
22
23
|
var COVERFLOW_LEAD_SHADOW_CLASS = "shadow-[0_24px_56px_oklch(0.28_0.03_45/0.32)]";
|
|
23
24
|
var COVERFLOW_PILL_CLASS = "inline-flex h-6 max-w-[85%] items-center gap-1 rounded-full px-2 text-[11px] font-semibold";
|
|
24
|
-
var COVERFLOW_DRIFT_DURATION_SECONDS = 26;
|
|
25
|
-
var COVERFLOW_DRIFT_PIXELS = 40;
|
|
26
25
|
var COVERFLOW_LEAD_Z_INDEX = 6;
|
|
27
|
-
var COVERFLOW_ARROW_CLASS = "absolute top-1/2 z-20
|
|
26
|
+
var COVERFLOW_ARROW_CLASS = "absolute top-1/2 z-20 hidden h-11 w-11 -translate-y-1/2 lg:flex cursor-pointer items-center justify-center rounded-full bg-background/85 text-foreground shadow-[var(--shadow-overlay)] backdrop-blur-sm transition-colors duration-150 hover:bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 motion-reduce:transition-none";
|
|
28
27
|
function wrapIndex(index, length) {
|
|
29
28
|
return (index % length + length) % length;
|
|
30
29
|
}
|
|
@@ -141,7 +140,6 @@ function Coverflow({
|
|
|
141
140
|
}) {
|
|
142
141
|
const scopeId = useId().replace(/[^a-zA-Z0-9]/g, "");
|
|
143
142
|
const scopeClass = `coverflow-${scopeId}`;
|
|
144
|
-
const containerRef = useRef(null);
|
|
145
143
|
const length = items.length;
|
|
146
144
|
const active = length > 0 ? wrapIndex(activeIndex, length) : 0;
|
|
147
145
|
const [step, setStep] = useState({ from: active, to: active, length });
|
|
@@ -150,21 +148,13 @@ function Coverflow({
|
|
|
150
148
|
step.length === length ? { from: step.to, to: active, length } : { from: active, to: active, length }
|
|
151
149
|
);
|
|
152
150
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
node.dataset.offscreen = entry.isIntersecting ? "false" : "true";
|
|
159
|
-
},
|
|
160
|
-
{ threshold: 0 }
|
|
161
|
-
);
|
|
162
|
-
observer.observe(node);
|
|
163
|
-
return () => observer.disconnect();
|
|
164
|
-
}, []);
|
|
151
|
+
const goTo = (index) => onActiveIndexChange == null ? void 0 : onActiveIndexChange(wrapIndex(index, length));
|
|
152
|
+
const { dragX, isDragging, handlers } = useDragSwipe({
|
|
153
|
+
onSwipe: (direction) => goTo(active + direction),
|
|
154
|
+
disabled: length < 2
|
|
155
|
+
});
|
|
165
156
|
if (length === 0) return null;
|
|
166
157
|
const activeItem = items[active];
|
|
167
|
-
const goTo = (index) => onActiveIndexChange == null ? void 0 : onActiveIndexChange(wrapIndex(index, length));
|
|
168
158
|
const activeDelta = ringOffset(step.to - step.from, length);
|
|
169
159
|
const visibleCards = items.map((item, index) => {
|
|
170
160
|
const offset = ringOffset(index - active, length);
|
|
@@ -208,28 +198,11 @@ function Coverflow({
|
|
|
208
198
|
--cf-tier-base: 0.5714;
|
|
209
199
|
}
|
|
210
200
|
}
|
|
211
|
-
.${scopeClass} .coverflow-lane {
|
|
212
|
-
animation: ${scopeClass}-drift ${COVERFLOW_DRIFT_DURATION_SECONDS}s ease-in-out infinite alternate;
|
|
213
|
-
}
|
|
214
|
-
.${scopeClass}[data-offscreen="true"] .coverflow-lane {
|
|
215
|
-
animation-play-state: paused;
|
|
216
|
-
}
|
|
217
|
-
@keyframes ${scopeClass}-drift {
|
|
218
|
-
from { transform: translateX(-${COVERFLOW_DRIFT_PIXELS}px); }
|
|
219
|
-
to { transform: translateX(${COVERFLOW_DRIFT_PIXELS}px); }
|
|
220
|
-
}
|
|
221
|
-
@media (prefers-reduced-motion: reduce) {
|
|
222
|
-
.${scopeClass} .coverflow-lane {
|
|
223
|
-
animation: none;
|
|
224
|
-
transform: none;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
201
|
` }),
|
|
228
202
|
/* @__PURE__ */ jsxs(
|
|
229
203
|
"div",
|
|
230
|
-
{
|
|
231
|
-
|
|
232
|
-
className: "relative flex h-[300px] items-center justify-center overflow-x-clip overflow-y-visible [perspective:900px] sm:h-[380px] sm:[perspective:1400px]",
|
|
204
|
+
__spreadProps(__spreadValues({}, handlers), {
|
|
205
|
+
className: "relative flex h-[300px] select-none items-center justify-center overflow-x-clip overflow-y-visible [touch-action:pan-y] [perspective:900px] sm:h-[380px] sm:[perspective:1400px]",
|
|
233
206
|
children: [
|
|
234
207
|
/* @__PURE__ */ jsx(
|
|
235
208
|
"div",
|
|
@@ -267,21 +240,31 @@ function Coverflow({
|
|
|
267
240
|
}
|
|
268
241
|
)
|
|
269
242
|
] }),
|
|
270
|
-
/* @__PURE__ */ jsx(
|
|
271
|
-
|
|
243
|
+
/* @__PURE__ */ jsx(
|
|
244
|
+
"div",
|
|
272
245
|
{
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
246
|
+
className: cn(
|
|
247
|
+
"coverflow-lane relative h-full w-full [transform-style:preserve-3d]",
|
|
248
|
+
!isDragging && "transition-transform duration-300 ease-out motion-reduce:transition-none"
|
|
249
|
+
),
|
|
250
|
+
style: { transform: `translateX(${dragX / 3}px)` },
|
|
251
|
+
children: visibleCards.map(({ item, index, offset, suppressTransition }) => /* @__PURE__ */ jsx(
|
|
252
|
+
CoverflowCard,
|
|
253
|
+
{
|
|
254
|
+
item,
|
|
255
|
+
index,
|
|
256
|
+
offset,
|
|
257
|
+
suppressTransition,
|
|
258
|
+
freeLabel,
|
|
259
|
+
onActivate: goTo,
|
|
260
|
+
linkComponent: LinkComponent
|
|
261
|
+
},
|
|
262
|
+
item.id
|
|
263
|
+
))
|
|
264
|
+
}
|
|
265
|
+
)
|
|
283
266
|
]
|
|
284
|
-
}
|
|
267
|
+
})
|
|
285
268
|
),
|
|
286
269
|
/* @__PURE__ */ jsxs("div", { className: "mt-4 space-y-4 text-center", children: [
|
|
287
270
|
/* @__PURE__ */ jsxs("div", { "aria-live": "polite", children: [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
declare const DateInput: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<HTMLInputElement>, "
|
|
3
|
+
declare const DateInput: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "type"> & {
|
|
4
4
|
/** Native input type. Defaults to "date". */
|
|
5
5
|
type?: "date" | "datetime-local" | "time" | "month" | "week";
|
|
6
6
|
size?: "sm" | "default" | "lg";
|
|
@@ -2,22 +2,36 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* DriftRail — an infinite horizontal marquee for logos, tag chips or small
|
|
5
|
-
* poster tiles. The caller passes one set of
|
|
6
|
-
* a second, `aria-hidden` copy right after it
|
|
7
|
-
* seamless. Because the loop depends on the duplicate being
|
|
8
|
-
* to the first pass, keep `children` a fixed, ordered list —
|
|
9
|
-
* randomisation.
|
|
5
|
+
* poster tiles that the reader can take hold of. The caller passes one set of
|
|
6
|
+
* children; the component renders a second, `aria-hidden` copy right after it
|
|
7
|
+
* so the loop is seamless. Because the loop depends on the duplicate being
|
|
8
|
+
* pixel-identical to the first pass, keep `children` a fixed, ordered list —
|
|
9
|
+
* no per-render randomisation.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* IT IS A SCROLLER THAT DRIFTS, NOT AN ANIMATION. It used to be a CSS
|
|
12
|
+
* `translateX` keyframe, which is cheap but cannot be grabbed: a finger on it
|
|
13
|
+
* did nothing, and a marquee that ignores the hand on it reads as a broken
|
|
14
|
+
* scroller. Now the rail is a real horizontal scroll container with the
|
|
15
|
+
* scrollbar hidden, and a `requestAnimationFrame` loop advances `scrollLeft`
|
|
16
|
+
* at `width / durationSeconds` per second. When the scroll position passes
|
|
17
|
+
* the first copy it is wrapped back by exactly one copy's width — the two
|
|
18
|
+
* copies are identical, so the jump is invisible — and the same wrap holds
|
|
19
|
+
* while the reader scrolls, in either direction, so there is no end to hit.
|
|
20
|
+
*
|
|
21
|
+
* THE READER WINS. A touch scrolls natively (momentum and all); a mouse drag
|
|
22
|
+
* scrolls the rail by the drag distance; a wheel works because it is a
|
|
23
|
+
* scroller. Any of those stops the drift, and it resumes a few seconds after
|
|
24
|
+
* the last interaction. Hover pauses it too (`pauseOnHover`), and an
|
|
25
|
+
* `IntersectionObserver` stops the loop off-screen so the page is not doing
|
|
26
|
+
* work nobody can see. `prefers-reduced-motion` removes the drift entirely;
|
|
27
|
+
* the rail stays scrollable by hand, which is more than the static strip it
|
|
28
|
+
* used to collapse to.
|
|
16
29
|
*/
|
|
17
30
|
type DriftRailProps = {
|
|
18
31
|
children: React.ReactNode;
|
|
19
32
|
/** Runs the loop right-to-left instead of left-to-right. */
|
|
20
33
|
reverse?: boolean;
|
|
34
|
+
/** Seconds for one full pass of the children. */
|
|
21
35
|
durationSeconds?: number;
|
|
22
36
|
/** Pauses the loop while the pointer hovers the rail. */
|
|
23
37
|
pauseOnHover?: boolean;
|