@bearmenu/ui 0.8.6 → 0.8.8
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-AHL45DD2.js +145 -0
- package/dist/chunk-IYDH5IU6.js +66 -0
- package/dist/chunk-OPVKL4VS.js +18 -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/category-deck.js +10 -1
- package/dist/components/command.d.ts +15 -15
- package/dist/components/coverflow.d.ts +11 -3
- package/dist/components/coverflow.js +34 -51
- 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 +68 -35
- package/dist/components/event-compact-row.d.ts +34 -6
- package/dist/components/event-compact-row.js +120 -38
- 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-hub-hero.d.ts +25 -4
- package/dist/components/event-hub-hero.js +89 -19
- package/dist/components/event-list-row.d.ts +19 -6
- package/dist/components/event-list-row.js +78 -34
- package/dist/components/event-types.d.ts +5 -1
- 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/item.d.ts +2 -2
- 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/section-header.d.ts +16 -1
- package/dist/components/section-header.js +26 -7
- package/dist/components/snap-rail.d.ts +34 -0
- package/dist/components/snap-rail.js +51 -0
- 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-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/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/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.test.tsx +11 -0
- package/src/components/event-card.tsx +67 -14
- package/src/components/event-compact-row.stories.tsx +30 -0
- package/src/components/event-compact-row.test.tsx +100 -0
- package/src/components/event-compact-row.tsx +166 -40
- package/src/components/event-day-header.tsx +3 -1
- package/src/components/event-day-separator.tsx +8 -1
- 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/event-types.ts +5 -1
- package/src/components/hour-band.stories.tsx +28 -5
- package/src/components/hour-band.tsx +90 -70
- package/src/components/poster-wall.test.tsx +28 -0
- package/src/components/poster-wall.tsx +96 -23
- 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/snap-rail.stories.tsx +79 -0
- package/src/components/snap-rail.test.tsx +18 -0
- package/src/components/snap-rail.tsx +67 -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/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
|
@@ -5,7 +5,7 @@ type PosterWallTile = {
|
|
|
5
5
|
src?: string;
|
|
6
6
|
};
|
|
7
7
|
type PosterWallProps = {
|
|
8
|
-
/** Background tiles.
|
|
8
|
+
/** Background tiles. The grid sizes itself to how many there are (see above); with none, a placeholder grid renders. */
|
|
9
9
|
tiles?: PosterWallTile[];
|
|
10
10
|
/** `compact` is the bottom-aligned mobile treatment (fewer, larger tiles, a top-fading veil). */
|
|
11
11
|
variant?: "default" | "compact";
|
|
@@ -13,13 +13,13 @@ type PosterWallProps = {
|
|
|
13
13
|
children?: React.ReactNode;
|
|
14
14
|
className?: string;
|
|
15
15
|
};
|
|
16
|
-
declare function PosterWall({ tiles, variant, children, className }: PosterWallProps): react_jsx_runtime.JSX.Element;
|
|
16
|
+
declare function PosterWall({ tiles, variant, children, className, }: PosterWallProps): react_jsx_runtime.JSX.Element;
|
|
17
17
|
type PosterWallSkeletonProps = {
|
|
18
18
|
/** `compact` is the bottom-aligned mobile treatment (fewer, larger tiles, a top-fading veil). */
|
|
19
19
|
variant?: "default" | "compact";
|
|
20
20
|
className?: string;
|
|
21
21
|
};
|
|
22
22
|
/** The tile grid at rest — the sweeping light never renders in the loading state. */
|
|
23
|
-
declare function PosterWallSkeleton({ variant, className }: PosterWallSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
23
|
+
declare function PosterWallSkeleton({ variant, className, }: PosterWallSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
24
24
|
|
|
25
25
|
export { PosterWall, type PosterWallProps, PosterWallSkeleton, type PosterWallSkeletonProps, type PosterWallTile };
|
|
@@ -25,24 +25,60 @@ function useInViewport() {
|
|
|
25
25
|
React.useEffect(() => {
|
|
26
26
|
const node = ref.current;
|
|
27
27
|
if (!node || typeof IntersectionObserver === "undefined") return;
|
|
28
|
-
const observer = new IntersectionObserver(
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const observer = new IntersectionObserver(
|
|
29
|
+
([entry]) => setInView(entry.isIntersecting),
|
|
30
|
+
{
|
|
31
|
+
threshold: 0
|
|
32
|
+
}
|
|
33
|
+
);
|
|
31
34
|
observer.observe(node);
|
|
32
35
|
return () => observer.disconnect();
|
|
33
36
|
}, []);
|
|
34
37
|
return [ref, inView];
|
|
35
38
|
}
|
|
36
|
-
function PosterWall({
|
|
39
|
+
function PosterWall({
|
|
40
|
+
tiles,
|
|
41
|
+
variant = "default",
|
|
42
|
+
children,
|
|
43
|
+
className
|
|
44
|
+
}) {
|
|
37
45
|
const isCompact = variant === "compact";
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
const maxCols = isCompact ? 6 : 12;
|
|
47
|
+
const maxSlots = isCompact ? POSTER_WALL_COMPACT_TILE_COUNT : POSTER_WALL_DESKTOP_TILE_COUNT;
|
|
48
|
+
const heightPx = isCompact ? 330 : 420;
|
|
49
|
+
const pictures = React.useMemo(
|
|
50
|
+
() => (tiles != null ? tiles : []).filter((tile) => !!tile.src),
|
|
51
|
+
[tiles]
|
|
52
|
+
);
|
|
43
53
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
44
54
|
const [wallRef, inView] = useInViewport();
|
|
45
55
|
const isSweepPaused = prefersReducedMotion || !inView;
|
|
56
|
+
const [width, setWidth] = React.useState(isCompact ? 390 : 1200);
|
|
57
|
+
React.useEffect(() => {
|
|
58
|
+
const node = wallRef.current;
|
|
59
|
+
if (!node || typeof ResizeObserver === "undefined") return;
|
|
60
|
+
const observer = new ResizeObserver(
|
|
61
|
+
([entry]) => setWidth(entry.contentRect.width)
|
|
62
|
+
);
|
|
63
|
+
observer.observe(node);
|
|
64
|
+
return () => observer.disconnect();
|
|
65
|
+
}, [wallRef]);
|
|
66
|
+
let cols = maxCols;
|
|
67
|
+
let slots;
|
|
68
|
+
if (pictures.length === 0) {
|
|
69
|
+
slots = Array.from({ length: maxSlots }, () => ({}));
|
|
70
|
+
} else {
|
|
71
|
+
const shown = Math.min(pictures.length, maxSlots);
|
|
72
|
+
cols = Math.min(
|
|
73
|
+
maxCols,
|
|
74
|
+
Math.max(2, Math.round(Math.sqrt(shown * width / heightPx)))
|
|
75
|
+
);
|
|
76
|
+
const rows = Math.max(1, Math.ceil(shown / cols));
|
|
77
|
+
slots = Array.from(
|
|
78
|
+
{ length: cols * rows },
|
|
79
|
+
(_, index) => pictures[index % pictures.length]
|
|
80
|
+
);
|
|
81
|
+
}
|
|
46
82
|
return /* @__PURE__ */ jsxs(
|
|
47
83
|
"div",
|
|
48
84
|
{
|
|
@@ -62,10 +98,8 @@ function PosterWall({ tiles, variant = "default", children, className }) {
|
|
|
62
98
|
/* @__PURE__ */ jsx(
|
|
63
99
|
"div",
|
|
64
100
|
{
|
|
65
|
-
className:
|
|
66
|
-
|
|
67
|
-
isCompact ? "grid-cols-6" : "grid-cols-12"
|
|
68
|
-
),
|
|
101
|
+
className: "absolute inset-0 grid auto-rows-fr gap-[2px] opacity-50",
|
|
102
|
+
style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` },
|
|
69
103
|
"aria-hidden": true,
|
|
70
104
|
children: slots.map(
|
|
71
105
|
(tile, index) => tile.src ? (
|
|
@@ -130,7 +164,10 @@ function PosterWall({ tiles, variant = "default", children, className }) {
|
|
|
130
164
|
}
|
|
131
165
|
);
|
|
132
166
|
}
|
|
133
|
-
function PosterWallSkeleton({
|
|
167
|
+
function PosterWallSkeleton({
|
|
168
|
+
variant = "default",
|
|
169
|
+
className
|
|
170
|
+
}) {
|
|
134
171
|
const isCompact = variant === "compact";
|
|
135
172
|
const tileCount = isCompact ? POSTER_WALL_COMPACT_TILE_COUNT : POSTER_WALL_DESKTOP_TILE_COUNT;
|
|
136
173
|
return /* @__PURE__ */ jsxs(
|
|
@@ -150,7 +187,13 @@ function PosterWallSkeleton({ variant = "default", className }) {
|
|
|
150
187
|
"absolute inset-0 grid auto-rows-fr gap-[2px] opacity-50",
|
|
151
188
|
isCompact ? "grid-cols-6" : "grid-cols-12"
|
|
152
189
|
),
|
|
153
|
-
children: Array.from({ length: tileCount }, (_, index) => /* @__PURE__ */ jsx(
|
|
190
|
+
children: Array.from({ length: tileCount }, (_, index) => /* @__PURE__ */ jsx(
|
|
191
|
+
Skeleton,
|
|
192
|
+
{
|
|
193
|
+
className: "h-full w-full rounded-none bg-white/10"
|
|
194
|
+
},
|
|
195
|
+
index
|
|
196
|
+
))
|
|
154
197
|
}
|
|
155
198
|
),
|
|
156
199
|
/* @__PURE__ */ jsx(
|
|
@@ -170,8 +213,21 @@ function PosterWallSkeleton({ variant = "default", className }) {
|
|
|
170
213
|
isCompact ? "justify-end gap-[11px] p-5" : "justify-center gap-[15px] px-12"
|
|
171
214
|
),
|
|
172
215
|
children: [
|
|
173
|
-
/* @__PURE__ */ jsx(
|
|
174
|
-
|
|
216
|
+
/* @__PURE__ */ jsx(
|
|
217
|
+
Skeleton,
|
|
218
|
+
{
|
|
219
|
+
className: cn(
|
|
220
|
+
"bg-white/15",
|
|
221
|
+
isCompact ? "h-[11px] w-40" : "h-3 w-52"
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
),
|
|
225
|
+
/* @__PURE__ */ jsx(
|
|
226
|
+
Skeleton,
|
|
227
|
+
{
|
|
228
|
+
className: cn("bg-white/20", isCompact ? "h-7 w-64" : "h-10 w-96")
|
|
229
|
+
}
|
|
230
|
+
)
|
|
175
231
|
]
|
|
176
232
|
}
|
|
177
233
|
)
|
|
@@ -25,6 +25,21 @@ type SectionHeaderProps = {
|
|
|
25
25
|
/** Trailing action label, e.g. "See all". */
|
|
26
26
|
action?: string;
|
|
27
27
|
actionHref?: string;
|
|
28
|
+
/**
|
|
29
|
+
* `muted` (default): 14px in `--muted-foreground`, at every width. `app`:
|
|
30
|
+
* BELOW `lg`, 12.5px semibold in `--accent` — the way an app's "All ›" reads
|
|
31
|
+
* at the end of a card's title row, quieter in size and louder in colour so
|
|
32
|
+
* it sits in the count's tier rather than competing with the title. From
|
|
33
|
+
* `lg` it falls back to `muted`: the app treatment is a phone treatment, and
|
|
34
|
+
* the desktop page it shares a header with is unchanged by it.
|
|
35
|
+
*/
|
|
36
|
+
actionTone?: "muted" | "app";
|
|
37
|
+
/**
|
|
38
|
+
* `always` (default) shows the subtitle at every width. `lg` hides it below
|
|
39
|
+
* the `lg` breakpoint for surfaces that narrate on desktop and not on a
|
|
40
|
+
* phone, where a card title with a count is the whole header.
|
|
41
|
+
*/
|
|
42
|
+
subtitleFrom?: "always" | "lg";
|
|
28
43
|
/** Defaults to a plain `<a>`. Pass `next/link` in a Next app. */
|
|
29
44
|
linkComponent?: React.ComponentType<SectionHeaderLinkProps>;
|
|
30
45
|
onAction?: (mouseEvent: React.MouseEvent) => void;
|
|
@@ -37,7 +52,7 @@ type SectionHeaderProps = {
|
|
|
37
52
|
as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "div";
|
|
38
53
|
className?: string;
|
|
39
54
|
};
|
|
40
|
-
declare function SectionHeader({ title, count, subtitle, action, actionHref, linkComponent: LinkComponent, onAction, as: Heading, className, }: SectionHeaderProps): react_jsx_runtime.JSX.Element;
|
|
55
|
+
declare function SectionHeader({ title, count, subtitle, action, actionHref, actionTone, subtitleFrom, linkComponent: LinkComponent, onAction, as: Heading, className, }: SectionHeaderProps): react_jsx_runtime.JSX.Element;
|
|
41
56
|
type SectionHeaderSkeletonProps = {
|
|
42
57
|
/** Shows the inline count placeholder, matching `SectionHeaderProps["count"]`. */
|
|
43
58
|
showCount?: boolean;
|
|
@@ -8,38 +8,57 @@ function DefaultLink(_a) {
|
|
|
8
8
|
var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
|
|
9
9
|
return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
|
|
10
10
|
}
|
|
11
|
-
var
|
|
12
|
-
"inline-flex shrink-0 items-center gap-0.5 rounded-sm
|
|
13
|
-
"transition-colors duration-150
|
|
11
|
+
var ACTION_BASE_CLASSES = cn(
|
|
12
|
+
"inline-flex min-h-11 shrink-0 items-center gap-0.5 rounded-sm -my-2 py-2 -mr-1 pr-1",
|
|
13
|
+
"transition-colors duration-150 motion-reduce:transition-none",
|
|
14
14
|
"cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
15
15
|
);
|
|
16
|
+
var ACTION_TONE_CLASSES = {
|
|
17
|
+
muted: "text-[14px] text-muted-foreground hover:text-foreground",
|
|
18
|
+
app: cn(
|
|
19
|
+
"text-[12.5px] font-semibold text-accent hover:text-accent/80",
|
|
20
|
+
"lg:text-[14px] lg:font-normal lg:text-muted-foreground lg:hover:text-foreground"
|
|
21
|
+
)
|
|
22
|
+
};
|
|
16
23
|
function SectionHeader({
|
|
17
24
|
title,
|
|
18
25
|
count,
|
|
19
26
|
subtitle,
|
|
20
27
|
action,
|
|
21
28
|
actionHref,
|
|
29
|
+
actionTone = "muted",
|
|
30
|
+
subtitleFrom = "always",
|
|
22
31
|
linkComponent: LinkComponent = DefaultLink,
|
|
23
32
|
onAction,
|
|
24
33
|
as: Heading = "h2",
|
|
25
34
|
className
|
|
26
35
|
}) {
|
|
27
36
|
const actionIcon = /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5", "aria-hidden": true });
|
|
37
|
+
const actionClasses = cn(ACTION_BASE_CLASSES, ACTION_TONE_CLASSES[actionTone]);
|
|
28
38
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col mb-3.5", className), children: [
|
|
29
39
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
30
40
|
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-baseline", children: [
|
|
31
41
|
/* @__PURE__ */ jsx(Heading, { className: "truncate text-[17px] font-bold tracking-[-0.01em] text-foreground md:text-[18px]", children: title }),
|
|
32
|
-
count !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-
|
|
42
|
+
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 })
|
|
33
43
|
] }),
|
|
34
|
-
action && (actionHref ? /* @__PURE__ */ jsxs(LinkComponent, { href: actionHref, className:
|
|
44
|
+
action && (actionHref ? /* @__PURE__ */ jsxs(LinkComponent, { href: actionHref, className: actionClasses, onClick: onAction, children: [
|
|
35
45
|
action,
|
|
36
46
|
actionIcon
|
|
37
|
-
] }) : onAction ? /* @__PURE__ */ jsxs("button", { type: "button", className:
|
|
47
|
+
] }) : onAction ? /* @__PURE__ */ jsxs("button", { type: "button", className: actionClasses, onClick: onAction, children: [
|
|
38
48
|
action,
|
|
39
49
|
actionIcon
|
|
40
50
|
] }) : null)
|
|
41
51
|
] }),
|
|
42
|
-
subtitle && /* @__PURE__ */ jsx(
|
|
52
|
+
subtitle && /* @__PURE__ */ jsx(
|
|
53
|
+
"p",
|
|
54
|
+
{
|
|
55
|
+
className: cn(
|
|
56
|
+
"mt-0.5 text-[13px] text-muted-foreground md:text-[14px]",
|
|
57
|
+
subtitleFrom === "lg" && "hidden lg:block"
|
|
58
|
+
),
|
|
59
|
+
children: subtitle
|
|
60
|
+
}
|
|
61
|
+
)
|
|
43
62
|
] });
|
|
44
63
|
}
|
|
45
64
|
function SectionHeaderSkeleton({
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* SnapRail — a horizontal, finger-driven rail with mandatory snap points, the
|
|
7
|
+
* way a native app lays out a row of cards. Not `DriftRail`: that one moves on
|
|
8
|
+
* its own and is for ambience; this one waits to be swiped and is for content
|
|
9
|
+
* the reader is expected to reach.
|
|
10
|
+
*
|
|
11
|
+
* Every direct child becomes a snap target and takes the rail's item width, so
|
|
12
|
+
* callers pass bare cards — no wrapper, no per-item width. Widths are
|
|
13
|
+
* percentages of the rail, so the peek of the next card is what tells the
|
|
14
|
+
* reader there is more; there is no scrollbar and no edge fade.
|
|
15
|
+
*
|
|
16
|
+
* `bleed` cancels the host's horizontal padding and restores it as scroll
|
|
17
|
+
* padding, so the first card lines up with the host's content edge and the
|
|
18
|
+
* rail still snaps to that same edge after a swipe. Without it, the rail
|
|
19
|
+
* snaps flush to the host's rounded corner and loads looking pre-scrolled.
|
|
20
|
+
* `card` is the 14px inset of a hub card; `page` is the 16px page gutter.
|
|
21
|
+
*/
|
|
22
|
+
declare const snapRailVariants: (props?: ({
|
|
23
|
+
itemWidth?: "sm" | "lg" | "md" | null | undefined;
|
|
24
|
+
gap?: "default" | "sm" | null | undefined;
|
|
25
|
+
bleed?: "none" | "page" | "card" | null | undefined;
|
|
26
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
27
|
+
type SnapRailProps = React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof snapRailVariants>;
|
|
28
|
+
declare const SnapRail: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & VariantProps<(props?: ({
|
|
29
|
+
itemWidth?: "sm" | "lg" | "md" | null | undefined;
|
|
30
|
+
gap?: "default" | "sm" | null | undefined;
|
|
31
|
+
bleed?: "none" | "page" | "card" | null | undefined;
|
|
32
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string> & React.RefAttributes<HTMLDivElement>>;
|
|
33
|
+
|
|
34
|
+
export { SnapRail, type SnapRailProps };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
2
|
+
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cva } from 'class-variance-authority';
|
|
5
|
+
import { jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var snapRailVariants = cva(
|
|
8
|
+
cn(
|
|
9
|
+
"flex snap-x snap-mandatory overflow-x-auto pb-0.5 scrollbar-hide",
|
|
10
|
+
"[&>*]:shrink-0 [&>*]:snap-start"
|
|
11
|
+
),
|
|
12
|
+
{
|
|
13
|
+
variants: {
|
|
14
|
+
itemWidth: {
|
|
15
|
+
sm: "[&>*]:w-[46%]",
|
|
16
|
+
md: "[&>*]:w-[60%]",
|
|
17
|
+
lg: "[&>*]:w-[80%]"
|
|
18
|
+
},
|
|
19
|
+
gap: {
|
|
20
|
+
sm: "gap-2",
|
|
21
|
+
default: "gap-3"
|
|
22
|
+
},
|
|
23
|
+
bleed: {
|
|
24
|
+
none: "",
|
|
25
|
+
card: "-mx-3.5 px-3.5 scroll-px-3.5",
|
|
26
|
+
page: "-mx-4 px-4 scroll-px-4"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
itemWidth: "sm",
|
|
31
|
+
gap: "default",
|
|
32
|
+
bleed: "none"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
var SnapRail = React.forwardRef(
|
|
37
|
+
(_a, ref) => {
|
|
38
|
+
var _b = _a, { className, itemWidth, gap, bleed } = _b, props = __objRest(_b, ["className", "itemWidth", "gap", "bleed"]);
|
|
39
|
+
return /* @__PURE__ */ jsx(
|
|
40
|
+
"div",
|
|
41
|
+
__spreadValues({
|
|
42
|
+
ref,
|
|
43
|
+
"data-slot": "snap-rail",
|
|
44
|
+
className: cn(snapRailVariants({ itemWidth, gap, bleed }), className)
|
|
45
|
+
}, props)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
SnapRail.displayName = "SnapRail";
|
|
50
|
+
|
|
51
|
+
export { SnapRail };
|
|
@@ -4,11 +4,11 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
4
4
|
|
|
5
5
|
declare const spinnerVariants: (props?: ({
|
|
6
6
|
size?: "default" | "xs" | "sm" | "lg" | "xl" | null | undefined;
|
|
7
|
-
tone?: "
|
|
7
|
+
tone?: "inherit" | "default" | "destructive" | "primary" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
declare const Spinner: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & VariantProps<(props?: ({
|
|
10
10
|
size?: "default" | "xs" | "sm" | "lg" | "xl" | null | undefined;
|
|
11
|
-
tone?: "
|
|
11
|
+
tone?: "inherit" | "default" | "destructive" | "primary" | null | undefined;
|
|
12
12
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & {
|
|
13
13
|
/** Visually-hidden label for screen readers. Defaults to "Loading". */
|
|
14
14
|
label?: string;
|
package/dist/components/tag.d.ts
CHANGED
|
@@ -3,11 +3,11 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const tagVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "success" | "warning" | "default" | "destructive" | "outline" | "primary" | "quiet" | null | undefined;
|
|
7
7
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
declare const Tag: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & VariantProps<(props?: ({
|
|
10
|
-
variant?: "
|
|
10
|
+
variant?: "success" | "warning" | "default" | "destructive" | "outline" | "primary" | "quiet" | null | undefined;
|
|
11
11
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
12
12
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & {
|
|
13
13
|
onRemove?: () => void;
|
|
@@ -22,9 +22,9 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
22
22
|
* Weights are 400 / 600 / 700. 500 is not in the system.
|
|
23
23
|
*/
|
|
24
24
|
declare const textVariants: (props?: ({
|
|
25
|
-
variant?: "
|
|
26
|
-
color?: "
|
|
27
|
-
weight?: "bold" | "
|
|
25
|
+
variant?: "body" | "caption" | "h1" | "h2" | "h3" | "h4" | "label" | "small" | "display" | "body-lg" | "body-sm" | "overline" | null | undefined;
|
|
26
|
+
color?: "inherit" | "default" | "destructive" | "muted" | "primary" | "primary-foreground" | null | undefined;
|
|
27
|
+
weight?: "bold" | "medium" | "normal" | "semibold" | null | undefined;
|
|
28
28
|
leading?: "none" | "normal" | "tight" | "snug" | "relaxed" | "loose" | null | undefined;
|
|
29
29
|
tracking?: "normal" | "tight" | "wide" | "wider" | null | undefined;
|
|
30
30
|
wrap?: "balance" | "pretty" | "nowrap" | null | undefined;
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* The mobile axis gutter, shared by `HourBand` and `TimelinePlayhead` so the
|
|
6
|
+
* hour chips and the current-time label sit in one column. 58px is the width
|
|
7
|
+
* of a five-glyph 24-hour label ("20:00") in the chip's mono type plus its
|
|
8
|
+
* padding; a 12-hour locale's "09:00 AM" overflows it, which is one of the
|
|
9
|
+
* reasons the events surfaces format 24-hour everywhere.
|
|
10
|
+
*/
|
|
11
|
+
declare const TIMELINE_MOBILE_GUTTER_CLASS = "w-[58px]";
|
|
4
12
|
type TimelineHourPuckProps = {
|
|
5
13
|
/** The hour, already formatted and localised — or an em dash for a quiet day. */
|
|
6
14
|
time: string;
|
|
@@ -8,6 +16,16 @@ type TimelineHourPuckProps = {
|
|
|
8
16
|
isLive?: boolean;
|
|
9
17
|
/** Shown under the puck when live, e.g. "NOW ON". Required to render it. */
|
|
10
18
|
liveLabel?: string;
|
|
19
|
+
/**
|
|
20
|
+
* `station` (default): the bordered puck that sits ON the hairline, for the
|
|
21
|
+
* desktop spine. `chip`: a filled, fixed-width lozenge with the hairline
|
|
22
|
+
* starting BELOW it, for the mobile gutter — an app's time label, not a
|
|
23
|
+
* station on a rail. In `chip` the live label is visually hidden: the tinted
|
|
24
|
+
* chip plus a small on-air glyph are the visible signal (the glyph so the
|
|
25
|
+
* state never rests on colour alone once the pulse is reduced away) and the
|
|
26
|
+
* label stays for screen readers only.
|
|
27
|
+
*/
|
|
28
|
+
variant?: "station" | "chip";
|
|
11
29
|
className?: string;
|
|
12
30
|
};
|
|
13
31
|
/**
|
|
@@ -25,7 +43,7 @@ type TimelineHourPuckProps = {
|
|
|
25
43
|
* centre this puck with `-translate-y-1/2`, and a two-item column would centre
|
|
26
44
|
* the STACK, lifting the puck off the line it exists to sit on.
|
|
27
45
|
*/
|
|
28
|
-
declare function TimelineHourPuck({ time, isLive, liveLabel, className }: TimelineHourPuckProps): react_jsx_runtime.JSX.Element;
|
|
46
|
+
declare function TimelineHourPuck({ time, isLive, liveLabel, variant, className, }: TimelineHourPuckProps): react_jsx_runtime.JSX.Element;
|
|
29
47
|
type TimelineBandProps = {
|
|
30
48
|
/** The lane column — usually a poster card, or empty for a quiet hour. */
|
|
31
49
|
lane: React.ReactNode;
|
|
@@ -43,4 +61,4 @@ type TimelineBandSkeletonProps = {
|
|
|
43
61
|
*/
|
|
44
62
|
declare function TimelineBandSkeleton({ className }: TimelineBandSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
45
63
|
|
|
46
|
-
export { TimelineBand, type TimelineBandProps, TimelineBandSkeleton, type TimelineBandSkeletonProps, TimelineHourPuck, type TimelineHourPuckProps };
|
|
64
|
+
export { TIMELINE_MOBILE_GUTTER_CLASS, TimelineBand, type TimelineBandProps, TimelineBandSkeleton, type TimelineBandSkeletonProps, TimelineHourPuck, type TimelineHourPuckProps };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { TimelineBand, TimelineBandSkeleton, TimelineHourPuck } from '../chunk-
|
|
1
|
+
export { TIMELINE_MOBILE_GUTTER_CLASS, TimelineBand, TimelineBandSkeleton, TimelineHourPuck } from '../chunk-3TNPSN4D.js';
|
|
2
2
|
import '../chunk-WSRWFA6K.js';
|
|
3
3
|
import '../chunk-QXHMPJ35.js';
|
|
4
4
|
import '../chunk-FEK5XGZW.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* TimelinePlayhead — the "you are here" mark on the mobile timeline: the
|
|
5
|
+
* current time in the axis gutter, a dashed rule across the content column,
|
|
6
|
+
* and a filled NOW pill at the far edge.
|
|
7
|
+
*
|
|
8
|
+
* It sits BETWEEN hour bands, at the point where the wall clock falls, so the
|
|
9
|
+
* reader can see at a glance which hours are behind them and which are ahead.
|
|
10
|
+
* The live hour band's tinted chip says "this hour is running"; the playhead
|
|
11
|
+
* says exactly how far into it we are. Both are needed: a band spans an hour
|
|
12
|
+
* and the hour is mostly not "now".
|
|
13
|
+
*
|
|
14
|
+
* The time label shares the gutter width with `HourBand` so it lines up under
|
|
15
|
+
* the hour chips. Both strings arrive formatted — the DS holds no clock.
|
|
16
|
+
*/
|
|
17
|
+
type TimelinePlayheadProps = {
|
|
18
|
+
/** The current time, already formatted — "21:38". */
|
|
19
|
+
time: string;
|
|
20
|
+
/** The pill text, e.g. "NOW". */
|
|
21
|
+
label: string;
|
|
22
|
+
className?: string;
|
|
23
|
+
};
|
|
24
|
+
declare function TimelinePlayhead({ time, label, className }: TimelinePlayheadProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
|
|
26
|
+
export { TimelinePlayhead, type TimelinePlayheadProps };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { TIMELINE_MOBILE_GUTTER_CLASS } from '../chunk-3TNPSN4D.js';
|
|
2
|
+
import '../chunk-WSRWFA6K.js';
|
|
3
|
+
import '../chunk-QXHMPJ35.js';
|
|
4
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
5
|
+
import '../chunk-3GWWZKX7.js';
|
|
6
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
function TimelinePlayhead({ time, label, className }) {
|
|
9
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2.5 pt-3", className), children: [
|
|
10
|
+
/* @__PURE__ */ jsx(
|
|
11
|
+
"span",
|
|
12
|
+
{
|
|
13
|
+
className: cn(
|
|
14
|
+
TIMELINE_MOBILE_GUTTER_CLASS,
|
|
15
|
+
"shrink-0 text-center font-mono text-[11px] font-bold tabular-nums text-success"
|
|
16
|
+
),
|
|
17
|
+
children: time
|
|
18
|
+
}
|
|
19
|
+
),
|
|
20
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "h-0 flex-1 border-t-[1.5px] border-dashed border-success/50" }),
|
|
21
|
+
/* @__PURE__ */ jsx("span", { className: "rounded-full bg-success px-2 py-0.5 text-[9.5px] font-extrabold tracking-[0.1em] text-success-foreground", children: label })
|
|
22
|
+
] });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { TimelinePlayhead };
|
|
@@ -22,14 +22,15 @@ type WeekendPanelProps = {
|
|
|
22
22
|
linkComponent?: React.ComponentType<WeekendPanelLinkProps>;
|
|
23
23
|
onActionClick?: () => void;
|
|
24
24
|
isHighlighted?: boolean;
|
|
25
|
-
/**
|
|
25
|
+
/** Desktop autoplay loop duration — the page turns every half of it. Default 7; sibling panels typically stagger at 8.5 and 10. */
|
|
26
26
|
durationSeconds?: number;
|
|
27
27
|
/**
|
|
28
28
|
* Accessible names for the pause/play toggle. Required — the control is
|
|
29
|
-
* only
|
|
29
|
+
* only rendered on desktop and not under `prefers-reduced-motion`, but the
|
|
30
|
+
* DS owns no copy.
|
|
30
31
|
*/
|
|
31
32
|
labels: WeekendPanelLabels;
|
|
32
|
-
/** The event cards.
|
|
33
|
+
/** The event cards. Built around exactly four (two pages of two). */
|
|
33
34
|
children?: React.ReactNode;
|
|
34
35
|
className?: string;
|
|
35
36
|
};
|
|
@@ -39,6 +40,6 @@ type WeekendPanelSkeletonProps = {
|
|
|
39
40
|
className?: string;
|
|
40
41
|
};
|
|
41
42
|
/** The panel at rest: the two visible cards of the two-up carousel, no slide. */
|
|
42
|
-
declare function WeekendPanelSkeleton({ isHighlighted, className }: WeekendPanelSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
43
|
+
declare function WeekendPanelSkeleton({ isHighlighted, className, }: WeekendPanelSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
43
44
|
|
|
44
45
|
export { WeekendPanel, type WeekendPanelLabels, type WeekendPanelLinkProps, type WeekendPanelProps, WeekendPanelSkeleton, type WeekendPanelSkeletonProps };
|