@brett_lamy/docstream 1.6.0 → 1.7.0

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.
Files changed (43) hide show
  1. package/README.md +34 -7
  2. package/dist/index.d.ts +2 -2
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/replay/ReplayPlayer.d.ts +64 -0
  7. package/dist/replay/ReplayPlayer.d.ts.map +1 -0
  8. package/dist/replay/ReplayPlayer.js +211 -0
  9. package/dist/replay/ReplayPlayer.js.map +1 -0
  10. package/dist/replay/ReplayPreview.d.ts +24 -12
  11. package/dist/replay/ReplayPreview.d.ts.map +1 -1
  12. package/dist/replay/ReplayPreview.js +37 -32
  13. package/dist/replay/ReplayPreview.js.map +1 -1
  14. package/dist/replay/ReplayStage.d.ts +1 -1
  15. package/dist/replay/ReplayStage.js +1 -1
  16. package/dist/replay/ReplayStageImpl.js +1 -1
  17. package/dist/replay/ReplayStageImpl.js.map +1 -1
  18. package/dist/replay/demo/index.d.ts +3 -0
  19. package/dist/replay/demo/index.d.ts.map +1 -0
  20. package/dist/replay/demo/index.js +66 -0
  21. package/dist/replay/demo/index.js.map +1 -0
  22. package/dist/replay/index.d.ts +2 -2
  23. package/dist/replay/index.d.ts.map +1 -1
  24. package/dist/replay/index.js +1 -1
  25. package/dist/replay/index.js.map +1 -1
  26. package/dist/replay/types.js +3 -3
  27. package/dist/replay/types.js.map +1 -1
  28. package/dist/styles.css +565 -75
  29. package/package.json +8 -6
  30. package/src/index.ts +2 -1
  31. package/src/replay/ReplayPlayer.tsx +430 -0
  32. package/src/replay/ReplayPreview.tsx +111 -85
  33. package/src/replay/ReplayStage.tsx +1 -1
  34. package/src/replay/ReplayStageImpl.tsx +1 -1
  35. package/src/replay/demo/index.ts +67 -0
  36. package/src/replay/index.ts +6 -1
  37. package/src/replay/types.ts +3 -3
  38. package/src/styles.css +565 -75
  39. package/dist/replay/NativeReplay.d.ts +0 -9
  40. package/dist/replay/NativeReplay.d.ts.map +0 -1
  41. package/dist/replay/NativeReplay.js +0 -175
  42. package/dist/replay/NativeReplay.js.map +0 -1
  43. package/src/replay/NativeReplay.tsx +0 -240
package/README.md CHANGED
@@ -130,17 +130,44 @@ chrome-free `/p/...` route automatically:
130
130
  {% embed url="https://loop-qa.replay.io/projects/project-id/journeys/journey-id" /%}
131
131
  ```
132
132
 
133
- The replay component is also available directly when a document needs a
134
- custom source or native rrweb events:
133
+ The replay component is also available directly. `ReplayPreview` takes either
134
+ `events` (an rrweb recording you hold: the full player) or `source` (a page URL, an
135
+ event array, or an events endpoint):
135
136
 
136
137
  ```tsx
137
138
  import { ReplayPreview } from "@brett_lamy/docstream"
138
139
 
139
140
  <ReplayPreview source="https://loop-qa.replay.io/projects/project-id/tasks/task-id" />
140
- ```
141
-
142
- Native rrweb playback needs the optional `rrweb` peer (`npm i rrweb@2.0.0-alpha.20`);
143
- it is imported only by the lazily loaded player chunk. To build custom player chrome, use
141
+ <ReplayPreview events={events} initialTime={6400} />
142
+ ```
143
+
144
+ The player is a browser frame (URL bar that follows the recording's navigations),
145
+ a page-shaped poster until it is ready, play/pause, a scrubber with the recording's
146
+ moments on a rail above it (clicks, console errors, failed requests, navigations,
147
+ custom events; press one to jump), speed, fullscreen, and a drawn cursor whose clicks
148
+ ripple. Keys work inside the player: Space/K, ←/→ (5 s), J/L (10 s), `<`/`>` speed,
149
+ F fullscreen, Home/End. `chrome` is `"browser"` (default), `"minimal"` or `"none"`;
150
+ `controls={false}` with `chrome="none"` is a still frame of the page at `initialTime`.
151
+ `playerRef` gives `{ play, pause, seek, toggle, getCurrentTime }`. Other props: `url`,
152
+ `title`, `trafficLights`, `autoplay`, `loop`, `speeds`, `markers`, `markerKinds`,
153
+ `cursor`, `fit` (`"width"` | `"contain"`), `poster`, `lazy`, `onTimeUpdate`,
154
+ `onPlayingChange`, `onMarkerPress`, `className`, `style`. `formatReplayTime(ms)` gives
155
+ `m:ss`. `replayDemoEvents` (a small synthetic recording) is exported from
156
+ `@brett_lamy/docstream/replay/demo`, outside the main entry.
157
+
158
+ The player is styled by `styles.css` in plain CSS, inside the `docstream.replay` cascade
159
+ layer and under zero-specificity `:where()` selectors, so your own rules (and utility
160
+ classes such as `w-full` or `pointer-events-none`) override it; if your utilities layer
161
+ is declared earlier than this stylesheet, put `@layer docstream.replay;` before it.
162
+ Colors come from the shadcn-style tokens `--card`, `--background`, `--foreground`,
163
+ `--muted`, `--muted-foreground`, `--border`, `--primary`, `--ring`, `--destructive`,
164
+ `--success`, `--warning` and `--tertiary-foreground`, each with a neutral fallback.
165
+ Parts are addressable as `[data-slot="replay-preview"]` (with `data-state`
166
+ `loading | paused | playing` and `data-chrome`), `-bar`, `-stage`, `-poster`, `-pointer`,
167
+ `-controls`, `-scrubber` and `-markers`.
168
+
169
+ rrweb (and its stylesheet) is imported only by the lazily loaded player chunk, so pages
170
+ that only embed Loop QA URLs never download it. To build custom player chrome, use
144
171
  the headless `ReplayStage` (the fitted page, driven through a ref and callbacks) with the
145
172
  pure timeline helpers, none of which load rrweb:
146
173
 
@@ -639,7 +666,7 @@ You can also resolve paths yourself with `resolveAsset`.
639
666
  - `GitbookStreamdown`: Parses and renders markdown for read-only stream output.
640
667
  - `DocsRenderer`: Renders a parsed `DocumentNode`.
641
668
  - `MarkdownContent`: Parses and renders a markdown string.
642
- - `ReplayPreview` / `ReplayEmbed`: Embeds public Loop QA pages or plays CORS-enabled rrweb event data.
669
+ - `ReplayPreview` / `ReplayEmbed`: A session-replay player for rrweb `events`, or an embed of public Loop QA pages / CORS-enabled event data via `source`.
643
670
  - `VideoEmbed`: Renders direct video assets or hosted video players.
644
671
  - `OpenApiOperation`: Renders a parsed OpenAPI operation block.
645
672
  - `SourcePreview`: Imports and renders a mounted component or CSF story export.
package/dist/index.d.ts CHANGED
@@ -12,8 +12,8 @@ export { DemoBlock, DemoFullscreen, DemoViewer, DocstreamDemoContext, DocstreamD
12
12
  export type { DemoComponent, DemoComponentProps, DemoFile, DemoFullscreenProps, DemoMarkdownFormat, DemoMeta, DemoResolver, DemoRuntimeOptions, DemoVariant, DemoViewerProps, DemoVFS, DemoVFSChange, DemoVFSEntry, DocstreamClipboard, DocstreamClipboardPayload, GlobDemoResolverOptions, InlineDemoRuntime, InlineDemoRuntimeProps, ResolveDemosOptions, ResolvedDemo, } from "./demo/index.js";
13
13
  export { CitationSources, DocstreamRefContext, InlineReference } from "./docs/reference.js";
14
14
  export type { CitationPreview, CitationPreviewResolver, DocstreamRefContextValue } from "./docs/reference.js";
15
- export { ReplayEmbed, ReplayPreview } from "./replay/ReplayPreview.js";
16
- export type { ReplayEventsSource, ReplayEventsUrlSource, ReplayPageSource, ReplayPreviewProps, ReplaySource, } from "./replay/ReplayPreview.js";
15
+ export { ReplayEmbed, ReplayPreview, formatReplayTime } from "./replay/ReplayPreview.js";
16
+ export type { ReplayEventsSource, ReplayEventsUrlSource, ReplayPageSource, ReplayPreviewHandle, ReplayPreviewProps, ReplaySource, } from "./replay/ReplayPreview.js";
17
17
  export type { ReplayEvent } from "./replay/types.js";
18
18
  export { isReplayQaUrl, normalizeReplayEmbedUrl } from "./replay/url.js";
19
19
  export { VideoEmbed } from "./video/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ export { CopyButton, copyText } from "./docs/copy.js";
8
8
  export { getSyncedTab, setSyncedTab, useSyncedTab } from "./docs/tabs-sync.js";
9
9
  export { DemoBlock, DemoFullscreen, DemoViewer, DocstreamDemoContext, DocstreamDemoRuntimeContext, DocstreamDemoVFSContext, DOCSTREAM_CLIPBOARD_TYPE, CopyDemoButton, createDemoVFS, createDocstreamClipboard, createDocstreamClipboardFromMarkdown, createGlobDemoResolver, docstreamClipboardItems, parseDocstreamClipboard, peekDemoSource, prefetchDemoSources, readDocstreamClipboard, readDocstreamClipboardItems, useDemoVFS, useDemoVFSFiles, defaultDemoMarkdown, inlineDemoMarkdown, inlineDemoNode, demoComponentFrom, demoFromSearch, demoHref, preloadDemos, resolveDemosToMarkdown, sortDemoFiles, toInlineFiles, useDemoResolver, useDemoRuntime, } from "./demo/index.js";
10
10
  export { CitationSources, DocstreamRefContext, InlineReference } from "./docs/reference.js";
11
- export { ReplayEmbed, ReplayPreview } from "./replay/ReplayPreview.js";
11
+ export { ReplayEmbed, ReplayPreview, formatReplayTime } from "./replay/ReplayPreview.js";
12
12
  export { isReplayQaUrl, normalizeReplayEmbedUrl } from "./replay/url.js";
13
13
  export { VideoEmbed } from "./video/index.js";
14
14
  export { OpenApiOperation } from "./openapi/OpenApiOperation.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,sGAAsG;AACtG,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEhD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC3E,OAAO,EACL,SAAS,EACT,cAAc,EACd,UAAU,EACV,oBAAoB,EACpB,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACd,aAAa,EACb,wBAAwB,EACxB,oCAAoC,EACpC,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,UAAU,EACV,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,sBAAsB,EACtB,aAAa,EACb,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,QAAQ,CAAA;AAuBf,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAExF,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AASnE,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAC7D,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AASpF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACrD,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAS3F,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACvG,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACrG,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,SAAS,EACT,cAAc,EACd,eAAe,EACf,kBAAkB,GACnB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AACrF,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC1E,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,sGAAsG;AACtG,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEhD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC3E,OAAO,EACL,SAAS,EACT,cAAc,EACd,UAAU,EACV,oBAAoB,EACpB,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACd,aAAa,EACb,wBAAwB,EACxB,oCAAoC,EACpC,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,UAAU,EACV,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,sBAAsB,EACtB,aAAa,EACb,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,QAAQ,CAAA;AAuBf,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAExF,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAUrF,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAC7D,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AASpF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACrD,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAS3F,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACvG,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACrG,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,SAAS,EACT,cAAc,EACd,eAAe,EACf,kBAAkB,GACnB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AACrF,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC1E,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA"}
@@ -0,0 +1,64 @@
1
+ import { type CSSProperties, type ReactNode, type Ref } from 'react';
2
+ import type { ReplayMarker, ReplayMarkerKind } from './markers.js';
3
+ import type { ReplayEvent } from './types.js';
4
+ export declare const DEFAULT_PLAYER_SPEEDS: number[];
5
+ export type ReplayChrome = 'browser' | 'minimal' | 'none';
6
+ export interface ReplayPreviewHandle {
7
+ play(offset?: number): void;
8
+ pause(offset?: number): void;
9
+ /** Jump to `ms` from the start, keeping the play state. */
10
+ seek(ms: number): void;
11
+ toggle(): void;
12
+ getCurrentTime(): number;
13
+ }
14
+ /** Options shared by every `ReplayPreview` (an `events` player or a `source` embed). */
15
+ export interface ReplayPlayerOptions {
16
+ /** Address shown in the URL bar (default: the recording's own URL, following its navigations). */
17
+ url?: string;
18
+ /** Accessible name of the player (default "Session replay"). */
19
+ title?: string;
20
+ /** `browser` (default): window buttons, URL bar, controls. `minimal`: the page and its controls in a rounded
21
+ * card. `none`: no frame, fill the parent (a hero, a lightbox). */
22
+ chrome?: ReplayChrome;
23
+ /** macOS window buttons in the browser chrome (default true). */
24
+ trafficLights?: boolean;
25
+ /** Play/pause, scrubber, speed and fullscreen (default true). */
26
+ controls?: boolean;
27
+ autoplay?: boolean;
28
+ loop?: boolean;
29
+ /** Where the player starts, in ms from the start. */
30
+ initialTime?: number;
31
+ /** Speeds the speed button cycles through; the first is the initial speed (default 1, 2, 4, 0.5). */
32
+ speeds?: number[];
33
+ /** Markers on the scrubber rail: `true` (default) reads them from the recording, `false` hides the rail,
34
+ * or pass your own. */
35
+ markers?: boolean | ReplayMarker[];
36
+ /** Which recorded marker kinds to show (default all). */
37
+ markerKinds?: ReplayMarkerKind[];
38
+ /** Draw the recorded pointer and click ripples (default true). */
39
+ cursor?: boolean;
40
+ /** `width` (default): the page scales to the frame's width and sets its height. `contain`: fill the frame's
41
+ * height (give it one) and letterbox the page. */
42
+ fit?: 'width' | 'contain';
43
+ /** Shown until the player is ready (default: a page-shaped skeleton). */
44
+ poster?: ReactNode;
45
+ /** Mount the player only once the frame nears the viewport (default true). */
46
+ lazy?: boolean;
47
+ /** Imperative control (play, pause, seek). */
48
+ playerRef?: Ref<ReplayPreviewHandle | null>;
49
+ onTimeUpdate?: (ms: number) => void;
50
+ onPlayingChange?: (playing: boolean) => void;
51
+ onMarkerPress?: (marker: ReplayMarker) => void;
52
+ className?: string;
53
+ style?: CSSProperties;
54
+ }
55
+ export declare function formatReplayTime(ms: number): string;
56
+ export declare function ReplayPlayer({ events, url, title, chrome, trafficLights, controls, autoplay, loop, initialTime, speeds, markers, markerKinds, cursor, fit, poster, lazy, playerRef, onTimeUpdate, onPlayingChange, onMarkerPress, className, style, }: ReplayPlayerOptions & {
57
+ events: ReplayEvent[];
58
+ }): import("react").JSX.Element;
59
+ export declare function BrowserBar({ href, trafficLights, loading }: {
60
+ href: string;
61
+ trafficLights: boolean;
62
+ loading: boolean;
63
+ }): import("react").JSX.Element;
64
+ //# sourceMappingURL=ReplayPlayer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReplayPlayer.d.ts","sourceRoot":"","sources":["../../src/replay/ReplayPlayer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,211 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* The player behind `ReplayPreview`: an rrweb session replay in a browser frame. The headless `ReplayStage`
3
+ plays the recording (rrweb loads lazily, on first render); this adds the chrome around it: a URL bar that
4
+ follows the recording's navigations, play/pause, a scrubber with the recording's moments on a rail above
5
+ it, a speed control, fullscreen, and a drawn cursor whose clicks ripple. Until the player is ready a
6
+ poster (a page-shaped skeleton by default) holds the frame's exact size, so nothing jumps.
7
+
8
+ Plain React + plain CSS (`@layer docstream.replay` in styles.css, `[data-slot]` hooks). Keys (focus inside
9
+ the player): Space / K play and pause, ← → seek 5 s, J / L 10 s, < > speed, F fullscreen, Home / End jump
10
+ to the ends. Everything drawn over the page is a function of the playhead, so scrubbing backwards replays
11
+ the ripples and the URL too. */
12
+ import { memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
13
+ import { useReducedMotion } from 'framer-motion';
14
+ import { Lock, Maximize, Minimize, Pause, Play, RotateCcw } from 'lucide-react';
15
+ import { ReplayStage } from './ReplayStage.js';
16
+ import { getReplayMarkers, getReplayMeta, getReplayPointerTrack, replayPointerAt } from './markers.js';
17
+ const TRAFFIC_LIGHTS = ['#FF5F57', '#FEBC2E', '#28C840'];
18
+ export const DEFAULT_PLAYER_SPEEDS = [1, 2, 4, 0.5];
19
+ const RIPPLE_MS = 650;
20
+ export function formatReplayTime(ms) {
21
+ const s = Math.max(0, Math.floor(ms / 1000));
22
+ return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, '0')}`;
23
+ }
24
+ const MARKER_NOUN = {
25
+ click: 'Click', error: 'Error', network: 'Request failed', navigation: 'Navigation', custom: 'Checkpoint',
26
+ };
27
+ export function ReplayPlayer({ events, url, title = 'Session replay', chrome = 'browser', trafficLights = true, controls = true, autoplay = false, loop = false, initialTime = 0, speeds = DEFAULT_PLAYER_SPEEDS, markers = true, markerKinds, cursor = true, fit = 'width', poster, lazy = true, playerRef, onTimeUpdate, onPlayingChange, onMarkerPress, className, style, }) {
28
+ const rootRef = useRef(null);
29
+ const stage = useRef(null);
30
+ const reduced = useReducedMotion();
31
+ const meta = useMemo(() => getReplayMeta(events), [events]);
32
+ const track = useMemo(() => getReplayPointerTrack(events), [events]);
33
+ const recorded = useMemo(() => getReplayMarkers(events), [events]);
34
+ const shown = useMemo(() => {
35
+ const list = Array.isArray(markers) ? markers : markers ? recorded : [];
36
+ return markerKinds ? list.filter((m) => markerKinds.includes(m.kind)) : list;
37
+ }, [markers, recorded, markerKinds]);
38
+ const [visible, setVisible] = useState(!lazy);
39
+ const [ready, setReady] = useState(false);
40
+ const [posterGone, setPosterGone] = useState(false);
41
+ const [time, setTime] = useState(initialTime);
42
+ const [playing, setPlaying] = useState(false);
43
+ const [finished, setFinished] = useState(false);
44
+ const [speedIndex, setSpeedIndex] = useState(0);
45
+ const [fullscreen, setFullscreen] = useState(false);
46
+ const duration = meta.duration;
47
+ const speedList = speeds.length ? speeds : DEFAULT_PLAYER_SPEEDS;
48
+ const speed = speedList[speedIndex % speedList.length] ?? 1;
49
+ // Lazy mount: start the player (and fetch rrweb) once the frame is near the viewport.
50
+ useEffect(() => {
51
+ if (visible)
52
+ return;
53
+ const el = rootRef.current;
54
+ if (!el || typeof IntersectionObserver === 'undefined')
55
+ return setVisible(true);
56
+ const io = new IntersectionObserver((entries) => entries.some((e) => e.isIntersecting) && setVisible(true), { rootMargin: '240px' });
57
+ io.observe(el);
58
+ return () => io.disconnect();
59
+ }, [visible]);
60
+ useEffect(() => {
61
+ const on = () => setFullscreen(document.fullscreenElement === rootRef.current);
62
+ document.addEventListener('fullscreenchange', on);
63
+ return () => document.removeEventListener('fullscreenchange', on);
64
+ }, []);
65
+ // The poster dissolves (CSS) once the page is ready, then leaves the tree.
66
+ useEffect(() => {
67
+ if (!ready)
68
+ return setPosterGone(false);
69
+ const timer = setTimeout(() => setPosterGone(true), reduced ? 120 : 260);
70
+ return () => clearTimeout(timer);
71
+ }, [ready, reduced]);
72
+ const handle = useMemo(() => ({
73
+ play: (offset) => { setFinished(false); stage.current?.play(offset); },
74
+ pause: (offset) => stage.current?.pause(offset),
75
+ seek: (ms) => { setFinished(false); stage.current?.seek(ms); },
76
+ toggle: () => { setFinished(false); stage.current?.toggle(); },
77
+ getCurrentTime: () => stage.current?.getCurrentTime() ?? 0,
78
+ }), []);
79
+ useImperativeHandle(playerRef, () => handle, [handle]);
80
+ const onTime = useCallback((ms) => { setTime(ms); onTimeUpdate?.(ms); }, [onTimeUpdate]);
81
+ const onPlaying = useCallback((p) => {
82
+ setPlaying(p);
83
+ if (p)
84
+ setFinished(false);
85
+ onPlayingChange?.(p);
86
+ }, [onPlayingChange]);
87
+ const toggle = () => handle.toggle();
88
+ const seekBy = (d) => handle.seek(Math.max(0, Math.min(duration, time + d)));
89
+ const cycleSpeed = (d = 1) => setSpeedIndex((i) => (i + d + speedList.length) % speedList.length);
90
+ const toggleFullscreen = () => {
91
+ const el = rootRef.current;
92
+ if (!el)
93
+ return;
94
+ if (document.fullscreenElement)
95
+ void document.exitFullscreen?.().catch(() => { });
96
+ else
97
+ void el.requestFullscreen?.().catch(() => { });
98
+ };
99
+ const jumpTo = (m) => {
100
+ handle.seek(Math.max(0, m.time - 250));
101
+ onMarkerPress?.(m);
102
+ };
103
+ const onKeyDown = (e) => {
104
+ const target = e.target;
105
+ if (e.metaKey || e.ctrlKey || e.altKey || target.closest('input:not([type=range]), textarea, [contenteditable=true]'))
106
+ return;
107
+ const onSlider = target.matches('input[type=range]');
108
+ const run = (fn) => { e.preventDefault(); fn(); };
109
+ switch (e.key) {
110
+ case ' ':
111
+ case 'k':
112
+ case 'K':
113
+ if (target.closest('button') && e.key === ' ')
114
+ return;
115
+ return run(toggle);
116
+ case 'ArrowLeft':
117
+ if (onSlider)
118
+ return;
119
+ return run(() => seekBy(-5000));
120
+ case 'ArrowRight':
121
+ if (onSlider)
122
+ return;
123
+ return run(() => seekBy(5000));
124
+ case 'j':
125
+ case 'J': return run(() => seekBy(-10000));
126
+ case 'l':
127
+ case 'L': return run(() => seekBy(10000));
128
+ case 'Home':
129
+ if (onSlider)
130
+ return;
131
+ return run(() => handle.seek(0));
132
+ case 'End':
133
+ if (onSlider)
134
+ return;
135
+ return run(() => handle.seek(duration));
136
+ case '>':
137
+ case '.': return run(() => cycleSpeed(1));
138
+ case '<':
139
+ case ',': return run(() => cycleSpeed(-1));
140
+ case 'f':
141
+ case 'F': return run(toggleFullscreen);
142
+ }
143
+ };
144
+ // The URL bar follows the recording: the latest navigation at or before the playhead.
145
+ const href = useMemo(() => {
146
+ if (url)
147
+ return url;
148
+ let current = meta.href ?? '';
149
+ for (const m of recorded)
150
+ if (m.kind === 'navigation' && m.time <= time && m.detail)
151
+ current = m.detail;
152
+ return current;
153
+ }, [url, meta.href, recorded, time]);
154
+ const w = meta.width || 1280;
155
+ const h = meta.height || 800;
156
+ const contain = fit === 'contain' || fullscreen;
157
+ return (_jsxs("div", { ref: rootRef, className: className ? `replay-preview ${className}` : 'replay-preview', "data-slot": "replay-preview", "data-replay-preview": "rrweb", "data-chrome": chrome, "data-fit": contain ? 'contain' : 'width', "data-state": !ready ? 'loading' : playing ? 'playing' : 'paused', "data-fullscreen": fullscreen || undefined, role: "group", "aria-label": title, "aria-busy": !ready || undefined, tabIndex: -1, onKeyDown: onKeyDown,
158
+ // A click anywhere in the player (the page, the frame) makes its keys live, without a focus ring.
159
+ onPointerDown: () => {
160
+ const root = rootRef.current;
161
+ if (root && !root.contains(document.activeElement))
162
+ root.focus({ preventScroll: true });
163
+ }, style: style, children: [chrome === 'browser' ? _jsx(BrowserBar, { href: href, trafficLights: trafficLights, loading: !ready && meta.playable }) : null, _jsxs("div", { "data-slot": "replay-preview-stage", style: { '--replay-ar': `${w} / ${h}` }, children: [visible && meta.playable ? (_jsx(ReplayStage, { ref: stage, events: events, fit: "contain", speed: speed, loop: loop, autoplay: autoplay, initialTime: initialTime, showMouse: false, className: "replay-preview__page", overlay: cursor ? _jsx(PointerOverlay, { track: track, time: time, reduced: !!reduced }) : null, onReady: () => setReady(true), onTimeUpdate: onTime, onPlayingChange: onPlaying, onFinish: () => setFinished(true) })) : null, !posterGone ? (_jsx("div", { "data-slot": "replay-preview-poster", "data-leaving": ready || undefined, children: poster ?? _jsx(PagePoster, { empty: !meta.playable }) })) : null, controls ? (_jsx("div", { "data-slot": "replay-preview-center", "data-show": (ready && !playing) || undefined, children: _jsx("button", { type: "button", tabIndex: -1, "aria-label": finished ? 'Replay from the start' : 'Play',
164
+ // The overlay leaves as playback starts; keep focus (and the keys) in the player.
165
+ onClick: () => { rootRef.current?.focus({ preventScroll: true }); toggle(); }, children: finished ? _jsx(RotateCcw, { size: 22, strokeWidth: 2.4 }) : _jsx(Play, { size: 22, strokeWidth: 2.4, fill: "currentColor" }) }) })) : null] }), controls ? (_jsxs("div", { "data-slot": "replay-preview-controls", children: [_jsx("button", { type: "button", "data-slot": "replay-preview-play", "aria-label": playing ? 'Pause' : 'Play', onClick: toggle, disabled: !ready, children: playing ? _jsx(Pause, { size: 15, fill: "currentColor" }) : _jsx(Play, { size: 15, fill: "currentColor" }) }), _jsxs("span", { "data-slot": "replay-preview-time", children: [_jsx("span", { children: formatReplayTime(time) }), " / ", formatReplayTime(duration)] }), _jsx(Scrubber, { time: time, duration: duration, markers: shown, disabled: !ready, onSeek: (ms) => handle.seek(ms), onMarker: jumpTo }), _jsx("button", { type: "button", "data-slot": "replay-preview-speed", "aria-label": `Playback speed ${speed}×`, onClick: () => cycleSpeed(1), children: `${speed}×` }), _jsx("button", { type: "button", "data-slot": "replay-preview-fullscreen", "aria-label": fullscreen ? 'Exit full screen' : 'Full screen', onClick: toggleFullscreen, children: fullscreen ? _jsx(Minimize, { size: 15 }) : _jsx(Maximize, { size: 15 }) })] })) : null] }));
166
+ }
167
+ /* ── parts ───────────────────────────────────────────────────────────────────────── */
168
+ export function BrowserBar({ href, trafficLights, loading }) {
169
+ const shown = href.replace(/^https?:\/\//, '');
170
+ const slash = shown.indexOf('/');
171
+ const host = slash < 0 ? shown : shown.slice(0, slash);
172
+ const path = slash < 0 ? '' : shown.slice(slash);
173
+ return (_jsxs("div", { "data-slot": "replay-preview-bar", children: [trafficLights ? (_jsx("span", { "aria-hidden": "true", "data-slot": "replay-preview-lights", children: TRAFFIC_LIGHTS.map((c) => _jsx("span", { style: { '--light': c } }, c)) })) : null, _jsxs("div", { "data-slot": "replay-preview-address", children: [_jsx("span", { "data-slot": "replay-preview-lock", "aria-hidden": "true", children: loading ? _jsx("span", { "data-slot": "replay-preview-spinner" }) : _jsx(Lock, { size: 10, strokeWidth: 2.5 }) }), _jsxs("span", { "data-slot": "replay-preview-url", title: href, children: [_jsx("span", { children: host }), _jsx("span", { children: path })] })] }), trafficLights ? _jsx("span", { "aria-hidden": "true", "data-slot": "replay-preview-lights-spacer" }) : null] }));
174
+ }
175
+ /** The recorded pointer and its click ripples, in recorded-viewport coordinates. */
176
+ const PointerOverlay = memo(function PointerOverlay({ track, time, reduced }) {
177
+ const at = replayPointerAt(track, time);
178
+ const ripples = track.clicks.filter((c) => time >= c.time && time - c.time < RIPPLE_MS);
179
+ return (_jsxs("div", { "data-slot": "replay-preview-pointer", "aria-hidden": "true", children: [ripples.map((c) => {
180
+ const p = (time - c.time) / RIPPLE_MS;
181
+ const ease = 1 - (1 - p) ** 3;
182
+ return (_jsx("span", { "data-slot": "replay-preview-ripple", style: {
183
+ left: c.x, top: c.y,
184
+ transform: `translate(-50%, -50%) scale(calc(${reduced ? 0.8 : 0.25 + ease * 1.05} / var(--replay-scale, 1)))`,
185
+ opacity: 1 - p,
186
+ } }, c.time));
187
+ }), at ? (_jsx("svg", { "data-slot": "replay-preview-cursor", viewBox: "0 0 20 24", width: "20", height: "24", style: { left: at.x - 2, top: at.y - 1, transform: 'scale(calc(1 / var(--replay-scale, 1)))' }, children: _jsx("path", { d: "M2.5 1.5v18.2l4.7-4.5 3 6.8 3.1-1.4-3-6.6h6.5z", fill: "#000", stroke: "#fff", strokeWidth: "1.4", strokeLinejoin: "round" }) })) : null] }));
188
+ });
189
+ function Scrubber({ time, duration, markers, disabled, onSeek, onMarker }) {
190
+ const max = Math.max(1, duration);
191
+ const value = Math.min(time, max);
192
+ // Dots closer than ~1.5% of the timeline would sit on top of each other: step each one 10px right of the last.
193
+ const nudges = useMemo(() => {
194
+ const out = new Map();
195
+ let last = null;
196
+ for (const m of [...markers].sort((a, b) => a.time - b.time)) {
197
+ if (m.kind === 'click')
198
+ continue;
199
+ const n = last && m.time - last.time < max * 0.015 ? last.n + 1 : 0;
200
+ out.set(m.id, n);
201
+ last = { time: m.time, n };
202
+ }
203
+ return out;
204
+ }, [markers, max]);
205
+ return (_jsxs("div", { "data-slot": "replay-preview-scrubber", "data-markers": markers.length ? '' : undefined, children: [markers.length ? (_jsx("div", { "data-slot": "replay-preview-markers", children: markers.map((m) => (_jsx("button", { type: "button", "data-kind": m.kind, "aria-label": `${m.label} at ${formatReplayTime(m.time)}`, title: `${formatReplayTime(m.time)} · ${MARKER_NOUN[m.kind]}\n${m.detail ? `${m.label} — ${m.detail}` : m.label}`, style: { left: `calc(${(m.time / max) * 100}% + ${(nudges.get(m.id) ?? 0) * 10}px)` }, onClick: () => onMarker(m), disabled: disabled }, m.id))) })) : null, _jsx("input", { type: "range", "aria-label": "Playback position", "aria-valuetext": `${formatReplayTime(value)} of ${formatReplayTime(duration)}`, min: 0, max: max, step: 10, value: value, disabled: disabled, style: { '--replay-progress': `${(value / max) * 100}%` }, onChange: (e) => onSeek(Number(e.currentTarget.value)) })] }));
206
+ }
207
+ /** A page-shaped placeholder: header, hero lines and a card grid, sized to the frame. */
208
+ function PagePoster({ empty }) {
209
+ return (_jsxs("div", { "data-slot": "replay-preview-skeleton", children: [_jsxs("div", { "data-part": "header", children: [_jsx("i", { style: { width: '12%' } }), _jsx("i", { style: { width: '8%' } }), _jsx("i", { style: { width: '8%' } }), _jsx("span", {}), _jsx("i", { "data-tone": "block", style: { width: '9%' } })] }), _jsxs("div", { "data-part": "hero", children: [_jsx("i", { style: { width: '38%', height: 12 } }), _jsx("i", { style: { width: '24%', height: 8 } })] }), _jsx("div", { "data-part": "grid", children: [0, 1, 2, 3].map((i) => _jsx("i", { "data-tone": "block" }, i)) }), empty ? _jsx("span", { "data-part": "empty", children: _jsx("span", { children: "This recording has no page snapshot to play" }) }) : null] }));
210
+ }
211
+ //# sourceMappingURL=ReplayPlayer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReplayPlayer.js","sourceRoot":"","sources":["../../src/replay/ReplayPlayer.tsx"],"names":[],"mappings":"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"}
@@ -1,4 +1,7 @@
1
+ import type { ReplayPlayerOptions } from './ReplayPlayer.js';
1
2
  import type { ReplayEvent } from './types.js';
3
+ export { formatReplayTime } from './ReplayPlayer.js';
4
+ export type { ReplayChrome, ReplayPlayerOptions, ReplayPreviewHandle } from './ReplayPlayer.js';
2
5
  export interface ReplayPageSource {
3
6
  kind: 'url';
4
7
  url: string;
@@ -14,20 +17,29 @@ export interface ReplayEventsUrlSource {
14
17
  fetchInit?: RequestInit;
15
18
  }
16
19
  export type ReplaySource = string | ReplayEvent[] | ReplayPageSource | ReplayEventsSource | ReplayEventsUrlSource;
17
- export interface ReplayPreviewProps {
18
- /** A public Loop QA URL, a public event endpoint, or an in-memory rrweb event list. */
19
- source: ReplaySource;
20
- /** Avoid mounting the rrweb player until the editor block is visible. */
20
+ interface ReplayPreviewCommon extends ReplayPlayerOptions {
21
+ /** Keep the player unmounted (a placeholder frame) until true, e.g. until an editor block is visible. */
21
22
  active?: boolean;
22
- /** Public-page embeds default to lazy loading; native rrweb playback defaults to paused. */
23
- autoplay?: boolean;
24
- loop?: boolean;
25
- className?: string;
26
- title?: string;
27
- /** Playback speed options mirror the Loop QA player. */
28
- speeds?: number[];
29
23
  }
30
- export declare function ReplayPreview({ source, active, autoplay, loop, className, title, speeds, }: ReplayPreviewProps): import("react").JSX.Element | null;
24
+ /** Play an rrweb recording you already hold. */
25
+ export interface ReplayPreviewEventsProps extends ReplayPreviewCommon {
26
+ events: ReplayEvent[];
27
+ source?: undefined;
28
+ }
29
+ /** Embed a public Loop QA URL, a public event endpoint, or an in-memory rrweb event list. */
30
+ export interface ReplayPreviewSourceProps extends ReplayPreviewCommon {
31
+ source: ReplaySource;
32
+ events?: undefined;
33
+ }
34
+ /** Pass `events` (the player API) or `source` (the embed API): both render the same player. */
35
+ export type ReplayPreviewProps = ReplayPreviewEventsProps | ReplayPreviewSourceProps;
36
+ /**
37
+ * A session replay in a browser frame. Pass `events` (an rrweb recording) to play it with the full player:
38
+ * URL bar, poster, scrubber with markers, pointer overlay, keyboard map, fullscreen. Or pass `source` (a
39
+ * public Loop QA URL, an events URL, or an event list), which renders the same player, or an iframe for
40
+ * page URLs. rrweb loads on first render of an event player, never for iframes.
41
+ */
42
+ export declare function ReplayPreview(props: ReplayPreviewProps): import("react").JSX.Element | null;
31
43
  /** Semantic alias for markdown/document renderers. */
32
44
  export declare const ReplayEmbed: typeof ReplayPreview;
33
45
  //# sourceMappingURL=ReplayPreview.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReplayPreview.d.ts","sourceRoot":"","sources":["../../src/replay/ReplayPreview.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,KAAK,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,YAAY,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,WAAW,CAAC;CACzB;AAED,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,WAAW,EAAE,GACb,gBAAgB,GAChB,kBAAkB,GAClB,qBAAqB,CAAC;AAE1B,MAAM,WAAW,kBAAkB;IACjC,uFAAuF;IACvF,MAAM,EAAE,YAAY,CAAC;IACrB,yEAAyE;IACzE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAiGD,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,MAAa,EACb,QAAgB,EAChB,IAAY,EACZ,SAAS,EACT,KAAK,EACL,MAAuB,GACxB,EAAE,kBAAkB,sCA8BpB;AAED,sDAAsD;AACtD,eAAO,MAAM,WAAW,sBAAgB,CAAC"}
1
+ {"version":3,"file":"ReplayPreview.d.ts","sourceRoot":"","sources":["../../src/replay/ReplayPreview.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAuB,MAAM,gBAAgB,CAAC;AAC/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE7F,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,KAAK,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,YAAY,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,WAAW,CAAC;CACzB;AAED,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,WAAW,EAAE,GACb,gBAAgB,GAChB,kBAAkB,GAClB,qBAAqB,CAAC;AAE1B,UAAU,mBAAoB,SAAQ,mBAAmB;IACvD,yGAAyG;IACzG,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,gDAAgD;AAChD,MAAM,WAAW,wBAAyB,SAAQ,mBAAmB;IACnE,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,6FAA6F;AAC7F,MAAM,WAAW,wBAAyB,SAAQ,mBAAmB;IACnE,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,+FAA+F;AAC/F,MAAM,MAAM,kBAAkB,GAAG,wBAAwB,GAAG,wBAAwB,CAAC;AAoHrF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,sCA4BtD;AAED,sDAAsD;AACtD,eAAO,MAAM,WAAW,sBAAgB,CAAC"}
@@ -1,7 +1,8 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Suspense, lazy, useEffect, useState } from 'react';
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { BrowserBar, ReplayPlayer } from './ReplayPlayer.js';
3
4
  import { normalizeReplayEmbedUrl } from './url.js';
4
- const DEFAULT_SPEEDS = [0.5, 1, 2, 4, 8];
5
+ export { formatReplayTime } from './ReplayPlayer.js';
5
6
  function sourcePage(source) {
6
7
  if (typeof source === 'string')
7
8
  return { kind: 'url', url: source };
@@ -21,19 +22,15 @@ function sourceEventsUrl(source) {
21
22
  return null;
22
23
  return source.kind === 'events-url' ? source : null;
23
24
  }
24
- function ReplayFrame({ source, title }) {
25
- const url = normalizeReplayEmbedUrl(source.url);
26
- if (!url) {
27
- return (_jsx("a", { className: "replay-preview__invalid", href: source.url, target: "_blank", rel: "noreferrer", children: "Open replay" }));
28
- }
29
- return (_jsx("iframe", { className: "replay-preview__frame", src: url, title: title ?? source.title ?? 'Replay preview', loading: "lazy", allow: "autoplay; fullscreen", allowFullScreen: true, referrerPolicy: "strict-origin-when-cross-origin" }));
25
+ /** The frame around a non-player body (an iframe, a loading or error note): same root, same chrome hooks. */
26
+ function Frame({ kind, chrome, className, title, href, trafficLights = true, ar, style, children, }) {
27
+ return (_jsxs("div", { className: className ? `replay-preview ${className}` : 'replay-preview', "data-slot": "replay-preview", "data-replay-preview": kind, "data-chrome": chrome, "data-fit": "width", style: style, ...(title ? { role: 'group', 'aria-label': title } : null), children: [chrome === 'browser' ? _jsx(BrowserBar, { href: href ?? '', trafficLights: trafficLights, loading: false }) : null, _jsx("div", { "data-slot": "replay-preview-stage", style: ar ? { '--replay-ar': ar } : undefined, children: children })] }));
30
28
  }
31
- // rrweb (and its stylesheet) load on first use of an event-based source.
32
- const LazyNativeReplay = lazy(() => import('./NativeReplay.js'));
33
- function NativeReplay(props) {
34
- return (_jsx(Suspense, { fallback: _jsx("div", { className: "replay-preview__empty", children: "Loading replay\u2026" }), children: _jsx(LazyNativeReplay, { ...props }) }));
29
+ function ReplayFrame({ source, title, chrome = 'minimal', className, style, trafficLights, }) {
30
+ const url = normalizeReplayEmbedUrl(source.url);
31
+ return (_jsx(Frame, { kind: "iframe", chrome: chrome, className: className, style: style, href: url ?? source.url, trafficLights: trafficLights, ar: "16 / 9", children: url ? (_jsx("iframe", { className: "replay-preview__frame", src: url, title: title ?? source.title ?? 'Replay preview', loading: "lazy", allow: "autoplay; fullscreen", allowFullScreen: true, referrerPolicy: "strict-origin-when-cross-origin" })) : (_jsx("a", { className: "replay-preview__invalid", href: source.url, target: "_blank", rel: "noreferrer", children: "Open replay" })) }));
35
32
  }
36
- function RemoteReplay({ source, autoplay, loop, speeds, }) {
33
+ function RemoteReplay({ source, options }) {
37
34
  const [events, setEvents] = useState(null);
38
35
  const [error, setError] = useState(null);
39
36
  useEffect(() => {
@@ -62,28 +59,36 @@ function RemoteReplay({ source, autoplay, loop, speeds, }) {
62
59
  });
63
60
  return () => controller.abort();
64
61
  }, [source.url, source.fetchInit]);
65
- if (error)
66
- return _jsx("div", { className: "replay-preview__error", role: "alert", children: error });
67
- if (!events)
68
- return _jsx("div", { className: "replay-preview__empty", children: "Loading replay\u2026" });
69
- return _jsx(NativeReplay, { events: events, autoplay: autoplay, loop: loop, speeds: speeds });
62
+ if (events)
63
+ return _jsx(ReplayPlayer, { ...options, events: events });
64
+ return (_jsx(Frame, { kind: "rrweb", chrome: options.chrome ?? 'browser', className: options.className, style: options.style, href: options.url, trafficLights: options.trafficLights, ar: "16 / 9", children: error ? (_jsx("div", { className: "replay-preview__error", role: "alert", children: error })) : (_jsx("div", { className: "replay-preview__empty", children: "Loading replay\u2026" })) }));
70
65
  }
71
- export function ReplayPreview({ source, active = true, autoplay = false, loop = false, className, title, speeds = DEFAULT_SPEEDS, }) {
72
- if (!active)
73
- return _jsx("div", { className: `replay-preview ${className ?? ''}`.trim(), "data-replay-preview": "paused" });
66
+ /**
67
+ * A session replay in a browser frame. Pass `events` (an rrweb recording) to play it with the full player:
68
+ * URL bar, poster, scrubber with markers, pointer overlay, keyboard map, fullscreen. Or pass `source` (a
69
+ * public Loop QA URL, an events URL, or an event list), which renders the same player, or an iframe for
70
+ * page URLs. rrweb loads on first render of an event player, never for iframes.
71
+ */
72
+ export function ReplayPreview(props) {
73
+ const { active = true, source, events, ...options } = props;
74
+ const { chrome, className, style } = options;
75
+ if (!active) {
76
+ return (_jsx("div", { className: className ? `replay-preview ${className}` : 'replay-preview', "data-slot": "replay-preview", "data-replay-preview": "paused", "data-chrome": chrome ?? 'minimal', style: style }));
77
+ }
78
+ if (events)
79
+ return _jsx(ReplayPlayer, { ...options, events: events });
80
+ if (source === undefined)
81
+ return null;
74
82
  const page = sourcePage(source);
75
- const events = sourceEvents(source);
76
- const eventsUrl = sourceEventsUrl(source);
77
- const rootClass = `replay-preview ${className ?? ''}`.trim();
78
83
  if (page) {
79
- return (_jsx("div", { className: rootClass, "data-replay-preview": "iframe", children: _jsx(ReplayFrame, { source: page, title: title }) }));
80
- }
81
- if (events) {
82
- return (_jsx("div", { className: rootClass, "data-replay-preview": "rrweb", children: _jsx(NativeReplay, { events: events.events, autoplay: autoplay, loop: loop, speeds: speeds }) }));
83
- }
84
- if (eventsUrl) {
85
- return (_jsx("div", { className: rootClass, "data-replay-preview": "rrweb", children: _jsx(RemoteReplay, { source: eventsUrl, autoplay: autoplay, loop: loop, speeds: speeds }) }));
84
+ return _jsx(ReplayFrame, { source: page, title: options.title, chrome: chrome, className: className, style: style, trafficLights: options.trafficLights });
86
85
  }
86
+ const list = sourceEvents(source);
87
+ if (list)
88
+ return _jsx(ReplayPlayer, { ...options, events: list.events });
89
+ const remote = sourceEventsUrl(source);
90
+ if (remote)
91
+ return _jsx(RemoteReplay, { source: remote, options: options });
87
92
  return null;
88
93
  }
89
94
  /** Semantic alias for markdown/document renderers. */