@bendyline/squisq-react 2.4.2 → 2.4.4

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  BlockRenderer,
3
3
  LinearDocView
4
- } from "./chunk-ZIMG7EQV.js";
4
+ } from "./chunk-EJMUO6VX.js";
5
5
  import {
6
6
  useAudioSync,
7
7
  useDocPlayback,
@@ -185,6 +185,7 @@ function MediaClipElement({
185
185
  src,
186
186
  preload: "auto",
187
187
  "data-clip-id": clip.id,
188
+ "data-active": active ? "true" : "false",
188
189
  "data-abs-start": clip.absoluteStart,
189
190
  "data-abs-end": clip.absoluteEnd,
190
191
  "data-source-in": clip.sourceIn
@@ -195,7 +196,6 @@ function MediaClipElement({
195
196
  {
196
197
  ...common,
197
198
  className: `doc-player__media-video${active ? " doc-player__media-video--active" : ""}`,
198
- "data-active": active ? "true" : "false",
199
199
  "data-video-placement": clip.placement ?? "default",
200
200
  muted: renderMode || muted,
201
201
  playsInline: true,
@@ -1540,6 +1540,7 @@ function buildSegmentTitleMap(doc) {
1540
1540
 
1541
1541
  // src/docPlayer/renderReadiness.ts
1542
1542
  var DEFAULT_VIDEO_FRAME_TIMEOUT_MS = 2e3;
1543
+ var VIDEO_FRAME_READINESS_POLL_MS = 16;
1543
1544
  var VIDEO_TIME_TOLERANCE_SECONDS = 0.01;
1544
1545
  function formatMediaTime(time) {
1545
1546
  return Number.isFinite(time) ? `${time.toFixed(3)}s` : String(time);
@@ -1565,6 +1566,7 @@ function seekVideoToFrame(video, targetTime, timeoutMs = DEFAULT_VIDEO_FRAME_TIM
1565
1566
  let videoFrameRequest = null;
1566
1567
  const cleanup = () => {
1567
1568
  clearTimeout(timeout);
1569
+ clearInterval(readinessPoll);
1568
1570
  video.removeEventListener("seeked", handleMediaReady);
1569
1571
  video.removeEventListener("loadeddata", handleMediaReady);
1570
1572
  video.removeEventListener("canplay", handleMediaReady);
@@ -1589,7 +1591,9 @@ function seekVideoToFrame(video, targetTime, timeoutMs = DEFAULT_VIDEO_FRAME_TIM
1589
1591
  );
1590
1592
  };
1591
1593
  const requestPresentedFrame = () => {
1592
- if (settled || video.seeking || video.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) return;
1594
+ if (settled || video.seeking || video.readyState < HTMLMediaElement.HAVE_CURRENT_DATA || Math.abs(video.currentTime - targetTime) > VIDEO_TIME_TOLERANCE_SECONDS) {
1595
+ return;
1596
+ }
1593
1597
  if (typeof video.requestVideoFrameCallback !== "function" || !isVisiblyPresented(video)) {
1594
1598
  finish();
1595
1599
  return;
@@ -1604,6 +1608,7 @@ function seekVideoToFrame(video, targetTime, timeoutMs = DEFAULT_VIDEO_FRAME_TIM
1604
1608
  requestPresentedFrame();
1605
1609
  }
1606
1610
  const timeout = setTimeout(fail, timeoutMs);
1611
+ const readinessPoll = setInterval(requestPresentedFrame, VIDEO_FRAME_READINESS_POLL_MS);
1607
1612
  video.addEventListener("seeked", handleMediaReady);
1608
1613
  video.addEventListener("loadeddata", handleMediaReady);
1609
1614
  video.addEventListener("canplay", handleMediaReady);
@@ -1757,6 +1762,27 @@ function DocPlayerContent({
1757
1762
  () => resolveMediaSchedule(doc, { intrinsicDuration: (clip) => clipDurations.get(clip.src) }),
1758
1763
  [doc, clipDurations]
1759
1764
  );
1765
+ const startActiveTimelineMedia = useCallback4(() => {
1766
+ if (renderMode) return;
1767
+ const root = containerRef.current;
1768
+ if (!root) return;
1769
+ const activeMedia = root.querySelectorAll(
1770
+ '.doc-player__block--active video[data-clip-start], [data-clip-id][data-active="true"]'
1771
+ );
1772
+ activeMedia.forEach((element) => {
1773
+ const playPromise = element.play();
1774
+ if (playPromise) playPromise.catch(() => {
1775
+ });
1776
+ });
1777
+ }, [renderMode]);
1778
+ const playWithTimelineMedia = useCallback4(() => {
1779
+ startActiveTimelineMedia();
1780
+ return play();
1781
+ }, [play, startActiveTimelineMedia]);
1782
+ const toggleWithTimelineMedia = useCallback4(() => {
1783
+ if (!isPlaying) startActiveTimelineMedia();
1784
+ return toggle();
1785
+ }, [isPlaying, startActiveTimelineMedia, toggle]);
1760
1786
  const currentTimeRef = useRef5(currentTime);
1761
1787
  currentTimeRef.current = currentTime;
1762
1788
  const committedRenderTimeRef = useRef5(currentTime);
@@ -1803,13 +1829,13 @@ function DocPlayerContent({
1803
1829
  ))
1804
1830
  return;
1805
1831
  containerRef.current?.focus({ preventScroll: true });
1806
- toggle();
1832
+ toggleWithTimelineMedia();
1807
1833
  const nextState = isPlaying ? "pause" : "play";
1808
1834
  setTapFeedback(nextState);
1809
1835
  clearTimeout(tapFeedbackTimer.current);
1810
1836
  tapFeedbackTimer.current = setTimeout(() => setTapFeedback(null), 600);
1811
1837
  },
1812
- [renderMode, toggle, isPlaying, isSlideshowMode, isLinearMode]
1838
+ [renderMode, toggleWithTimelineMedia, isPlaying, isSlideshowMode, isLinearMode]
1813
1839
  );
1814
1840
  const autoSurface = useAutoSurface(surface === "auto");
1815
1841
  const resolvedSurface = surface === "auto" ? autoSurface : surface;
@@ -1932,9 +1958,9 @@ function DocPlayerContent({
1932
1958
  useEffect5(() => {
1933
1959
  if (isAudioReady && autoPlay && !hasAutoPlayed.current) {
1934
1960
  hasAutoPlayed.current = true;
1935
- play();
1961
+ playWithTimelineMedia();
1936
1962
  }
1937
- }, [isAudioReady, autoPlay, play]);
1963
+ }, [isAudioReady, autoPlay, playWithTimelineMedia]);
1938
1964
  useEffect5(() => {
1939
1965
  onTimeUpdate?.(currentTime);
1940
1966
  }, [currentTime, onTimeUpdate]);
@@ -2173,14 +2199,21 @@ function DocPlayerContent({
2173
2199
  );
2174
2200
  const playbackActions = useMemo3(
2175
2201
  () => ({
2176
- toggle,
2202
+ toggle: toggleWithTimelineMedia,
2177
2203
  restart,
2178
2204
  seekTo,
2179
2205
  setCaptionsEnabled,
2180
2206
  cycleCaptionMode,
2181
2207
  toggleFullscreen: onFullscreenToggle
2182
2208
  }),
2183
- [toggle, restart, seekTo, setCaptionsEnabled, cycleCaptionMode, onFullscreenToggle]
2209
+ [
2210
+ toggleWithTimelineMedia,
2211
+ restart,
2212
+ seekTo,
2213
+ setCaptionsEnabled,
2214
+ cycleCaptionMode,
2215
+ onFullscreenToggle
2216
+ ]
2184
2217
  );
2185
2218
  const slideNavActions = useMemo3(
2186
2219
  () => ({
@@ -2275,8 +2308,8 @@ function DocPlayerContent({
2275
2308
  onPlaybackStateChange?.(playbackState);
2276
2309
  }, [playbackState, onPlaybackStateChange]);
2277
2310
  useEffect5(() => {
2278
- onControlsReady?.({ play, pause, ...playbackActions });
2279
- }, [play, pause, playbackActions, onControlsReady]);
2311
+ onControlsReady?.({ play: playWithTimelineMedia, pause, ...playbackActions });
2312
+ }, [playWithTimelineMedia, pause, playbackActions, onControlsReady]);
2280
2313
  const getBlockTitle = useCallback4((block) => {
2281
2314
  const docBlock = block;
2282
2315
  if (isTemplateBlock2(docBlock)) {
@@ -2390,7 +2423,7 @@ function DocPlayerContent({
2390
2423
  switch (e.key) {
2391
2424
  case " ":
2392
2425
  e.preventDefault();
2393
- toggle();
2426
+ toggleWithTimelineMedia();
2394
2427
  break;
2395
2428
  case "ArrowRight":
2396
2429
  e.preventDefault();
@@ -2403,7 +2436,14 @@ function DocPlayerContent({
2403
2436
  }
2404
2437
  }
2405
2438
  },
2406
- [isSlideshowMode, isLinearMode, toggle, seekTo, slideNavActions, onFullscreenToggle]
2439
+ [
2440
+ isSlideshowMode,
2441
+ isLinearMode,
2442
+ toggleWithTimelineMedia,
2443
+ seekTo,
2444
+ slideNavActions,
2445
+ onFullscreenToggle
2446
+ ]
2407
2447
  );
2408
2448
  const handleKeyDown = useCallback4(
2409
2449
  (e) => handleKeyboardShortcut(e, false),
@@ -2498,6 +2538,7 @@ function DocPlayerContent({
2498
2538
  basePath,
2499
2539
  isEntering: false,
2500
2540
  viewport: activeViewport,
2541
+ muted: renderMode || muted,
2501
2542
  animationsEnabled,
2502
2543
  theme: effectiveTheme
2503
2544
  }
@@ -2515,15 +2556,20 @@ function DocPlayerContent({
2515
2556
  isExiting: true,
2516
2557
  transition: currentBlock?.transition,
2517
2558
  viewport: activeViewport,
2559
+ muted: renderMode || muted,
2518
2560
  animationsEnabled,
2519
2561
  theme: effectiveTheme
2520
2562
  }
2521
2563
  ) }, previousBlock.id),
2522
- !showCoverBlock && currentBlock && /* @__PURE__ */ jsx7(
2564
+ currentBlock && /* @__PURE__ */ jsx7(
2523
2565
  "div",
2524
2566
  {
2525
2567
  className: `doc-player__block doc-player__block--active${swipe.phase !== "idle" ? ` doc-player__block--${swipe.phase}` : ""}`,
2526
- style: swipe.phase !== "idle" ? { transform: `translateX(${swipe.offsetPx}px)` } : void 0,
2568
+ "aria-hidden": showCoverBlock || void 0,
2569
+ style: showCoverBlock || swipe.phase !== "idle" ? {
2570
+ ...swipe.phase !== "idle" ? { transform: `translateX(${swipe.offsetPx}px)` } : {},
2571
+ ...showCoverBlock ? { opacity: 0, pointerEvents: "none" } : {}
2572
+ } : void 0,
2527
2573
  children: /* @__PURE__ */ jsx7(
2528
2574
  BlockRenderer,
2529
2575
  {
@@ -2533,6 +2579,7 @@ function DocPlayerContent({
2533
2579
  isEntering: animationsEnabled && isEntering,
2534
2580
  viewport: activeViewport,
2535
2581
  isPlaying,
2582
+ muted: renderMode || muted,
2536
2583
  animationsEnabled,
2537
2584
  theme: effectiveTheme
2538
2585
  }
@@ -9,7 +9,7 @@ import {
9
9
  TreeLayer,
10
10
  VideoLayer,
11
11
  getTransitionClass
12
- } from "./chunk-EMSYAEWP.js";
12
+ } from "./chunk-TI5X7SBC.js";
13
13
  import {
14
14
  useAutoSurface
15
15
  } from "./chunk-TT6ENR6T.js";
@@ -38,6 +38,7 @@ function BlockRenderer({
38
38
  transition,
39
39
  viewport = DEFAULT_VIEWPORT,
40
40
  isPlaying,
41
+ muted = false,
41
42
  animationsEnabled = true,
42
43
  theme
43
44
  }) {
@@ -72,6 +73,7 @@ function BlockRenderer({
72
73
  viewport,
73
74
  blockTime,
74
75
  isPlaying,
76
+ muted,
75
77
  animationsEnabled,
76
78
  theme
77
79
  },
@@ -87,6 +89,7 @@ function LayerRenderer({
87
89
  viewport,
88
90
  blockTime,
89
91
  isPlaying,
92
+ muted,
90
93
  animationsEnabled,
91
94
  theme
92
95
  }) {
@@ -127,7 +130,8 @@ function LayerRenderer({
127
130
  basePath,
128
131
  viewport,
129
132
  blockTime,
130
- isPlaying
133
+ isPlaying,
134
+ muted
131
135
  }
132
136
  );
133
137
  case "table":
@@ -1245,7 +1245,14 @@ function MapLayer({ layer, basePath, viewport, blockTime }) {
1245
1245
  import { useRef, useEffect as useEffect2 } from "react";
1246
1246
  import { jsx as jsx7 } from "react/jsx-runtime";
1247
1247
  var VIDEO_SYNC_DRIFT_SECONDS = 0.2;
1248
- function VideoLayer({ layer, basePath, viewport, blockTime, isPlaying }) {
1248
+ function VideoLayer({
1249
+ layer,
1250
+ basePath,
1251
+ viewport,
1252
+ blockTime,
1253
+ isPlaying,
1254
+ muted = false
1255
+ }) {
1249
1256
  const { content, position } = layer;
1250
1257
  const videoRef = useRef(null);
1251
1258
  const hasStartedRef = useRef(false);
@@ -1316,7 +1323,7 @@ function VideoLayer({ layer, basePath, viewport, blockTime, isPlaying }) {
1316
1323
  ref: videoRef,
1317
1324
  src,
1318
1325
  poster: posterSrc,
1319
- muted: true,
1326
+ muted,
1320
1327
  playsInline: true,
1321
1328
  preload: "auto",
1322
1329
  "data-clip-start": content.clipStart,
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  formatTime,
13
13
  resolveDocPlayerAppearance,
14
14
  useMediaClipDurations
15
- } from "./chunk-R5XTAWQH.js";
15
+ } from "./chunk-AKPXDG4E.js";
16
16
  import {
17
17
  BlockRenderer,
18
18
  CanvasSection,
@@ -20,7 +20,7 @@ import {
20
20
  PageSectionView,
21
21
  PageViewContext,
22
22
  usePageView
23
- } from "./chunk-ZIMG7EQV.js";
23
+ } from "./chunk-EJMUO6VX.js";
24
24
  import {
25
25
  ImageLayer,
26
26
  MapLayer,
@@ -33,7 +33,7 @@ import {
33
33
  VideoLayer,
34
34
  getAnimationStyle,
35
35
  getTransitionClass
36
- } from "./chunk-EMSYAEWP.js";
36
+ } from "./chunk-TI5X7SBC.js";
37
37
  import {
38
38
  useModalDialog
39
39
  } from "./chunk-65POMKHR.js";
@@ -70,8 +70,10 @@ interface VideoLayerProps {
70
70
  blockTime: number;
71
71
  /** Whether the doc is currently playing */
72
72
  isPlaying?: boolean;
73
+ /** Silence the video's own audio track. */
74
+ muted?: boolean;
73
75
  }
74
- declare function VideoLayer({ layer, basePath, viewport, blockTime, isPlaying }: VideoLayerProps): react_jsx_runtime.JSX.Element;
76
+ declare function VideoLayer({ layer, basePath, viewport, blockTime, isPlaying, muted, }: VideoLayerProps): react_jsx_runtime.JSX.Element;
75
77
 
76
78
  interface TableLayerProps {
77
79
  layer: TableLayer$1;
@@ -8,7 +8,7 @@ import {
8
8
  TextLayer,
9
9
  TreeLayer,
10
10
  VideoLayer
11
- } from "../chunk-EMSYAEWP.js";
11
+ } from "../chunk-TI5X7SBC.js";
12
12
  import "../chunk-WLUZTUNZ.js";
13
13
  import "../chunk-LR3AIGDD.js";
14
14
  export {
@@ -4,8 +4,8 @@ import {
4
4
  PageSectionView,
5
5
  PageViewContext,
6
6
  usePageView
7
- } from "../chunk-ZIMG7EQV.js";
8
- import "../chunk-EMSYAEWP.js";
7
+ } from "../chunk-EJMUO6VX.js";
8
+ import "../chunk-TI5X7SBC.js";
9
9
  import "../chunk-TT6ENR6T.js";
10
10
  import "../chunk-D7KN4CRG.js";
11
11
  import "../chunk-WLUZTUNZ.js";
@@ -269,6 +269,8 @@ interface BlockRendererProps {
269
269
  viewport?: ViewportDimensions;
270
270
  /** Whether the doc is currently playing (controls video playback) */
271
271
  isPlaying?: boolean;
272
+ /** Silence audio carried by video layers. */
273
+ muted?: boolean;
272
274
  /**
273
275
  * Whether to render block transitions and layer animations (default: true).
274
276
  * Disabling this only removes authored/render-style motion; timed video
@@ -278,7 +280,7 @@ interface BlockRendererProps {
278
280
  /** Resolved theme inherited by rich-media renderers such as Mermaid. */
279
281
  theme?: Theme;
280
282
  }
281
- declare function BlockRenderer({ block, blockTime, basePath, isEntering, isExiting, transition, viewport, isPlaying, animationsEnabled, theme, }: BlockRendererProps): react_jsx_runtime.JSX.Element;
283
+ declare function BlockRenderer({ block, blockTime, basePath, isEntering, isExiting, transition, viewport, isPlaying, muted, animationsEnabled, theme, }: BlockRendererProps): react_jsx_runtime.JSX.Element;
282
284
 
283
285
  interface CaptionOverlayProps {
284
286
  /** Caption track with timestamped phrases */
@@ -10,11 +10,11 @@ import {
10
10
  MediaClipLayer,
11
11
  SocialCaptionOverlay,
12
12
  formatTime
13
- } from "../chunk-R5XTAWQH.js";
13
+ } from "../chunk-AKPXDG4E.js";
14
14
  import {
15
15
  BlockRenderer
16
- } from "../chunk-ZIMG7EQV.js";
17
- import "../chunk-EMSYAEWP.js";
16
+ } from "../chunk-EJMUO6VX.js";
17
+ import "../chunk-TI5X7SBC.js";
18
18
  import "../chunk-BOZJ655L.js";
19
19
  import "../chunk-TT6ENR6T.js";
20
20
  import {