@bearmenu/ui 0.8.4 → 0.8.7
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 +85 -0
- package/dist/chunk-6XMYEZVR.js +26 -0
- package/dist/chunk-DNSXMHYX.js +8 -0
- package/dist/chunk-FDITZ2VM.js +16 -0
- package/dist/chunk-GPH6L4DX.js +55 -0
- package/dist/{chunk-N2KNBPAQ.js → chunk-QXHMPJ35.js} +1 -0
- package/dist/chunk-TT3WFS6S.js +379 -0
- package/dist/chunk-UXWAOISG.js +170 -0
- package/dist/{chunk-UZ3PCIE5.js → chunk-XWMRABZW.js} +2 -2
- package/dist/{chunk-VBA45GLP.js → chunk-ZDAHKI3A.js} +12 -2
- package/dist/components/card.d.ts +2 -2
- package/dist/components/card.js +4 -127
- package/dist/components/category-deck.d.ts +50 -0
- package/dist/components/category-deck.js +128 -0
- package/dist/components/concept-card.d.ts +43 -0
- package/dist/components/concept-card.js +81 -0
- package/dist/components/coverflow.d.ts +123 -0
- package/dist/components/coverflow.js +300 -0
- package/dist/components/day-rail-chip.d.ts +82 -0
- package/dist/components/day-rail-chip.js +105 -0
- package/dist/components/drift-rail.d.ts +28 -0
- package/dist/components/drift-rail.js +3 -0
- package/dist/components/event-card.d.ts +97 -0
- package/dist/components/event-card.js +164 -0
- package/dist/components/event-compact-row.d.ts +73 -0
- package/dist/components/event-compact-row.js +134 -0
- package/dist/components/event-day-header.d.ts +65 -0
- package/dist/components/event-day-header.js +95 -0
- package/dist/components/event-day-separator.d.ts +46 -0
- package/dist/components/event-day-separator.js +50 -0
- package/dist/components/event-detail-panel.d.ts +80 -0
- package/dist/components/event-detail-panel.js +251 -0
- package/dist/components/event-hub-hero.d.ts +34 -0
- package/dist/components/event-hub-hero.js +57 -0
- package/dist/components/event-index-row.d.ts +68 -0
- package/dist/components/event-index-row.js +84 -0
- package/dist/components/event-list-row-wide.d.ts +101 -0
- package/dist/components/event-list-row-wide.js +218 -0
- package/dist/components/event-list-row.d.ts +82 -0
- package/dist/components/event-list-row.js +173 -0
- package/dist/components/event-poster-fallback.d.ts +20 -0
- package/dist/components/event-poster-fallback.js +3 -0
- package/dist/components/event-types.d.ts +122 -0
- package/dist/components/event-types.js +2 -0
- package/dist/components/events-empty-state.d.ts +44 -0
- package/dist/components/events-empty-state.js +73 -0
- package/dist/components/facet-group.d.ts +93 -0
- package/dist/components/facet-group.js +222 -0
- package/dist/components/featured-rail-item.d.ts +42 -0
- package/dist/components/featured-rail-item.js +88 -0
- package/dist/components/hour-band.d.ts +68 -0
- package/dist/components/hour-band.js +53 -0
- package/dist/components/hour-group.d.ts +67 -0
- package/dist/components/hour-group.js +59 -0
- package/dist/components/motion-icon-controls.js +3 -379
- package/dist/components/multi-select-combobox.js +1 -1
- package/dist/components/place-about-tab.js +3 -3
- package/dist/components/place-details-mobile.js +3 -3
- package/dist/components/poster-stack.d.ts +30 -0
- package/dist/components/poster-stack.js +104 -0
- package/dist/components/poster-tape.d.ts +36 -0
- package/dist/components/poster-tape.js +64 -0
- package/dist/components/poster-wall.d.ts +25 -0
- package/dist/components/poster-wall.js +183 -0
- package/dist/components/quiet-stretch.d.ts +43 -0
- package/dist/components/quiet-stretch.js +54 -0
- package/dist/components/section-header.d.ts +53 -0
- package/dist/components/section-header.js +63 -0
- package/dist/components/segmented-nav.d.ts +62 -0
- package/dist/components/segmented-nav.js +54 -0
- package/dist/components/skeleton-card.js +1 -1
- package/dist/components/skeleton.d.ts +17 -0
- package/dist/components/skeleton.js +1 -1
- package/dist/components/tag-group.js +3 -26
- package/dist/components/tag.d.ts +2 -2
- package/dist/components/tag.js +1 -1
- package/dist/components/timeline-band.d.ts +46 -0
- package/dist/components/timeline-band.js +5 -0
- package/dist/components/venue-events-block.d.ts +143 -0
- package/dist/components/venue-events-block.js +222 -0
- package/dist/components/weekend-panel.d.ts +44 -0
- package/dist/components/weekend-panel.js +231 -0
- package/package.json +1 -1
- package/src/components/card.tsx +44 -1
- package/src/components/category-deck.stories.tsx +96 -0
- package/src/components/category-deck.tsx +227 -0
- package/src/components/concept-card.stories.tsx +80 -0
- package/src/components/concept-card.tsx +143 -0
- package/src/components/coverflow.stories.tsx +240 -0
- package/src/components/coverflow.test.tsx +193 -0
- package/src/components/coverflow.tsx +550 -0
- package/src/components/day-rail-chip.stories.tsx +145 -0
- package/src/components/day-rail-chip.tsx +201 -0
- package/src/components/drift-rail.stories.tsx +92 -0
- package/src/components/drift-rail.tsx +86 -0
- package/src/components/event-card.stories.tsx +248 -0
- package/src/components/event-card.test.tsx +188 -0
- package/src/components/event-card.tsx +329 -0
- package/src/components/event-compact-row.stories.tsx +221 -0
- package/src/components/event-compact-row.test.tsx +51 -0
- package/src/components/event-compact-row.tsx +270 -0
- package/src/components/event-day-header.stories.tsx +124 -0
- package/src/components/event-day-header.tsx +180 -0
- package/src/components/event-day-separator.stories.tsx +70 -0
- package/src/components/event-day-separator.tsx +95 -0
- package/src/components/event-detail-panel.stories.tsx +191 -0
- package/src/components/event-detail-panel.tsx +360 -0
- package/src/components/event-hub-hero.stories.tsx +66 -0
- package/src/components/event-hub-hero.tsx +110 -0
- package/src/components/event-index-row.stories.tsx +116 -0
- package/src/components/event-index-row.tsx +181 -0
- package/src/components/event-list-row-wide.stories.tsx +204 -0
- package/src/components/event-list-row-wide.tsx +386 -0
- package/src/components/event-list-row.stories.tsx +159 -0
- package/src/components/event-list-row.tsx +335 -0
- package/src/components/event-poster-fallback.stories.tsx +52 -0
- package/src/components/event-poster-fallback.tsx +31 -0
- package/src/components/event-types.ts +137 -0
- package/src/components/events-empty-state.stories.tsx +59 -0
- package/src/components/events-empty-state.tsx +131 -0
- package/src/components/facet-group.stories.tsx +247 -0
- package/src/components/facet-group.test.tsx +225 -0
- package/src/components/facet-group.tsx +352 -0
- package/src/components/featured-rail-item.stories.tsx +86 -0
- package/src/components/featured-rail-item.tsx +153 -0
- package/src/components/hour-band.stories.tsx +159 -0
- package/src/components/hour-band.tsx +126 -0
- package/src/components/hour-group.stories.tsx +100 -0
- package/src/components/hour-group.tsx +124 -0
- package/src/components/poster-stack.stories.tsx +68 -0
- package/src/components/poster-stack.tsx +155 -0
- package/src/components/poster-tape.stories.tsx +70 -0
- package/src/components/poster-tape.tsx +122 -0
- package/src/components/poster-wall.stories.tsx +95 -0
- package/src/components/poster-wall.tsx +220 -0
- package/src/components/quiet-stretch.stories.tsx +62 -0
- package/src/components/quiet-stretch.tsx +115 -0
- package/src/components/section-header.stories.tsx +70 -0
- package/src/components/section-header.tsx +134 -0
- package/src/components/segmented-nav.stories.tsx +118 -0
- package/src/components/segmented-nav.tsx +113 -0
- package/src/components/skeleton.tsx +18 -0
- package/src/components/tag.tsx +11 -1
- package/src/components/timeline-band.stories.tsx +206 -0
- package/src/components/timeline-band.tsx +207 -0
- package/src/components/venue-events-block.stories.tsx +216 -0
- package/src/components/venue-events-block.tsx +408 -0
- package/src/components/weekend-panel.stories.tsx +92 -0
- package/src/components/weekend-panel.tsx +322 -0
- package/src/globals.css +19 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { Skeleton } from '../chunk-QXHMPJ35.js';
|
|
2
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
3
|
+
import '../chunk-3GWWZKX7.js';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var POSTER_WALL_DESKTOP_TILE_COUNT = 48;
|
|
8
|
+
var POSTER_WALL_COMPACT_TILE_COUNT = 36;
|
|
9
|
+
var POSTER_WALL_SWEEP_KEYFRAMES_ID = "ds-poster-wall-sweep-keyframes";
|
|
10
|
+
function usePrefersReducedMotion() {
|
|
11
|
+
const [reduced, setReduced] = React.useState(false);
|
|
12
|
+
React.useEffect(() => {
|
|
13
|
+
if (typeof window === "undefined" || !window.matchMedia) return;
|
|
14
|
+
const query = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
15
|
+
setReduced(query.matches);
|
|
16
|
+
const onChange = () => setReduced(query.matches);
|
|
17
|
+
query.addEventListener("change", onChange);
|
|
18
|
+
return () => query.removeEventListener("change", onChange);
|
|
19
|
+
}, []);
|
|
20
|
+
return reduced;
|
|
21
|
+
}
|
|
22
|
+
function useInViewport() {
|
|
23
|
+
const ref = React.useRef(null);
|
|
24
|
+
const [inView, setInView] = React.useState(true);
|
|
25
|
+
React.useEffect(() => {
|
|
26
|
+
const node = ref.current;
|
|
27
|
+
if (!node || typeof IntersectionObserver === "undefined") return;
|
|
28
|
+
const observer = new IntersectionObserver(([entry]) => setInView(entry.isIntersecting), {
|
|
29
|
+
threshold: 0
|
|
30
|
+
});
|
|
31
|
+
observer.observe(node);
|
|
32
|
+
return () => observer.disconnect();
|
|
33
|
+
}, []);
|
|
34
|
+
return [ref, inView];
|
|
35
|
+
}
|
|
36
|
+
function PosterWall({ tiles, variant = "default", children, className }) {
|
|
37
|
+
const isCompact = variant === "compact";
|
|
38
|
+
const tileCount = isCompact ? POSTER_WALL_COMPACT_TILE_COUNT : POSTER_WALL_DESKTOP_TILE_COUNT;
|
|
39
|
+
const slots = Array.from({ length: tileCount }, (_, index) => {
|
|
40
|
+
var _a;
|
|
41
|
+
return (_a = tiles == null ? void 0 : tiles[index]) != null ? _a : {};
|
|
42
|
+
});
|
|
43
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
44
|
+
const [wallRef, inView] = useInViewport();
|
|
45
|
+
const isSweepPaused = prefersReducedMotion || !inView;
|
|
46
|
+
return /* @__PURE__ */ jsxs(
|
|
47
|
+
"div",
|
|
48
|
+
{
|
|
49
|
+
ref: wallRef,
|
|
50
|
+
className: cn(
|
|
51
|
+
"relative overflow-hidden rounded-[18px] bg-[oklch(0.22_0.012_60)]",
|
|
52
|
+
isCompact ? "h-[330px]" : "h-[420px]",
|
|
53
|
+
className
|
|
54
|
+
),
|
|
55
|
+
children: [
|
|
56
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
57
|
+
@keyframes ${POSTER_WALL_SWEEP_KEYFRAMES_ID} {
|
|
58
|
+
0% { transform: translateX(-30%); }
|
|
59
|
+
100% { transform: translateX(30%); }
|
|
60
|
+
}
|
|
61
|
+
` }),
|
|
62
|
+
/* @__PURE__ */ jsx(
|
|
63
|
+
"div",
|
|
64
|
+
{
|
|
65
|
+
className: cn(
|
|
66
|
+
"absolute inset-0 grid auto-rows-fr gap-[2px] opacity-50",
|
|
67
|
+
isCompact ? "grid-cols-6" : "grid-cols-12"
|
|
68
|
+
),
|
|
69
|
+
"aria-hidden": true,
|
|
70
|
+
children: slots.map(
|
|
71
|
+
(tile, index) => tile.src ? (
|
|
72
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
73
|
+
/* @__PURE__ */ jsx(
|
|
74
|
+
"img",
|
|
75
|
+
{
|
|
76
|
+
src: tile.src,
|
|
77
|
+
alt: "",
|
|
78
|
+
loading: "lazy",
|
|
79
|
+
decoding: "async",
|
|
80
|
+
className: "h-full w-full object-cover"
|
|
81
|
+
},
|
|
82
|
+
index
|
|
83
|
+
)
|
|
84
|
+
) : /* @__PURE__ */ jsx(
|
|
85
|
+
"div",
|
|
86
|
+
{
|
|
87
|
+
className: "h-full w-full bg-[repeating-linear-gradient(45deg,color-mix(in_oklch,white_10%,transparent)_0px,color-mix(in_oklch,white_10%,transparent)_2px,transparent_2px,transparent_8px)]"
|
|
88
|
+
},
|
|
89
|
+
index
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
),
|
|
94
|
+
/* @__PURE__ */ jsx(
|
|
95
|
+
"div",
|
|
96
|
+
{
|
|
97
|
+
className: "absolute -inset-[20%]",
|
|
98
|
+
style: {
|
|
99
|
+
background: "radial-gradient(circle at 30% 50%, oklch(1 0 0 / 0.34) 0%, transparent 42%)",
|
|
100
|
+
animationName: POSTER_WALL_SWEEP_KEYFRAMES_ID,
|
|
101
|
+
animationDuration: "18s",
|
|
102
|
+
animationTimingFunction: "linear",
|
|
103
|
+
animationIterationCount: "infinite",
|
|
104
|
+
animationPlayState: isSweepPaused ? "paused" : "running"
|
|
105
|
+
},
|
|
106
|
+
"aria-hidden": true
|
|
107
|
+
}
|
|
108
|
+
),
|
|
109
|
+
/* @__PURE__ */ jsx(
|
|
110
|
+
"div",
|
|
111
|
+
{
|
|
112
|
+
className: "absolute inset-0",
|
|
113
|
+
style: {
|
|
114
|
+
background: isCompact ? "linear-gradient(to top, oklch(0.2 0.01 60 / 0.93) 0%, oklch(0.2 0.01 60 / 0.7) 55%, oklch(0.2 0.01 60 / 0.35) 100%)" : "linear-gradient(90deg, oklch(0.2 0.01 60 / 0.88) 0%, oklch(0.2 0.01 60 / 0.55) 55%, oklch(0.2 0.01 60 / 0.2) 100%)"
|
|
115
|
+
},
|
|
116
|
+
"aria-hidden": true
|
|
117
|
+
}
|
|
118
|
+
),
|
|
119
|
+
/* @__PURE__ */ jsx(
|
|
120
|
+
"div",
|
|
121
|
+
{
|
|
122
|
+
className: cn(
|
|
123
|
+
"relative flex h-full min-w-0 flex-col text-white",
|
|
124
|
+
isCompact ? "justify-end gap-[11px] p-5" : "justify-center gap-[15px] px-12"
|
|
125
|
+
),
|
|
126
|
+
children
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
function PosterWallSkeleton({ variant = "default", className }) {
|
|
134
|
+
const isCompact = variant === "compact";
|
|
135
|
+
const tileCount = isCompact ? POSTER_WALL_COMPACT_TILE_COUNT : POSTER_WALL_DESKTOP_TILE_COUNT;
|
|
136
|
+
return /* @__PURE__ */ jsxs(
|
|
137
|
+
"div",
|
|
138
|
+
{
|
|
139
|
+
"aria-hidden": "true",
|
|
140
|
+
className: cn(
|
|
141
|
+
"relative overflow-hidden rounded-[18px] bg-[oklch(0.22_0.012_60)]",
|
|
142
|
+
isCompact ? "h-[330px]" : "h-[420px]",
|
|
143
|
+
className
|
|
144
|
+
),
|
|
145
|
+
children: [
|
|
146
|
+
/* @__PURE__ */ jsx(
|
|
147
|
+
"div",
|
|
148
|
+
{
|
|
149
|
+
className: cn(
|
|
150
|
+
"absolute inset-0 grid auto-rows-fr gap-[2px] opacity-50",
|
|
151
|
+
isCompact ? "grid-cols-6" : "grid-cols-12"
|
|
152
|
+
),
|
|
153
|
+
children: Array.from({ length: tileCount }, (_, index) => /* @__PURE__ */ jsx(Skeleton, { className: "h-full w-full rounded-none bg-white/10" }, index))
|
|
154
|
+
}
|
|
155
|
+
),
|
|
156
|
+
/* @__PURE__ */ jsx(
|
|
157
|
+
"div",
|
|
158
|
+
{
|
|
159
|
+
className: "absolute inset-0",
|
|
160
|
+
style: {
|
|
161
|
+
background: isCompact ? "linear-gradient(to top, oklch(0.2 0.01 60 / 0.93) 0%, oklch(0.2 0.01 60 / 0.7) 55%, oklch(0.2 0.01 60 / 0.35) 100%)" : "linear-gradient(90deg, oklch(0.2 0.01 60 / 0.88) 0%, oklch(0.2 0.01 60 / 0.55) 55%, oklch(0.2 0.01 60 / 0.2) 100%)"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
),
|
|
165
|
+
/* @__PURE__ */ jsxs(
|
|
166
|
+
"div",
|
|
167
|
+
{
|
|
168
|
+
className: cn(
|
|
169
|
+
"relative flex h-full min-w-0 flex-col",
|
|
170
|
+
isCompact ? "justify-end gap-[11px] p-5" : "justify-center gap-[15px] px-12"
|
|
171
|
+
),
|
|
172
|
+
children: [
|
|
173
|
+
/* @__PURE__ */ jsx(Skeleton, { className: cn("bg-white/15", isCompact ? "h-[11px] w-40" : "h-3 w-52") }),
|
|
174
|
+
/* @__PURE__ */ jsx(Skeleton, { className: cn("bg-white/20", isCompact ? "h-7 w-64" : "h-10 w-96") })
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export { PosterWall, PosterWallSkeleton };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* QuietStretch — the collapsed run of quiet days on the timeline, summarising
|
|
6
|
+
* a run of near-empty days into one row so the reader doesn't scroll past
|
|
7
|
+
* dozens of "nothing on" headers to reach the next thing worth seeing.
|
|
8
|
+
*
|
|
9
|
+
* Responsive rather than a separate mobile component: past `sm` the label,
|
|
10
|
+
* days and action sit on one row; below it they stack, and the days list
|
|
11
|
+
* wraps at a tighter gap (14px vs. the desktop 22px).
|
|
12
|
+
*
|
|
13
|
+
* The action renders as a link whenever `href` is given, a button when only
|
|
14
|
+
* `onAction` is — same anchor rule as the rest of the events surface.
|
|
15
|
+
*/
|
|
16
|
+
type QuietStretchLinkProps = {
|
|
17
|
+
href: string;
|
|
18
|
+
className?: string;
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
onClick?: (mouseEvent: React.MouseEvent) => void;
|
|
21
|
+
};
|
|
22
|
+
type QuietStretchDay = {
|
|
23
|
+
id: string;
|
|
24
|
+
/** Already formatted and localised, e.g. "Mon 7". */
|
|
25
|
+
dayLabel: string;
|
|
26
|
+
count: number;
|
|
27
|
+
};
|
|
28
|
+
type QuietStretchProps = {
|
|
29
|
+
/** e.g. "QUIET STRETCH". */
|
|
30
|
+
label: string;
|
|
31
|
+
days: QuietStretchDay[];
|
|
32
|
+
/** Shown in place of a zero count, e.g. "nothing yet". */
|
|
33
|
+
emptyLabel: string;
|
|
34
|
+
/** e.g. "Expand". */
|
|
35
|
+
actionLabel: string;
|
|
36
|
+
href?: string;
|
|
37
|
+
linkComponent?: React.ComponentType<QuietStretchLinkProps>;
|
|
38
|
+
onAction?: (mouseEvent: React.MouseEvent) => void;
|
|
39
|
+
className?: string;
|
|
40
|
+
};
|
|
41
|
+
declare function QuietStretch({ label, days, emptyLabel, actionLabel, href, linkComponent: LinkComponent, onAction, className, }: QuietStretchProps): react_jsx_runtime.JSX.Element;
|
|
42
|
+
|
|
43
|
+
export { QuietStretch, type QuietStretchDay, type QuietStretchLinkProps, type QuietStretchProps };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
2
|
+
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
3
|
+
import { ChevronDown } from 'lucide-react';
|
|
4
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
function DefaultLink(_a) {
|
|
7
|
+
var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
|
|
8
|
+
return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
|
|
9
|
+
}
|
|
10
|
+
function QuietStretch({
|
|
11
|
+
label,
|
|
12
|
+
days,
|
|
13
|
+
emptyLabel,
|
|
14
|
+
actionLabel,
|
|
15
|
+
href,
|
|
16
|
+
linkComponent: LinkComponent = DefaultLink,
|
|
17
|
+
onAction,
|
|
18
|
+
className
|
|
19
|
+
}) {
|
|
20
|
+
const isInteractive = !!href || !!onAction;
|
|
21
|
+
const actionClasses = cn(
|
|
22
|
+
"inline-flex items-center gap-1 whitespace-nowrap rounded-sm text-[13px] font-bold text-primary sm:ml-auto",
|
|
23
|
+
isInteractive && cn(
|
|
24
|
+
"-m-1 cursor-pointer p-1",
|
|
25
|
+
"transition-colors duration-150 hover:text-primary/80 motion-reduce:transition-none",
|
|
26
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
27
|
+
)
|
|
28
|
+
);
|
|
29
|
+
const action = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
30
|
+
actionLabel,
|
|
31
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5", "aria-hidden": true })
|
|
32
|
+
] });
|
|
33
|
+
return /* @__PURE__ */ jsxs(
|
|
34
|
+
"div",
|
|
35
|
+
{
|
|
36
|
+
className: cn(
|
|
37
|
+
"my-2 flex flex-col gap-3 rounded-xl bg-muted px-[22px] py-5",
|
|
38
|
+
"sm:flex-row sm:items-center sm:gap-4",
|
|
39
|
+
className
|
|
40
|
+
),
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ jsx("span", { className: "whitespace-nowrap text-xs font-extrabold tracking-widest text-muted-foreground", children: label }),
|
|
43
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3.5 text-[13px] sm:gap-[22px]", children: days.map((day) => /* @__PURE__ */ jsxs("span", { className: "whitespace-nowrap", children: [
|
|
44
|
+
/* @__PURE__ */ jsx("span", { className: "font-bold", children: day.dayLabel }),
|
|
45
|
+
" ",
|
|
46
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: day.count > 0 ? day.count : emptyLabel })
|
|
47
|
+
] }, day.id)) }),
|
|
48
|
+
href ? /* @__PURE__ */ jsx(LinkComponent, { href, className: actionClasses, onClick: onAction, children: action }) : onAction ? /* @__PURE__ */ jsx("button", { type: "button", className: actionClasses, onClick: onAction, children: action }) : /* @__PURE__ */ jsx("span", { className: actionClasses, children: action })
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { QuietStretch };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SectionHeader — the title row every rail, list and hub section opens with:
|
|
6
|
+
* title (+ optional count), an optional trailing action, and an optional
|
|
7
|
+
* subtitle line beneath.
|
|
8
|
+
*
|
|
9
|
+
* Renders a link when `actionHref` is given, a button when only `onAction`
|
|
10
|
+
* is, and no action at all otherwise — same href/onClick contract as
|
|
11
|
+
* `EventCard`. No app schema, no i18n, no app hooks.
|
|
12
|
+
*/
|
|
13
|
+
type SectionHeaderLinkProps = {
|
|
14
|
+
href: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
children: React.ReactNode;
|
|
17
|
+
onClick?: (mouseEvent: React.MouseEvent) => void;
|
|
18
|
+
};
|
|
19
|
+
type SectionHeaderProps = {
|
|
20
|
+
title: string;
|
|
21
|
+
/** Renders inline after the title in muted text, e.g. "12". */
|
|
22
|
+
count?: number;
|
|
23
|
+
/** Sub-text below the title row. */
|
|
24
|
+
subtitle?: string;
|
|
25
|
+
/** Trailing action label, e.g. "See all". */
|
|
26
|
+
action?: string;
|
|
27
|
+
actionHref?: string;
|
|
28
|
+
/** Defaults to a plain `<a>`. Pass `next/link` in a Next app. */
|
|
29
|
+
linkComponent?: React.ComponentType<SectionHeaderLinkProps>;
|
|
30
|
+
onAction?: (mouseEvent: React.MouseEvent) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Heading level for `title`, or `"p"` / `"div"` for a section opener that
|
|
33
|
+
* should NOT enter the document outline — e.g. an index whose own group
|
|
34
|
+
* headings are the page's semantic `h2`s, where a generic opener above them
|
|
35
|
+
* would dilute the headings that matter. Defaults to `"h2"`.
|
|
36
|
+
*/
|
|
37
|
+
as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "div";
|
|
38
|
+
className?: string;
|
|
39
|
+
};
|
|
40
|
+
declare function SectionHeader({ title, count, subtitle, action, actionHref, linkComponent: LinkComponent, onAction, as: Heading, className, }: SectionHeaderProps): react_jsx_runtime.JSX.Element;
|
|
41
|
+
type SectionHeaderSkeletonProps = {
|
|
42
|
+
/** Shows the inline count placeholder, matching `SectionHeaderProps["count"]`. */
|
|
43
|
+
showCount?: boolean;
|
|
44
|
+
/** Shows the trailing action placeholder, matching `SectionHeaderProps["action"]`. */
|
|
45
|
+
showAction?: boolean;
|
|
46
|
+
/** Shows the subtitle placeholder, matching `SectionHeaderProps["subtitle"]`. */
|
|
47
|
+
showSubtitle?: boolean;
|
|
48
|
+
className?: string;
|
|
49
|
+
};
|
|
50
|
+
/** Mirrors `<SectionHeader>`'s geometry exactly so nothing shifts when data lands. */
|
|
51
|
+
declare function SectionHeaderSkeleton({ showCount, showAction, showSubtitle, className, }: SectionHeaderSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
52
|
+
|
|
53
|
+
export { SectionHeader, type SectionHeaderLinkProps, type SectionHeaderProps, SectionHeaderSkeleton, type SectionHeaderSkeletonProps };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Skeleton } from '../chunk-QXHMPJ35.js';
|
|
2
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
3
|
+
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
4
|
+
import { ChevronRight } from 'lucide-react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function DefaultLink(_a) {
|
|
8
|
+
var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
|
|
9
|
+
return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
|
|
10
|
+
}
|
|
11
|
+
var ACTION_CLASSES = cn(
|
|
12
|
+
"inline-flex shrink-0 items-center gap-0.5 rounded-sm text-[14px] text-muted-foreground",
|
|
13
|
+
"transition-colors duration-150 hover:text-foreground motion-reduce:transition-none",
|
|
14
|
+
"cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
15
|
+
);
|
|
16
|
+
function SectionHeader({
|
|
17
|
+
title,
|
|
18
|
+
count,
|
|
19
|
+
subtitle,
|
|
20
|
+
action,
|
|
21
|
+
actionHref,
|
|
22
|
+
linkComponent: LinkComponent = DefaultLink,
|
|
23
|
+
onAction,
|
|
24
|
+
as: Heading = "h2",
|
|
25
|
+
className
|
|
26
|
+
}) {
|
|
27
|
+
const actionIcon = /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5", "aria-hidden": true });
|
|
28
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col mb-3.5", className), children: [
|
|
29
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
30
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-baseline", children: [
|
|
31
|
+
/* @__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-0.5 shrink-0 text-[12px] text-muted-foreground", children: count })
|
|
33
|
+
] }),
|
|
34
|
+
action && (actionHref ? /* @__PURE__ */ jsxs(LinkComponent, { href: actionHref, className: ACTION_CLASSES, onClick: onAction, children: [
|
|
35
|
+
action,
|
|
36
|
+
actionIcon
|
|
37
|
+
] }) : onAction ? /* @__PURE__ */ jsxs("button", { type: "button", className: ACTION_CLASSES, onClick: onAction, children: [
|
|
38
|
+
action,
|
|
39
|
+
actionIcon
|
|
40
|
+
] }) : null)
|
|
41
|
+
] }),
|
|
42
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-[13px] text-muted-foreground md:text-[14px]", children: subtitle })
|
|
43
|
+
] });
|
|
44
|
+
}
|
|
45
|
+
function SectionHeaderSkeleton({
|
|
46
|
+
showCount,
|
|
47
|
+
showAction,
|
|
48
|
+
showSubtitle,
|
|
49
|
+
className
|
|
50
|
+
}) {
|
|
51
|
+
return /* @__PURE__ */ jsxs("div", { "aria-hidden": "true", className: cn("flex flex-col mb-3.5", className), children: [
|
|
52
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
53
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-baseline gap-1", children: [
|
|
54
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-[17px] w-32 md:h-[18px]" }),
|
|
55
|
+
showCount && /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-4" })
|
|
56
|
+
] }),
|
|
57
|
+
showAction && /* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-16" })
|
|
58
|
+
] }),
|
|
59
|
+
showSubtitle && /* @__PURE__ */ jsx(Skeleton, { className: "mt-0.5 h-[13px] w-48 md:h-3.5" })
|
|
60
|
+
] });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { SectionHeader, SectionHeaderSkeleton };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SegmentedNav — a segmented control whose segments are LINKS, not buttons.
|
|
6
|
+
*
|
|
7
|
+
* Use this when the segments are separate routes. For segments that swap
|
|
8
|
+
* content inside one page, use `<Tabs>` (Radix tab-panel semantics) or
|
|
9
|
+
* `<ToggleGroup>` (button semantics) instead — a nav landmark with
|
|
10
|
+
* `aria-current="page"` is only correct when each segment is a destination.
|
|
11
|
+
*
|
|
12
|
+
* FRAMEWORK-AGNOSTIC BY DESIGN. This renders a plain `<a>` unless the caller
|
|
13
|
+
* passes `linkComponent`. It deliberately does NOT import `next/link` the way
|
|
14
|
+
* `link-button.tsx` does — that import is what quietly makes a component
|
|
15
|
+
* Next-only, and this one has to work in admin (Vite) too.
|
|
16
|
+
*
|
|
17
|
+
* Segments stretch to fill the row on mobile and shrink to their content from
|
|
18
|
+
* `lg` up, matching the `.mtog` / `.tog` split in the source design.
|
|
19
|
+
*
|
|
20
|
+
* The `w-full` below `lg` is what makes that sentence TRUE, and it is not
|
|
21
|
+
* redundant with the segments' own `flex-1`. `flex-1` only distributes the
|
|
22
|
+
* width the nav already has; the nav itself sizes to content whenever its
|
|
23
|
+
* parent is a flex row, so a caller placing this beside other controls got
|
|
24
|
+
* three segments hugging their labels with dead space alongside — the
|
|
25
|
+
* component quietly not doing the thing its own docblock claimed. Callers that
|
|
26
|
+
* genuinely want it to hug on mobile can pass `w-auto` through `className`,
|
|
27
|
+
* which wins via `cn`'s merge.
|
|
28
|
+
*/
|
|
29
|
+
type SegmentedNavItem = {
|
|
30
|
+
/** Stable identity, compared against `activeId`. */
|
|
31
|
+
id: string;
|
|
32
|
+
href: string;
|
|
33
|
+
label: string;
|
|
34
|
+
/** Rendered before the label. Size it at the call site (the design uses 15–16px). */
|
|
35
|
+
icon?: React.ReactNode;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The shape `linkComponent` must accept. `next/link` satisfies it structurally,
|
|
39
|
+
* so callers can pass it directly.
|
|
40
|
+
*/
|
|
41
|
+
type SegmentedNavLinkProps = {
|
|
42
|
+
href: string;
|
|
43
|
+
className?: string;
|
|
44
|
+
children: React.ReactNode;
|
|
45
|
+
"aria-current"?: "page";
|
|
46
|
+
onClick?: () => void;
|
|
47
|
+
};
|
|
48
|
+
type SegmentedNavProps = {
|
|
49
|
+
items: SegmentedNavItem[];
|
|
50
|
+
/** `id` of the segment for the current route. */
|
|
51
|
+
activeId: string;
|
|
52
|
+
/** Accessible name for the nav landmark. Translated by the caller. */
|
|
53
|
+
label: string;
|
|
54
|
+
/** Defaults to a plain `<a>`. Pass `next/link` in a Next app. */
|
|
55
|
+
linkComponent?: React.ComponentType<SegmentedNavLinkProps>;
|
|
56
|
+
/** Fired with the segment id on click — analytics, haptics. Never navigation. */
|
|
57
|
+
onSelect?: (id: string) => void;
|
|
58
|
+
className?: string;
|
|
59
|
+
};
|
|
60
|
+
declare function SegmentedNav({ items, activeId, label, linkComponent: LinkComponent, onSelect, className, }: SegmentedNavProps): react_jsx_runtime.JSX.Element;
|
|
61
|
+
|
|
62
|
+
export { SegmentedNav, type SegmentedNavItem, type SegmentedNavLinkProps, type SegmentedNavProps };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
2
|
+
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
3
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
function DefaultLink(_a) {
|
|
6
|
+
var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
|
|
7
|
+
return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
|
|
8
|
+
}
|
|
9
|
+
function SegmentedNav({
|
|
10
|
+
items,
|
|
11
|
+
activeId,
|
|
12
|
+
label,
|
|
13
|
+
linkComponent: LinkComponent = DefaultLink,
|
|
14
|
+
onSelect,
|
|
15
|
+
className
|
|
16
|
+
}) {
|
|
17
|
+
return /* @__PURE__ */ jsx(
|
|
18
|
+
"nav",
|
|
19
|
+
{
|
|
20
|
+
"aria-label": label,
|
|
21
|
+
className: cn(
|
|
22
|
+
"flex w-full items-center gap-0.5 rounded-lg border border-border bg-card p-0.5",
|
|
23
|
+
"lg:inline-flex lg:w-fit",
|
|
24
|
+
className
|
|
25
|
+
),
|
|
26
|
+
children: items.map((item) => {
|
|
27
|
+
const isActive = item.id === activeId;
|
|
28
|
+
return /* @__PURE__ */ jsxs(
|
|
29
|
+
LinkComponent,
|
|
30
|
+
{
|
|
31
|
+
href: item.href,
|
|
32
|
+
"aria-current": isActive ? "page" : void 0,
|
|
33
|
+
onClick: onSelect ? () => onSelect(item.id) : void 0,
|
|
34
|
+
className: cn(
|
|
35
|
+
"inline-flex h-9 flex-1 items-center justify-center gap-1.5 rounded-md px-3",
|
|
36
|
+
"text-[13px] font-semibold lg:flex-none lg:text-sm",
|
|
37
|
+
"transition-colors duration-150 motion-reduce:transition-none",
|
|
38
|
+
"cursor-pointer touch-manipulation select-none",
|
|
39
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
40
|
+
isActive ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground"
|
|
41
|
+
),
|
|
42
|
+
children: [
|
|
43
|
+
item.icon,
|
|
44
|
+
item.label
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
item.id
|
|
48
|
+
);
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { SegmentedNav };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Skeleton } from '../chunk-
|
|
1
|
+
import { Skeleton } from '../chunk-QXHMPJ35.js';
|
|
2
2
|
import { AspectRatio } from '../chunk-3VMDCCCX.js';
|
|
3
3
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
4
4
|
import { __objRest, __spreadProps, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React__default from 'react';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* The shimmer stops under `prefers-reduced-motion: reduce`.
|
|
6
|
+
*
|
|
7
|
+
* It did not, and this is the one animation in the package that is guaranteed
|
|
8
|
+
* to be on screen during every slow load, on every surface, in multiples — a
|
|
9
|
+
* list of twelve skeleton rows is twelve sweeping gradients. A reader who has
|
|
10
|
+
* asked the OS for less motion is exactly the reader least served by that.
|
|
11
|
+
*
|
|
12
|
+
* `motion-reduce:` on the `before:` pseudo-element rather than a media query in
|
|
13
|
+
* a style block, because the animation is declared as a utility class here and
|
|
14
|
+
* a class beats a class predictably; the components that animate via an inline
|
|
15
|
+
* `animation-play-state` need the media-query form instead, and say so.
|
|
16
|
+
*
|
|
17
|
+
* The skeleton still reads as a skeleton without the sweep — it keeps its muted
|
|
18
|
+
* fill and its geometry, which is what actually communicates "content is coming
|
|
19
|
+
* and it will be this shape".
|
|
20
|
+
*/
|
|
4
21
|
declare function Skeleton({ className, ...props }: React__default.HTMLAttributes<HTMLDivElement>): react_jsx_runtime.JSX.Element;
|
|
5
22
|
|
|
6
23
|
export { Skeleton };
|
|
@@ -1,26 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
-
|
|
6
|
-
var TagGroup = React.forwardRef((_a, ref) => {
|
|
7
|
-
var _b = _a, { className, label, srLabel = true, children } = _b, props = __objRest(_b, ["className", "label", "srLabel", "children"]);
|
|
8
|
-
return /* @__PURE__ */ jsxs(
|
|
9
|
-
"div",
|
|
10
|
-
__spreadProps(__spreadValues({
|
|
11
|
-
ref,
|
|
12
|
-
role: "group",
|
|
13
|
-
"aria-label": label,
|
|
14
|
-
"data-slot": "tag-group",
|
|
15
|
-
className: cn("flex flex-wrap items-center gap-1.5", className)
|
|
16
|
-
}, props), {
|
|
17
|
-
children: [
|
|
18
|
-
label && !srLabel && /* @__PURE__ */ jsx("span", { className: "mr-1 text-xs font-semibold text-muted-foreground", children: label }),
|
|
19
|
-
children
|
|
20
|
-
]
|
|
21
|
-
})
|
|
22
|
-
);
|
|
23
|
-
});
|
|
24
|
-
TagGroup.displayName = "TagGroup";
|
|
25
|
-
|
|
26
|
-
export { TagGroup };
|
|
1
|
+
export { TagGroup } from '../chunk-6XMYEZVR.js';
|
|
2
|
+
import '../chunk-FEK5XGZW.js';
|
|
3
|
+
import '../chunk-3GWWZKX7.js';
|
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?: "default" | "destructive" | "outline" | "success" | "warning" | "primary" | null | undefined;
|
|
6
|
+
variant?: "default" | "destructive" | "outline" | "success" | "warning" | "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?: "default" | "destructive" | "outline" | "success" | "warning" | "primary" | null | undefined;
|
|
10
|
+
variant?: "default" | "destructive" | "outline" | "success" | "warning" | "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;
|
package/dist/components/tag.js
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
type TimelineHourPuckProps = {
|
|
5
|
+
/** The hour, already formatted and localised — or an em dash for a quiet day. */
|
|
6
|
+
time: string;
|
|
7
|
+
/** Marks this as the hour currently in progress. */
|
|
8
|
+
isLive?: boolean;
|
|
9
|
+
/** Shown under the puck when live, e.g. "NOW ON". Required to render it. */
|
|
10
|
+
liveLabel?: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The station on the timeline's axis — ONE object, positioned by its host:
|
|
15
|
+
* `HourGroup` centres it on its own heading rule out in the desktop spine,
|
|
16
|
+
* `HourBand` pins it to the top of the mobile gutter.
|
|
17
|
+
*
|
|
18
|
+
* Extracted because it was hand-rolled twice and the copies had already
|
|
19
|
+
* drifted — this one bordered and `rounded-[7px] px-[7px]`, `hour-band.tsx`'s
|
|
20
|
+
* borderless and `rounded-md px-1.5`. The `bg-background` fill punches through
|
|
21
|
+
* the hairline so the rail reads as continuous behind the label rather than
|
|
22
|
+
* butting into it.
|
|
23
|
+
*
|
|
24
|
+
* The live label is absolutely positioned rather than a flex sibling: hosts
|
|
25
|
+
* centre this puck with `-translate-y-1/2`, and a two-item column would centre
|
|
26
|
+
* the STACK, lifting the puck off the line it exists to sit on.
|
|
27
|
+
*/
|
|
28
|
+
declare function TimelineHourPuck({ time, isLive, liveLabel, className }: TimelineHourPuckProps): react_jsx_runtime.JSX.Element;
|
|
29
|
+
type TimelineBandProps = {
|
|
30
|
+
/** The lane column — usually a poster card, or empty for a quiet hour. */
|
|
31
|
+
lane: React.ReactNode;
|
|
32
|
+
/** The content column, normally one `<HourGroup spine>` per hour. */
|
|
33
|
+
children: React.ReactNode;
|
|
34
|
+
className?: string;
|
|
35
|
+
};
|
|
36
|
+
declare function TimelineBand({ lane, children, className }: TimelineBandProps): react_jsx_runtime.JSX.Element;
|
|
37
|
+
type TimelineBandSkeletonProps = {
|
|
38
|
+
className?: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Holds the lane/spine/content geometry so nothing jumps when data lands.
|
|
42
|
+
* The spine renders its hairline with no puck — there's no hour to show yet.
|
|
43
|
+
*/
|
|
44
|
+
declare function TimelineBandSkeleton({ className }: TimelineBandSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
45
|
+
|
|
46
|
+
export { TimelineBand, type TimelineBandProps, TimelineBandSkeleton, type TimelineBandSkeletonProps, TimelineHourPuck, type TimelineHourPuckProps };
|