@bearmenu/ui 0.8.17 → 0.8.18
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-WYTJR2YU.js → chunk-5CPBSNWQ.js} +6 -1
- package/dist/{chunk-54FQQZZJ.js → chunk-EQYB4Q77.js} +1 -1
- package/dist/chunk-LYREUZH6.js +156 -0
- package/dist/chunk-PW247TG2.js +81 -0
- package/dist/components/alert.d.ts +2 -2
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/card.d.ts +2 -2
- package/dist/components/command.d.ts +15 -15
- package/dist/components/concept-compare-rail.js +2 -2
- package/dist/components/concept-compare.js +2 -2
- package/dist/components/event-card.d.ts +22 -4
- package/dist/components/event-card.js +95 -50
- package/dist/components/event-day-header.d.ts +5 -3
- package/dist/components/event-day-header.js +12 -4
- package/dist/components/event-door.d.ts +41 -0
- package/dist/components/event-door.js +65 -0
- package/dist/components/event-hub-hero.d.ts +10 -2
- package/dist/components/event-hub-hero.js +11 -5
- package/dist/components/event-tonight-strip.d.ts +50 -0
- package/dist/components/event-tonight-strip.js +67 -0
- package/dist/components/item.d.ts +2 -2
- package/dist/components/menu-hub-hero.d.ts +7 -1
- package/dist/components/menu-hub-hero.js +2 -1
- package/dist/components/place-card.js +1 -1
- package/dist/components/poster-stack.d.ts +36 -3
- package/dist/components/poster-stack.js +49 -18
- package/dist/components/snap-rail.d.ts +2 -2
- package/dist/components/snap-rail.js +1 -1
- package/dist/components/spinner.d.ts +2 -2
- package/dist/components/tag.d.ts +2 -2
- package/dist/components/text.d.ts +3 -3
- package/dist/components/timeline-day.d.ts +54 -0
- package/dist/components/timeline-day.js +65 -0
- package/dist/components/timeline-hour-puck.d.ts +47 -0
- package/dist/components/timeline-hour-puck.js +3 -0
- package/dist/components/timeline-hour.d.ts +96 -0
- package/dist/components/{timeline-band.js → timeline-hour.js} +2 -1
- package/dist/components/timeline-playhead.js +1 -3
- package/package.json +1 -1
- package/src/components/event-card.tsx +70 -13
- package/src/components/event-day-header.tsx +19 -7
- package/src/components/event-door.stories.tsx +88 -0
- package/src/components/event-door.tsx +97 -0
- package/src/components/event-hub-hero.tsx +21 -3
- package/src/components/event-tonight-strip.stories.tsx +78 -0
- package/src/components/event-tonight-strip.test.tsx +59 -0
- package/src/components/event-tonight-strip.tsx +134 -0
- package/src/components/menu-hub-hero.test.tsx +13 -0
- package/src/components/menu-hub-hero.tsx +9 -2
- package/src/components/poster-stack.stories.tsx +43 -1
- package/src/components/poster-stack.tsx +98 -19
- package/src/components/snap-rail.tsx +6 -1
- package/src/components/timeline-day.stories.tsx +201 -0
- package/src/components/timeline-day.test.tsx +78 -0
- package/src/components/timeline-day.tsx +114 -0
- package/src/components/timeline-hour-puck.tsx +139 -0
- package/src/components/timeline-hour.tsx +266 -0
- package/src/components/timeline-playhead.tsx +1 -1
- package/dist/chunk-NSNEANOQ.js +0 -104
- package/dist/components/hour-band.d.ts +0 -66
- package/dist/components/hour-band.js +0 -81
- package/dist/components/hour-group.d.ts +0 -67
- package/dist/components/hour-group.js +0 -59
- package/dist/components/timeline-band.d.ts +0 -64
- package/src/components/hour-band.stories.tsx +0 -182
- package/src/components/hour-band.tsx +0 -146
- package/src/components/hour-group.stories.tsx +0 -100
- package/src/components/hour-group.tsx +0 -124
- package/src/components/timeline-band.stories.tsx +0 -206
- package/src/components/timeline-band.tsx +0 -247
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
import { Radio } from "lucide-react";
|
|
5
|
-
import { cn } from "../lib/utils";
|
|
6
|
-
import { Separator } from "./separator";
|
|
7
|
-
import { Skeleton } from "./skeleton";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* TimelineBand — the desktop timeline's three-column row: lane │ spine │ content.
|
|
11
|
-
*
|
|
12
|
-
* Desktop counterpart of `<HourBand>`. Where the mobile timeline collapses the
|
|
13
|
-
* axis into a 52px gutter beside full-width cards, the desktop layout gives the
|
|
14
|
-
* poster its own lane (`--timeline-lane`), a dedicated spine
|
|
15
|
-
* (`--timeline-spine`) carrying the hairline, and a separate content column for
|
|
16
|
-
* whatever follows.
|
|
17
|
-
*
|
|
18
|
-
* ── The band does not draw hours ──────────────────────────────────────────
|
|
19
|
-
* IT USED TO, and only for the hour it opened on. Every LATER hour was an
|
|
20
|
-
* inline `HourGroup` heading in the content column instead, so one concept was
|
|
21
|
-
* drawn in two grammars 48px apart — a bordered puck ON the axis at the top of
|
|
22
|
-
* the day, bare muted text OFF it for the rest of it. An axis whose ticks are
|
|
23
|
-
* labelled once is not an axis, and that is exactly how it read: the later
|
|
24
|
-
* hours were harder to follow than the first.
|
|
25
|
-
*
|
|
26
|
-
* Now every hour is a station and `HourGroup` emits its own, via
|
|
27
|
-
* `TimelineHourPuck` below. The band keeps the geometry and the hairline and
|
|
28
|
-
* nothing else — which is also why `puckTop` is gone: each puck centres itself
|
|
29
|
-
* on its own heading rule, so there is no magic offset left for a caller to
|
|
30
|
-
* tune against a lane height.
|
|
31
|
-
*
|
|
32
|
-
* The invariant the old docblock was reaching for still holds, and states more
|
|
33
|
-
* simply now: AN HOUR APPEARS EXACTLY ONCE, AND ALWAYS ON THE SPINE.
|
|
34
|
-
*
|
|
35
|
-
* HOW THE CONTENT COLUMN IS MEANT TO BE FILLED — the source design composes it
|
|
36
|
-
* in tiers, and getting this wrong is what makes the band look flat:
|
|
37
|
-
*
|
|
38
|
-
* lane one feature card (an `EventCard` with `emphasis`), plus any
|
|
39
|
-
* "N earlier events" collapse control beneath it.
|
|
40
|
-
* content an `<HourGroup spine>` per hour — the opening one holding a grid
|
|
41
|
-
* of `EventCard`s, later ones holding the denser
|
|
42
|
-
* `<EventCompactRow>` as the night thins out.
|
|
43
|
-
*
|
|
44
|
-
* So the density falls off across the row: one poster, then a few cards, then
|
|
45
|
-
* rows.
|
|
46
|
-
*/
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Ring pulse on the live puck — inherited from an earlier `TimelinePlayhead`,
|
|
50
|
-
* which carried this surface's only motion. Kept at its 2.4s `ease-in-out` and
|
|
51
|
-
* its reduced-motion kill switch, but BOX-SHADOW ONLY: a `transform: scale`
|
|
52
|
-
* would make the hairline visibly breathe here, because this puck sits ON the
|
|
53
|
-
* rail. (Today's `timeline-playhead.tsx` is static and sits between bands.)
|
|
54
|
-
*/
|
|
55
|
-
const LIVE_PUCK_PULSE_CLASS = "bm-timeline-live-puck-pulse";
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* The mobile axis gutter, shared by `HourBand` and `TimelinePlayhead` so the
|
|
59
|
-
* hour chips and the current-time label sit in one column. 58px is the width
|
|
60
|
-
* of a five-glyph 24-hour label ("20:00") in the chip's mono type plus its
|
|
61
|
-
* padding; a 12-hour locale's "09:00 AM" overflows it, which is one of the
|
|
62
|
-
* reasons the events surfaces format 24-hour everywhere.
|
|
63
|
-
*/
|
|
64
|
-
export const TIMELINE_MOBILE_GUTTER_CLASS = "w-[58px]";
|
|
65
|
-
|
|
66
|
-
export type TimelineHourPuckProps = {
|
|
67
|
-
/** The hour, already formatted and localised — or an em dash for a quiet day. */
|
|
68
|
-
time: string;
|
|
69
|
-
/** Marks this as the hour currently in progress. */
|
|
70
|
-
isLive?: boolean;
|
|
71
|
-
/** Shown under the puck when live, e.g. "NOW ON". Required to render it. */
|
|
72
|
-
liveLabel?: string;
|
|
73
|
-
/**
|
|
74
|
-
* `station` (default): the bordered puck that sits ON the hairline, for the
|
|
75
|
-
* desktop spine. `chip`: a filled, fixed-width lozenge with the hairline
|
|
76
|
-
* starting BELOW it, for the mobile gutter — an app's time label, not a
|
|
77
|
-
* station on a rail. In `chip` the live label is visually hidden: the tinted
|
|
78
|
-
* chip plus a small on-air glyph are the visible signal (the glyph so the
|
|
79
|
-
* state never rests on colour alone once the pulse is reduced away) and the
|
|
80
|
-
* label stays for screen readers only.
|
|
81
|
-
*/
|
|
82
|
-
variant?: "station" | "chip";
|
|
83
|
-
className?: string;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* The station on the timeline's axis — ONE object, positioned by its host:
|
|
88
|
-
* `HourGroup` centres it on its own heading rule out in the desktop spine,
|
|
89
|
-
* `HourBand` pins it to the top of the mobile gutter.
|
|
90
|
-
*
|
|
91
|
-
* Extracted because it was hand-rolled twice and the copies had already
|
|
92
|
-
* drifted — this one bordered and `rounded-[7px] px-[7px]`, `hour-band.tsx`'s
|
|
93
|
-
* borderless and `rounded-md px-1.5`. The `bg-background` fill punches through
|
|
94
|
-
* the hairline so the rail reads as continuous behind the label rather than
|
|
95
|
-
* butting into it.
|
|
96
|
-
*
|
|
97
|
-
* The live label is absolutely positioned rather than a flex sibling: hosts
|
|
98
|
-
* centre this puck with `-translate-y-1/2`, and a two-item column would centre
|
|
99
|
-
* the STACK, lifting the puck off the line it exists to sit on.
|
|
100
|
-
*/
|
|
101
|
-
export function TimelineHourPuck({
|
|
102
|
-
time,
|
|
103
|
-
isLive,
|
|
104
|
-
liveLabel,
|
|
105
|
-
variant = "station",
|
|
106
|
-
className,
|
|
107
|
-
}: TimelineHourPuckProps) {
|
|
108
|
-
const isChip = variant === "chip";
|
|
109
|
-
|
|
110
|
-
return (
|
|
111
|
-
<span className={cn("relative flex justify-center", className)}>
|
|
112
|
-
{isLive && (
|
|
113
|
-
<style>{`
|
|
114
|
-
@keyframes ${LIVE_PUCK_PULSE_CLASS} {
|
|
115
|
-
0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklch, var(--success) 40%, transparent); }
|
|
116
|
-
50% { box-shadow: 0 0 0 4px color-mix(in oklch, var(--success) 0%, transparent); }
|
|
117
|
-
}
|
|
118
|
-
.${LIVE_PUCK_PULSE_CLASS} {
|
|
119
|
-
animation: ${LIVE_PUCK_PULSE_CLASS} 2.4s ease-in-out infinite;
|
|
120
|
-
}
|
|
121
|
-
@media (prefers-reduced-motion: reduce) {
|
|
122
|
-
.${LIVE_PUCK_PULSE_CLASS} { animation: none; }
|
|
123
|
-
}
|
|
124
|
-
`}</style>
|
|
125
|
-
)}
|
|
126
|
-
<span
|
|
127
|
-
className={cn(
|
|
128
|
-
"whitespace-nowrap font-mono tabular-nums",
|
|
129
|
-
isChip
|
|
130
|
-
? cn(
|
|
131
|
-
"inline-flex h-6 min-w-[58px] items-center justify-center gap-1 rounded-[7px] px-1 text-[12px] font-medium",
|
|
132
|
-
isLive ? cn("bg-success/10 text-success", LIVE_PUCK_PULSE_CLASS) : "bg-muted text-foreground"
|
|
133
|
-
)
|
|
134
|
-
: cn(
|
|
135
|
-
"rounded-[7px] border bg-background px-[7px] py-[3px] text-[12.5px] font-medium",
|
|
136
|
-
isLive
|
|
137
|
-
? cn("border-success/40 text-success", LIVE_PUCK_PULSE_CLASS)
|
|
138
|
-
: "border-border text-foreground"
|
|
139
|
-
)
|
|
140
|
-
)}
|
|
141
|
-
>
|
|
142
|
-
{isChip && isLive && <Radio className="h-2.5 w-2.5 shrink-0" aria-hidden />}
|
|
143
|
-
{time}
|
|
144
|
-
</span>
|
|
145
|
-
{isLive && !!liveLabel && (
|
|
146
|
-
<span
|
|
147
|
-
className={cn(
|
|
148
|
-
isChip
|
|
149
|
-
? "sr-only"
|
|
150
|
-
: cn(
|
|
151
|
-
"absolute top-[calc(100%+6px)] whitespace-nowrap bg-background px-1",
|
|
152
|
-
"text-[9.5px] font-extrabold tracking-[0.08em] text-success"
|
|
153
|
-
)
|
|
154
|
-
)}
|
|
155
|
-
>
|
|
156
|
-
{liveLabel}
|
|
157
|
-
</span>
|
|
158
|
-
)}
|
|
159
|
-
</span>
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export type TimelineBandProps = {
|
|
164
|
-
/** The lane column — usually a poster card, or empty for a quiet hour. */
|
|
165
|
-
lane: React.ReactNode;
|
|
166
|
-
/** The content column, normally one `<HourGroup spine>` per hour. */
|
|
167
|
-
children: React.ReactNode;
|
|
168
|
-
className?: string;
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
export function TimelineBand({ lane, children, className }: TimelineBandProps) {
|
|
172
|
-
return (
|
|
173
|
-
<div className={cn("flex items-stretch", className)}>
|
|
174
|
-
<div className="w-[var(--timeline-lane)] shrink-0">{lane}</div>
|
|
175
|
-
|
|
176
|
-
<div className="relative flex w-[var(--timeline-spine)] shrink-0 justify-center self-stretch">
|
|
177
|
-
<Separator orientation="vertical" className="h-full" />
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
<div className="flex min-w-0 flex-1 flex-col">{children}</div>
|
|
181
|
-
</div>
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* A fixed-size shimmer block. `radiusPx` only needs to be passed for the
|
|
187
|
-
* poster-sized blocks (12, matching `rounded-xl`) — every thinner text-line
|
|
188
|
-
* height here (13–18px) is less than twice that radius, so the browser clamps
|
|
189
|
-
* it to a pill automatically even left at the `Skeleton` default.
|
|
190
|
-
*/
|
|
191
|
-
function sk(width: string, height: number, radiusPx = 12) {
|
|
192
|
-
return (
|
|
193
|
-
<Skeleton
|
|
194
|
-
style={{ width, height: `${height}px`, borderRadius: `${radiusPx}px` }}
|
|
195
|
-
/>
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export type TimelineBandSkeletonProps = {
|
|
200
|
-
className?: string;
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Holds the lane/spine/content geometry so nothing jumps when data lands.
|
|
205
|
-
* The spine renders its hairline with no puck — there's no hour to show yet.
|
|
206
|
-
*/
|
|
207
|
-
export function TimelineBandSkeleton({ className }: TimelineBandSkeletonProps) {
|
|
208
|
-
return (
|
|
209
|
-
<div className={cn("flex items-stretch", className)} aria-hidden="true">
|
|
210
|
-
<div className="flex w-[var(--timeline-lane)] shrink-0 flex-col gap-3">
|
|
211
|
-
{sk("100%", 297, 12)}
|
|
212
|
-
{sk("70%", 18)}
|
|
213
|
-
{sk("45%", 13)}
|
|
214
|
-
</div>
|
|
215
|
-
|
|
216
|
-
<div className="relative flex w-[var(--timeline-spine)] shrink-0 justify-center self-stretch">
|
|
217
|
-
<Separator orientation="vertical" className="h-full" />
|
|
218
|
-
</div>
|
|
219
|
-
|
|
220
|
-
<div className="flex min-w-0 flex-1 flex-col gap-4">
|
|
221
|
-
<div className="grid grid-cols-3 gap-[10px]">
|
|
222
|
-
{Array.from({ length: 3 }, (_, index) => (
|
|
223
|
-
<div key={index} className="flex flex-col gap-2">
|
|
224
|
-
{sk("100%", 190, 12)}
|
|
225
|
-
{sk("85%", 15)}
|
|
226
|
-
{sk("55%", 12)}
|
|
227
|
-
</div>
|
|
228
|
-
))}
|
|
229
|
-
</div>
|
|
230
|
-
|
|
231
|
-
<div className="flex flex-col">
|
|
232
|
-
{Array.from({ length: 3 }, (_, index) => (
|
|
233
|
-
<div key={index} className="relative flex items-center gap-[11px] py-2">
|
|
234
|
-
<Separator className="absolute inset-x-0 top-0" />
|
|
235
|
-
|
|
236
|
-
<Skeleton className="h-[34px] w-[34px] shrink-0 rounded-md" />
|
|
237
|
-
<div className="flex min-w-0 flex-1 flex-col gap-1.5">
|
|
238
|
-
{sk("60%", 13)}
|
|
239
|
-
{sk("40%", 11.5)}
|
|
240
|
-
</div>
|
|
241
|
-
</div>
|
|
242
|
-
))}
|
|
243
|
-
</div>
|
|
244
|
-
</div>
|
|
245
|
-
</div>
|
|
246
|
-
);
|
|
247
|
-
}
|