@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,9 +1,27 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* PosterStack — three overlapping, gently rotated posters that float, the
|
|
5
6
|
* hub hero's aside slot in the source design.
|
|
6
7
|
*
|
|
8
|
+
* TAPPABLE SINCE 0.8.18. The stack was three decorative images: the loudest
|
|
9
|
+
* thing on the hub's first screen, and the one thing on it a reader could not
|
|
10
|
+
* tap. A poster with `href` is an anchor now — the event's detail page for
|
|
11
|
+
* the crawler and a modified click, whatever the app's `linkComponent` does
|
|
12
|
+
* for a plain tap (the hub opens its preview drawer). `caption` prints the
|
|
13
|
+
* title at the poster's foot: it gives the tap a visible reason on touch,
|
|
14
|
+
* where there is no hover, and it is the anchor's accessible name, so the
|
|
15
|
+
* `<img>` goes `alt=""` whenever a caption is set. Without `href` a poster is
|
|
16
|
+
* decorative, as before.
|
|
17
|
+
*
|
|
18
|
+
* The float and the press live on DIFFERENT elements. The wrapper carries
|
|
19
|
+
* the keyframe `transform` (rotation + drift); the anchor inside it carries
|
|
20
|
+
* the press scale and the focus ring. One element cannot animate one
|
|
21
|
+
* `transform` and transition another. The pointed poster comes to the front
|
|
22
|
+
* (`hover:z-[4]`, `focus-within:z-[4]`) — z-index is not animated, it is the
|
|
23
|
+
* "pick this one" cue.
|
|
24
|
+
*
|
|
7
25
|
* Two motion rules, both mandatory:
|
|
8
26
|
* 1. Stops entirely under `prefers-reduced-motion: reduce` — enforced via
|
|
9
27
|
* an injected `<style>` media query rather than relying on Tailwind's
|
|
@@ -15,16 +33,31 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
15
33
|
* spends a paint budget while it isn't visible. Skipped entirely when
|
|
16
34
|
* reduced motion is on, since nothing is animating to pause.
|
|
17
35
|
*/
|
|
36
|
+
type PosterStackLinkProps = {
|
|
37
|
+
href: string;
|
|
38
|
+
className?: string;
|
|
39
|
+
children: React.ReactNode;
|
|
40
|
+
onClick?: (mouseEvent: React.MouseEvent) => void;
|
|
41
|
+
};
|
|
18
42
|
type PosterStackPoster = {
|
|
19
|
-
/** Absent renders
|
|
43
|
+
/** Absent renders `fallback` instead of an image. */
|
|
20
44
|
src?: string;
|
|
21
45
|
alt: string;
|
|
46
|
+
/** The event's detail page. With it the poster is an anchor; without it, decorative. */
|
|
47
|
+
href?: string;
|
|
48
|
+
/** Caption at the poster's foot — the event title. Becomes the anchor's
|
|
49
|
+
* accessible name; the `<img>` then gets `alt=""`. */
|
|
50
|
+
caption?: string;
|
|
51
|
+
/** Rendered when `src` is absent or fails. Defaults to `<EventPosterFallback />`. */
|
|
52
|
+
fallback?: React.ReactNode;
|
|
22
53
|
};
|
|
23
54
|
type PosterStackProps = {
|
|
24
55
|
/** Rendered in order; only the first three are shown. */
|
|
25
56
|
posters: PosterStackPoster[];
|
|
57
|
+
/** Defaults to a plain `<a>`. Pass `next/link`, or an anchor that opens the app's preview. */
|
|
58
|
+
linkComponent?: React.ComponentType<PosterStackLinkProps>;
|
|
26
59
|
className?: string;
|
|
27
60
|
};
|
|
28
|
-
declare function PosterStack({ posters, className }: PosterStackProps): react_jsx_runtime.JSX.Element;
|
|
61
|
+
declare function PosterStack({ posters, linkComponent: LinkComponent, className, }: PosterStackProps): react_jsx_runtime.JSX.Element;
|
|
29
62
|
|
|
30
|
-
export { PosterStack, type PosterStackPoster, type PosterStackProps };
|
|
63
|
+
export { PosterStack, type PosterStackLinkProps, type PosterStackPoster, type PosterStackProps };
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import { EventPosterFallback } from '../chunk-FDITZ2VM.js';
|
|
1
2
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
2
|
-
import '../chunk-MMUBH76A.js';
|
|
3
|
+
import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
|
|
3
4
|
import { useRef, useState, useEffect } from 'react';
|
|
4
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
5
6
|
|
|
7
|
+
function DefaultLink(_a) {
|
|
8
|
+
var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
|
|
9
|
+
return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
|
|
10
|
+
}
|
|
6
11
|
var POSTER_STACK_OBSERVER_ROOT_MARGIN = "200px";
|
|
7
12
|
var POSTER_STACK_ANIMATION_STYLE = `
|
|
8
13
|
@keyframes ds-poster-stack-float-1 { to { transform: rotate(-5deg) translateY(-16px); } }
|
|
@@ -14,27 +19,31 @@ var POSTER_STACK_ANIMATION_STYLE = `
|
|
|
14
19
|
`;
|
|
15
20
|
var POSTER_SLOTS = [
|
|
16
21
|
{
|
|
17
|
-
positionClassName: "left-
|
|
22
|
+
positionClassName: "left-0 top-[28px] w-[112px] md:left-0 md:top-[52px] md:w-[196px]",
|
|
18
23
|
restTransform: "rotate(-5deg)",
|
|
19
24
|
animationName: "ds-poster-stack-float-1",
|
|
20
25
|
animationDurationMs: 9e3
|
|
21
26
|
},
|
|
22
27
|
{
|
|
23
|
-
positionClassName: "left-[
|
|
28
|
+
positionClassName: "left-[104px] top-0 w-[128px] md:left-[168px] md:w-[232px]",
|
|
24
29
|
restTransform: "rotate(3deg)",
|
|
25
30
|
animationName: "ds-poster-stack-float-2",
|
|
26
31
|
animationDurationMs: 11e3,
|
|
27
32
|
zIndexClassName: "z-[3]"
|
|
28
33
|
},
|
|
29
34
|
{
|
|
30
|
-
positionClassName: "left-[
|
|
35
|
+
positionClassName: "left-[224px] top-[44px] w-[112px] md:left-[378px] md:top-24 md:w-[196px]",
|
|
31
36
|
restTransform: "rotate(6deg)",
|
|
32
37
|
animationName: "ds-poster-stack-float-3",
|
|
33
38
|
animationDurationMs: 1e4
|
|
34
39
|
}
|
|
35
40
|
];
|
|
36
41
|
var POSTER_SHADOW = "0 22px 50px oklch(0.3 0.02 60 / 0.24)";
|
|
37
|
-
function PosterStack({
|
|
42
|
+
function PosterStack({
|
|
43
|
+
posters,
|
|
44
|
+
linkComponent: LinkComponent = DefaultLink,
|
|
45
|
+
className
|
|
46
|
+
}) {
|
|
38
47
|
const containerRef = useRef(null);
|
|
39
48
|
const posterRefs = useRef([]);
|
|
40
49
|
const [failedIndices, setFailedIndices] = useState(/* @__PURE__ */ new Set());
|
|
@@ -56,11 +65,32 @@ function PosterStack({ posters, className }) {
|
|
|
56
65
|
return () => observer.disconnect();
|
|
57
66
|
}, []);
|
|
58
67
|
const visiblePosters = posters.slice(0, POSTER_SLOTS.length);
|
|
59
|
-
return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: cn("relative h-[
|
|
68
|
+
return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: cn("relative h-[212px] md:h-[400px]", className), children: [
|
|
60
69
|
/* @__PURE__ */ jsx("style", { children: POSTER_STACK_ANIMATION_STYLE }),
|
|
61
70
|
visiblePosters.map((poster, index) => {
|
|
71
|
+
var _a;
|
|
62
72
|
const slot = POSTER_SLOTS[index];
|
|
63
73
|
const showPoster = !!poster.src && !failedIndices.has(index);
|
|
74
|
+
const face = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
75
|
+
showPoster ? (
|
|
76
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
77
|
+
/* @__PURE__ */ jsx(
|
|
78
|
+
"img",
|
|
79
|
+
{
|
|
80
|
+
src: poster.src,
|
|
81
|
+
alt: poster.caption ? "" : poster.alt,
|
|
82
|
+
loading: "lazy",
|
|
83
|
+
decoding: "async",
|
|
84
|
+
className: cn(
|
|
85
|
+
"h-full w-full object-cover",
|
|
86
|
+
poster.href && "transition-transform duration-300 group-hover/poster:scale-[1.03] motion-reduce:transition-none"
|
|
87
|
+
),
|
|
88
|
+
onError: () => setFailedIndices((current) => new Set(current).add(index))
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
) : (_a = poster.fallback) != null ? _a : /* @__PURE__ */ jsx(EventPosterFallback, {}),
|
|
92
|
+
poster.caption && /* @__PURE__ */ jsx("span", { className: "absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/70 to-transparent px-2 pb-2 pt-6", children: /* @__PURE__ */ jsx("span", { className: "line-clamp-2 text-[11px] font-semibold leading-[1.25] text-white md:text-[12.5px]", children: poster.caption }) })
|
|
93
|
+
] });
|
|
64
94
|
return /* @__PURE__ */ jsx(
|
|
65
95
|
"div",
|
|
66
96
|
{
|
|
@@ -71,7 +101,8 @@ function PosterStack({ posters, className }) {
|
|
|
71
101
|
className: cn(
|
|
72
102
|
"absolute aspect-[3/4] overflow-hidden rounded-xl bg-muted",
|
|
73
103
|
slot.positionClassName,
|
|
74
|
-
slot.zIndexClassName
|
|
104
|
+
slot.zIndexClassName,
|
|
105
|
+
poster.href && "hover:z-[4] focus-within:z-[4]"
|
|
75
106
|
),
|
|
76
107
|
style: {
|
|
77
108
|
transform: slot.restTransform,
|
|
@@ -82,18 +113,18 @@ function PosterStack({ posters, className }) {
|
|
|
82
113
|
animationIterationCount: "infinite",
|
|
83
114
|
animationDirection: "alternate"
|
|
84
115
|
},
|
|
85
|
-
children:
|
|
86
|
-
|
|
87
|
-
"img",
|
|
116
|
+
children: poster.href ? /* @__PURE__ */ jsx(
|
|
117
|
+
LinkComponent,
|
|
88
118
|
{
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
119
|
+
href: poster.href,
|
|
120
|
+
className: cn(
|
|
121
|
+
"group/poster relative block h-full w-full overflow-hidden rounded-xl",
|
|
122
|
+
"transition-transform duration-150 active:scale-[0.98] motion-reduce:transition-none",
|
|
123
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
124
|
+
),
|
|
125
|
+
children: face
|
|
95
126
|
}
|
|
96
|
-
)
|
|
127
|
+
) : /* @__PURE__ */ jsx("div", { className: "relative h-full w-full", children: face })
|
|
97
128
|
},
|
|
98
129
|
poster.alt || index
|
|
99
130
|
);
|
|
@@ -21,7 +21,7 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
21
21
|
* `card` is the 14px inset of a hub card; `page` is the 16px page gutter.
|
|
22
22
|
*/
|
|
23
23
|
declare const snapRailVariants: (props?: ({
|
|
24
|
-
itemWidth?: "sm" | "lg" | "full" | "md" | null | undefined;
|
|
24
|
+
itemWidth?: "xs" | "sm" | "lg" | "full" | "md" | null | undefined;
|
|
25
25
|
gap?: "default" | "sm" | null | undefined;
|
|
26
26
|
bleed?: "none" | "page" | "card" | null | undefined;
|
|
27
27
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
@@ -43,7 +43,7 @@ type SnapRailProps = React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof
|
|
|
43
43
|
onActiveChange?: (index: number) => void;
|
|
44
44
|
};
|
|
45
45
|
declare const SnapRail: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & VariantProps<(props?: ({
|
|
46
|
-
itemWidth?: "sm" | "lg" | "full" | "md" | null | undefined;
|
|
46
|
+
itemWidth?: "xs" | "sm" | "lg" | "full" | "md" | null | undefined;
|
|
47
47
|
gap?: "default" | "sm" | null | undefined;
|
|
48
48
|
bleed?: "none" | "page" | "card" | null | undefined;
|
|
49
49
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & {
|
|
@@ -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;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* TimelineDay — one day's programme on the timeline: a column of
|
|
6
|
+
* `TimelineHour`s that becomes, from `lg`, the three-column row
|
|
7
|
+
* lane │ spine │ content that `TimelineBand` used to draw.
|
|
8
|
+
*
|
|
9
|
+
* ONE DOM FOR BOTH VIEWPORTS. `TimelineBand` took the lane as a prop — a
|
|
10
|
+
* second parent — which forced the consumer to render two trees and pick one
|
|
11
|
+
* in JavaScript, and a server render cannot pick. Here the lane is grid
|
|
12
|
+
* column 1, and the day's hero is an ordinary child in its chronological
|
|
13
|
+
* slot that the grid PLACES in that column from `lg` (see `TimelineHour`
|
|
14
|
+
* `role="hero"`). Source order is the phone's visual order, which is the
|
|
15
|
+
* primary surface and the one a screen reader gets on both.
|
|
16
|
+
*
|
|
17
|
+
* `rows` is the number of children that are NOT the hero — the column-3
|
|
18
|
+
* items. It sets `--timeline-rows`, which both the lane and the spine span,
|
|
19
|
+
* and the explicit row track count. It has to be a number the caller
|
|
20
|
+
* supplies: the grid needs the lane to cover every row so auto-placement
|
|
21
|
+
* never drops a later hour into the lane column, and this component cannot
|
|
22
|
+
* tell a hero child from an hour child without inspecting props.
|
|
23
|
+
*
|
|
24
|
+
* `laneTop` is the lane's sticky `top` as a CSS value. `position: sticky` on
|
|
25
|
+
* a grid item is bounded by its grid area — column 1, rows 1…N, the day's
|
|
26
|
+
* full height — so the poster holds while column 3 scrolls and releases when
|
|
27
|
+
* the day runs out, with no scroll listener and no measured height.
|
|
28
|
+
*
|
|
29
|
+
* The spine is a vertical `Separator` in column 2 spanning every row, drawn
|
|
30
|
+
* here so consumers never forget it; the pucks that sit on it are
|
|
31
|
+
* `TimelineHour`'s.
|
|
32
|
+
*/
|
|
33
|
+
type TimelineDayProps = {
|
|
34
|
+
/** The column-3 children count — every child except the hero. */
|
|
35
|
+
rows: number;
|
|
36
|
+
/** Sticky `top` for the lane, as a CSS value. Omitted, the lane scrolls. */
|
|
37
|
+
laneTop?: string;
|
|
38
|
+
/** `TimelineHour`s, in chronological order, the hero among them. */
|
|
39
|
+
children: React.ReactNode;
|
|
40
|
+
className?: string;
|
|
41
|
+
};
|
|
42
|
+
declare function TimelineDay({ rows, laneTop, children, className }: TimelineDayProps): react_jsx_runtime.JSX.Element;
|
|
43
|
+
type TimelineDaySkeletonProps = {
|
|
44
|
+
/** Hours to reserve space for. */
|
|
45
|
+
hourCount?: number;
|
|
46
|
+
className?: string;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Holds the day's geometry at both widths so nothing jumps when data lands:
|
|
50
|
+
* the phone's stacked hours, the desktop's lane / spine / grid.
|
|
51
|
+
*/
|
|
52
|
+
declare function TimelineDaySkeleton({ hourCount, className }: TimelineDaySkeletonProps): react_jsx_runtime.JSX.Element;
|
|
53
|
+
|
|
54
|
+
export { TimelineDay, type TimelineDayProps, TimelineDaySkeleton, type TimelineDaySkeletonProps };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { TimelineHourSkeleton } from '../chunk-LYREUZH6.js';
|
|
2
|
+
import '../chunk-PW247TG2.js';
|
|
3
|
+
import { Separator } from '../chunk-NWZGSLPU.js';
|
|
4
|
+
import { Skeleton } from '../chunk-XBBEX4SF.js';
|
|
5
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
6
|
+
import { __spreadValues } from '../chunk-MMUBH76A.js';
|
|
7
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
function TimelineDay({ rows, laneTop, children, className }) {
|
|
10
|
+
const style = __spreadValues({
|
|
11
|
+
"--timeline-rows": String(Math.max(rows, 1))
|
|
12
|
+
}, laneTop !== void 0 ? { "--timeline-lane-top": laneTop } : {});
|
|
13
|
+
return /* @__PURE__ */ jsxs(
|
|
14
|
+
"div",
|
|
15
|
+
{
|
|
16
|
+
className: cn(
|
|
17
|
+
"flex flex-col",
|
|
18
|
+
"lg:grid lg:grid-cols-[var(--timeline-lane)_var(--timeline-spine)_minmax(0,1fr)]",
|
|
19
|
+
"lg:[grid-template-rows:repeat(var(--timeline-rows),auto)]",
|
|
20
|
+
className
|
|
21
|
+
),
|
|
22
|
+
style,
|
|
23
|
+
children: [
|
|
24
|
+
/* @__PURE__ */ jsx(
|
|
25
|
+
"div",
|
|
26
|
+
{
|
|
27
|
+
"aria-hidden": true,
|
|
28
|
+
className: cn(
|
|
29
|
+
"hidden lg:col-start-2 lg:row-start-1 lg:flex lg:justify-center lg:self-stretch",
|
|
30
|
+
"lg:[grid-row-end:span_var(--timeline-rows)]"
|
|
31
|
+
),
|
|
32
|
+
children: /* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-full" })
|
|
33
|
+
}
|
|
34
|
+
),
|
|
35
|
+
children
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
function TimelineDaySkeleton({ hourCount = 2, className }) {
|
|
41
|
+
return /* @__PURE__ */ jsxs(
|
|
42
|
+
"div",
|
|
43
|
+
{
|
|
44
|
+
"aria-hidden": "true",
|
|
45
|
+
className: cn(
|
|
46
|
+
"flex flex-col",
|
|
47
|
+
"lg:grid lg:grid-cols-[var(--timeline-lane)_var(--timeline-spine)_minmax(0,1fr)]",
|
|
48
|
+
"lg:[grid-template-rows:repeat(var(--timeline-rows),auto)]",
|
|
49
|
+
className
|
|
50
|
+
),
|
|
51
|
+
style: { "--timeline-rows": String(hourCount) },
|
|
52
|
+
children: [
|
|
53
|
+
/* @__PURE__ */ jsxs("div", { className: "hidden lg:col-start-1 lg:row-start-1 lg:flex lg:flex-col lg:gap-3 lg:pt-3.5 lg:[grid-row-end:span_var(--timeline-rows)]", children: [
|
|
54
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "aspect-[3/4] w-full rounded-xl" }),
|
|
55
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-[18px] w-[70%]" }),
|
|
56
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-[13px] w-[45%]" })
|
|
57
|
+
] }),
|
|
58
|
+
/* @__PURE__ */ jsx("div", { className: "hidden lg:col-start-2 lg:row-start-1 lg:flex lg:justify-center lg:self-stretch lg:[grid-row-end:span_var(--timeline-rows)]", children: /* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-full" }) }),
|
|
59
|
+
Array.from({ length: hourCount }, (_, index) => /* @__PURE__ */ jsx(TimelineHourSkeleton, { cardCount: index === 0 ? 3 : 2 }, index))
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { TimelineDay, TimelineDaySkeleton };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The phone axis gutter, shared by `TimelineHour` and `TimelinePlayhead` so
|
|
5
|
+
* the hour chips and the current-time label sit in one column. 58px is the
|
|
6
|
+
* width of a five-glyph 24-hour label ("20:00") in the chip's mono type plus
|
|
7
|
+
* its padding; a 12-hour locale's "09:00 AM" overflows it, which is one of the
|
|
8
|
+
* reasons the events surfaces format 24-hour everywhere.
|
|
9
|
+
*/
|
|
10
|
+
declare const TIMELINE_MOBILE_GUTTER_CLASS = "w-[58px]";
|
|
11
|
+
type TimelineHourPuckProps = {
|
|
12
|
+
/** The hour, already formatted and localised — or an em dash for a quiet day. */
|
|
13
|
+
time: string;
|
|
14
|
+
/** Marks this as the hour currently in progress. */
|
|
15
|
+
isLive?: boolean;
|
|
16
|
+
/** Shown under the puck when live, e.g. "NOW ON". Required to render it. */
|
|
17
|
+
liveLabel?: string;
|
|
18
|
+
/**
|
|
19
|
+
* `station`: the bordered puck that sits ON the hairline, for the desktop
|
|
20
|
+
* spine. `chip`: a filled, fixed-width lozenge with the hairline starting
|
|
21
|
+
* BELOW it, for the phone gutter — an app's time label, not a station on a
|
|
22
|
+
* rail. `responsive` (the default): the chip below `lg`, the station from
|
|
23
|
+
* `lg` — ONE node that changes its look with the viewport, so a
|
|
24
|
+
* server-rendered timeline carries a single DOM for both widths. In the
|
|
25
|
+
* chip look the live label is visually hidden: the tinted chip plus a small
|
|
26
|
+
* on-air glyph are the visible signal (the glyph so the state never rests on
|
|
27
|
+
* colour alone once the pulse is reduced away) and the label stays for
|
|
28
|
+
* screen readers only.
|
|
29
|
+
*/
|
|
30
|
+
variant?: "station" | "chip" | "responsive";
|
|
31
|
+
className?: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* The station on the timeline's axis — ONE object, positioned by its host
|
|
35
|
+
* (`TimelineHour`): pinned to the top of the phone gutter, centred on the
|
|
36
|
+
* hour's heading rule out on the desktop spine.
|
|
37
|
+
*
|
|
38
|
+
* The `bg-background` fill punches through the hairline so the rail reads as
|
|
39
|
+
* continuous behind the label rather than butting into it.
|
|
40
|
+
*
|
|
41
|
+
* The live label is absolutely positioned rather than a flex sibling: hosts
|
|
42
|
+
* centre this puck with `-translate-y-1/2`, and a two-item column would centre
|
|
43
|
+
* the STACK, lifting the puck off the line it exists to sit on.
|
|
44
|
+
*/
|
|
45
|
+
declare function TimelineHourPuck({ time, isLive, liveLabel, variant, className, }: TimelineHourPuckProps): react_jsx_runtime.JSX.Element;
|
|
46
|
+
|
|
47
|
+
export { TIMELINE_MOBILE_GUTTER_CLASS, TimelineHourPuck, type TimelineHourPuckProps };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* TimelineHour — one hour of a day's programme, ONE DOM for both viewports.
|
|
6
|
+
*
|
|
7
|
+
* Replaces `HourBand` (the phone band: a 58px gutter with a filled chip and
|
|
8
|
+
* a hairline dropping from it, the hour's cards beside) and `HourGroup` (the
|
|
9
|
+
* desktop heading: a station out on `TimelineDay`'s spine, a rule and a
|
|
10
|
+
* count). They were two components because the timeline picked one per
|
|
11
|
+
* viewport in JavaScript, and a server render cannot know the viewport — so
|
|
12
|
+
* the server rendered nothing. This is both, with CSS deciding:
|
|
13
|
+
*
|
|
14
|
+
* below `lg` the section carries a 70px left inset; the puck sits at the
|
|
15
|
+
* top-left of that gutter as a chip, a hairline drops beneath
|
|
16
|
+
* it, and the heading row is hidden — the chip IS the heading.
|
|
17
|
+
* from `lg` the inset goes, the heading row shows (rule + count), and the
|
|
18
|
+
* puck moves out to the spine, centred on that rule, as a
|
|
19
|
+
* station. Its vertical position is a constant (`--timeline-
|
|
20
|
+
* heading` below), which is why the heading row has a fixed
|
|
21
|
+
* height: "top-1/2 of the row" needs the puck INSIDE the row,
|
|
22
|
+
* and inside the row it cannot also be the phone's gutter chip.
|
|
23
|
+
*
|
|
24
|
+
* The invariant `TimelineBand` used to state still holds: AN HOUR APPEARS
|
|
25
|
+
* EXACTLY ONCE, AND ALWAYS ON THE SPINE. Roles are how a day keeps it while
|
|
26
|
+
* one of its events is lifted into the desktop lane:
|
|
27
|
+
*
|
|
28
|
+
* hour the default — a station, the hour's events.
|
|
29
|
+
* hero the day's feature. Below `lg` a normal hour holding one
|
|
30
|
+
* card, in its chronological slot. From `lg` the node moves
|
|
31
|
+
* to `TimelineDay`'s lane column (grid placement, not source
|
|
32
|
+
* order), pins, and loses its puck and heading — the lane
|
|
33
|
+
* card carries its own start time, see `EventCard` `hideWhen`
|
|
34
|
+
* `"below-lg"`.
|
|
35
|
+
* continuation what is left of the hero's hour. Below `lg` its chip is
|
|
36
|
+
* `invisible` (the gutter and hairline stay, so the reader sees
|
|
37
|
+
* ONE band for that hour, hero first); from `lg` it shows its
|
|
38
|
+
* station, because the hero is in the lane now and the hour
|
|
39
|
+
* needs its puck back. When the hero was its hour's only
|
|
40
|
+
* event there is no continuation, and the hour simply leaves
|
|
41
|
+
* the desktop column — exactly what `HourGroup`'s
|
|
42
|
+
* `excludeEventId` used to do.
|
|
43
|
+
* unscheduled events the ingest dated but never timed. No station at any
|
|
44
|
+
* width — the axis encodes clock position and these have none
|
|
45
|
+
* — and no gutter inset: an inline heading (the caller's
|
|
46
|
+
* label, a rule, the count) at both widths, after the day's
|
|
47
|
+
* real programme.
|
|
48
|
+
*
|
|
49
|
+
* `layout`: `cards` stacks posters with a gap (a card is its own frame, a
|
|
50
|
+
* hairline between two posters reads as a third object) and from `lg` lays
|
|
51
|
+
* them on a two/three-up grid; `rows` rules between children on both widths.
|
|
52
|
+
* Children are read with `Children.toArray`, which drops `null`/`false`, so a
|
|
53
|
+
* conditional first row never inherits a rule meant for a second; pass rows
|
|
54
|
+
* as siblings, not inside a fragment.
|
|
55
|
+
*/
|
|
56
|
+
type TimelineHourRole = "hour" | "hero" | "continuation" | "unscheduled";
|
|
57
|
+
type TimelineHourProps = {
|
|
58
|
+
/** The hour, already formatted and localised — "20:00". For `unscheduled`,
|
|
59
|
+
* the caller's label for the group ("Time to be confirmed"). */
|
|
60
|
+
time: string;
|
|
61
|
+
role?: TimelineHourRole;
|
|
62
|
+
/** Marks this as the hour currently in progress. */
|
|
63
|
+
isLive?: boolean;
|
|
64
|
+
/** Under the station when live, e.g. "NOW ON"; screen-reader-only in the chip. */
|
|
65
|
+
liveLabel?: string;
|
|
66
|
+
/** Desktop heading count, e.g. "3 events" — mirrors `EventDayHeader`'s `meta`.
|
|
67
|
+
* Also the phone heading for `unscheduled`. */
|
|
68
|
+
countLabel?: string;
|
|
69
|
+
/** Trailing note after the children, e.g. "No start time was published". */
|
|
70
|
+
note?: string;
|
|
71
|
+
layout?: "cards" | "rows";
|
|
72
|
+
/** The hour's events — each direct child one card or row. */
|
|
73
|
+
children: React.ReactNode;
|
|
74
|
+
/**
|
|
75
|
+
* Events past the hour's card cap, after `children`: cards on the phone
|
|
76
|
+
* (the same stack, same gap), rows from `lg` (ruled, under the grid) —
|
|
77
|
+
* pass `EventCard density="row-lg"`. The desktop's density ladder inside
|
|
78
|
+
* one hour: a few posters, then rows.
|
|
79
|
+
*/
|
|
80
|
+
overflow?: React.ReactNode;
|
|
81
|
+
className?: string;
|
|
82
|
+
};
|
|
83
|
+
declare function TimelineHour({ time, role, isLive, liveLabel, countLabel, note, layout, children, overflow, className, }: TimelineHourProps): react_jsx_runtime.JSX.Element;
|
|
84
|
+
type TimelineHourSkeletonProps = {
|
|
85
|
+
/** Cards to reserve space for. */
|
|
86
|
+
cardCount?: number;
|
|
87
|
+
className?: string;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Mirrors `TimelineHour` at both widths — the phone's gutter chip and
|
|
91
|
+
* hairline, the desktop's grid of poster placeholders — so nothing jumps when
|
|
92
|
+
* data lands.
|
|
93
|
+
*/
|
|
94
|
+
declare function TimelineHourSkeleton({ cardCount, className }: TimelineHourSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
95
|
+
|
|
96
|
+
export { TimelineHour, type TimelineHourProps, type TimelineHourRole, TimelineHourSkeleton, type TimelineHourSkeletonProps };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { TimelineHour, TimelineHourSkeleton } from '../chunk-LYREUZH6.js';
|
|
2
|
+
import '../chunk-PW247TG2.js';
|
|
2
3
|
import '../chunk-NWZGSLPU.js';
|
|
3
4
|
import '../chunk-XBBEX4SF.js';
|
|
4
5
|
import '../chunk-FEK5XGZW.js';
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { TIMELINE_MOBILE_GUTTER_CLASS } from '../chunk-
|
|
2
|
-
import '../chunk-NWZGSLPU.js';
|
|
3
|
-
import '../chunk-XBBEX4SF.js';
|
|
1
|
+
import { TIMELINE_MOBILE_GUTTER_CLASS } from '../chunk-PW247TG2.js';
|
|
4
2
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
5
3
|
import '../chunk-MMUBH76A.js';
|
|
6
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|