@bendyline/squisq-react 1.4.1 → 1.4.2

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/index.d.ts CHANGED
@@ -131,6 +131,12 @@ interface PlaybackState$1 {
131
131
  currentSegmentName: string | null;
132
132
  /** Current block data (for extracting image info, etc.) */
133
133
  currentBlock: Block | null;
134
+ /** Optional display label for non-block slides, e.g. the managed cover. */
135
+ currentSlideLabel?: string;
136
+ /** Optional human-facing slide number, separate from internal nav index. */
137
+ currentSlideNumber?: number;
138
+ /** Optional human-facing slide total, separate from internal nav total. */
139
+ totalSlideNumber?: number;
134
140
  }
135
141
  /** Playback actions exposed to external control components */
136
142
  interface PlaybackActions$1 {
@@ -280,6 +286,11 @@ interface DocPlayerProps {
280
286
  * template-annotated sections as inline SVG cards. No audio, no timeline.
281
287
  */
282
288
  displayMode?: DisplayMode;
289
+ /**
290
+ * Whether to synthesize and show the managed cover slide from
291
+ * `doc.startBlock`. Defaults to true for existing documents.
292
+ */
293
+ showCoverSlide?: boolean;
283
294
  /** Caption display style (default: 'standard').
284
295
  * 'social' shows large centered words with the active word highlighted. */
285
296
  captionStyle?: CaptionStyle;
package/dist/index.js CHANGED
@@ -2712,9 +2712,16 @@ function DocControlsOverlay({
2712
2712
  // src/DocControlsSlideshow.tsx
2713
2713
  import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
2714
2714
  function DocControlsSlideshow({ state, slideNav }) {
2715
- const { currentBlockIndex, totalBlocks } = state;
2715
+ const {
2716
+ currentBlockIndex,
2717
+ currentSlideLabel,
2718
+ currentSlideNumber,
2719
+ totalBlocks,
2720
+ totalSlideNumber
2721
+ } = state;
2716
2722
  const isFirst = currentBlockIndex <= 0;
2717
2723
  const isLast = currentBlockIndex >= totalBlocks - 1;
2724
+ const counterText = totalBlocks > 0 ? currentSlideLabel ?? `${currentSlideNumber ?? currentBlockIndex + 1} / ${totalSlideNumber ?? totalBlocks}` : "\u2014";
2718
2725
  return /* @__PURE__ */ jsxs10(
2719
2726
  "div",
2720
2727
  {
@@ -2782,7 +2789,7 @@ function DocControlsSlideshow({ state, slideNav }) {
2782
2789
  padding: "0 4px",
2783
2790
  letterSpacing: "0.02em"
2784
2791
  },
2785
- children: totalBlocks > 0 ? `${currentBlockIndex + 1} / ${totalBlocks}` : "\u2014"
2792
+ children: counterText
2786
2793
  }
2787
2794
  ),
2788
2795
  /* @__PURE__ */ jsx15(
@@ -3641,6 +3648,7 @@ function DocPlayerContent({
3641
3648
  onBlockMarkers,
3642
3649
  forceViewport,
3643
3650
  displayMode = "video",
3651
+ showCoverSlide = true,
3644
3652
  theme,
3645
3653
  surface,
3646
3654
  captionStyle = "standard",
@@ -3732,6 +3740,7 @@ function DocPlayerContent({
3732
3740
  } = useDocPlayback(doc, currentTime, activeViewport, renderMode, effectiveTheme);
3733
3741
  const coverBlock = useMemo9(() => {
3734
3742
  const startBlockConfig = doc.startBlock;
3743
+ if (!showCoverSlide) return null;
3735
3744
  if (!startBlockConfig) return null;
3736
3745
  const context = createTemplateContext(effectiveTheme, 0, 1, activeViewport);
3737
3746
  const layers = expandCoverBlock(startBlockConfig, context);
@@ -3744,24 +3753,43 @@ function DocPlayerContent({
3744
3753
  audioSegment: -1,
3745
3754
  layers
3746
3755
  };
3747
- }, [doc.startBlock, activeViewport, effectiveTheme]);
3756
+ }, [doc.startBlock, activeViewport, effectiveTheme, showCoverSlide]);
3757
+ const hasManagedCover = !!coverBlock;
3758
+ const [slideshowCoverVisible, setSlideshowCoverVisible] = useState7(false);
3759
+ const slideshowCoverInitKeyRef = useRef7("");
3760
+ useEffect8(() => {
3761
+ const initKey = `${isSlideshowMode}:${hasManagedCover}:${renderMode}`;
3762
+ if (slideshowCoverInitKeyRef.current === initKey) return;
3763
+ slideshowCoverInitKeyRef.current = initKey;
3764
+ if (isSlideshowMode && hasManagedCover && !renderMode) {
3765
+ setSlideshowCoverVisible(true);
3766
+ pause();
3767
+ } else {
3768
+ setSlideshowCoverVisible(false);
3769
+ }
3770
+ }, [isSlideshowMode, hasManagedCover, renderMode, pause]);
3748
3771
  const [coverForced, setCoverForced] = useState7(false);
3749
3772
  const [coverGraceActive, setCoverGraceActive] = useState7(false);
3750
3773
  const coverGraceTimer = useRef7();
3751
3774
  const coverWasShowing = useRef7(false);
3752
3775
  const hasPlayedOnce = useRef7(false);
3753
- const atRest = !!(coverBlock && !isPlaying && currentTime === 0 && !hasPlayedOnce.current && !renderMode && !autoPlay);
3776
+ const atRest = !!(coverBlock && !isSlideshowMode && !isPlaying && currentTime === 0 && !hasPlayedOnce.current && !renderMode && !autoPlay);
3754
3777
  if (atRest) coverWasShowing.current = true;
3755
3778
  useEffect8(() => {
3756
- if (isPlaying && coverWasShowing.current && coverBlock && !renderMode) {
3779
+ if (isPlaying && coverWasShowing.current && coverBlock && !renderMode && !isSlideshowMode) {
3757
3780
  coverWasShowing.current = false;
3758
3781
  hasPlayedOnce.current = true;
3759
3782
  setCoverGraceActive(true);
3760
3783
  coverGraceTimer.current = setTimeout(() => setCoverGraceActive(false), 3e3);
3761
3784
  }
3762
- }, [isPlaying, coverBlock, renderMode]);
3785
+ }, [isPlaying, coverBlock, renderMode, isSlideshowMode]);
3763
3786
  useEffect8(() => () => clearTimeout(coverGraceTimer.current), []);
3764
- const showCoverBlock = !isSlideshowMode && !isLinearMode && coverBlock && (coverForced || coverGraceActive || !isPlaying && currentTime === 0 && !hasPlayedOnce.current && !renderMode && !autoPlay);
3787
+ const showVideoCoverBlock = !isSlideshowMode && !isLinearMode && !!coverBlock && (coverForced || coverGraceActive || !isPlaying && currentTime === 0 && !hasPlayedOnce.current && !renderMode && !autoPlay);
3788
+ const showSlideshowCover = !!(isSlideshowMode && !isLinearMode && !renderMode && coverBlock && slideshowCoverVisible);
3789
+ const showCoverBlock = showVideoCoverBlock || showSlideshowCover;
3790
+ const slideshowHasCover = !!(isSlideshowMode && !renderMode && coverBlock);
3791
+ const slideshowSlideIndex = slideshowHasCover ? slideshowCoverVisible ? 0 : currentBlockIndex + 1 : currentBlockIndex;
3792
+ const slideshowTotalSlides = slideshowHasCover ? expandedBlocks.length + 1 : expandedBlocks.length;
3765
3793
  const hasAutoPlayed = useRef7(false);
3766
3794
  useEffect8(() => {
3767
3795
  if (isAudioReady && autoPlay && !hasAutoPlayed.current) {
@@ -3938,8 +3966,8 @@ function DocPlayerContent({
3938
3966
  isPlaying,
3939
3967
  currentTime,
3940
3968
  totalDuration,
3941
- currentBlockIndex,
3942
- totalBlocks: expandedBlocks.length,
3969
+ currentBlockIndex: slideshowSlideIndex,
3970
+ totalBlocks: slideshowTotalSlides,
3943
3971
  docProgress,
3944
3972
  hasCaptions: !!hasCaptions,
3945
3973
  captionsEnabled,
@@ -3947,15 +3975,18 @@ function DocPlayerContent({
3947
3975
  isFullscreen,
3948
3976
  currentSegmentIndex: currentSegment,
3949
3977
  currentSegmentName: segmentTitleMap.get(currentSegment) ?? doc.audio.segments[currentSegment]?.name ?? null,
3950
- currentBlock: currentBlock ?? null
3978
+ currentBlock: showSlideshowCover ? coverBlock : currentBlock ?? null,
3979
+ currentSlideLabel: showSlideshowCover ? "Cover" : void 0,
3980
+ currentSlideNumber: slideshowHasCover && !showSlideshowCover ? currentBlockIndex + 1 : void 0,
3981
+ totalSlideNumber: slideshowHasCover ? expandedBlocks.length : void 0
3951
3982
  }),
3952
3983
  // eslint-disable-next-line react-hooks/exhaustive-deps -- doc.audio.segments is stable within a given doc
3953
3984
  [
3954
3985
  isPlaying,
3955
3986
  currentTime,
3956
3987
  totalDuration,
3957
- currentBlockIndex,
3958
- expandedBlocks.length,
3988
+ slideshowSlideIndex,
3989
+ slideshowTotalSlides,
3959
3990
  docProgress,
3960
3991
  hasCaptions,
3961
3992
  captionsEnabled,
@@ -3963,7 +3994,12 @@ function DocPlayerContent({
3963
3994
  isFullscreen,
3964
3995
  currentSegment,
3965
3996
  segmentTitleMap,
3966
- currentBlock
3997
+ currentBlock,
3998
+ currentBlockIndex,
3999
+ showSlideshowCover,
4000
+ coverBlock,
4001
+ slideshowHasCover,
4002
+ expandedBlocks.length
3967
4003
  ]
3968
4004
  );
3969
4005
  const playbackActions = useMemo9(
@@ -3980,24 +4016,56 @@ function DocPlayerContent({
3980
4016
  const slideNavActions = useMemo9(
3981
4017
  () => ({
3982
4018
  nextSlide: () => {
4019
+ if (slideshowHasCover && slideshowCoverVisible) {
4020
+ const target = expandedBlocks[0];
4021
+ if (target) {
4022
+ setSlideshowCoverVisible(false);
4023
+ seekTo(target.startTime);
4024
+ pause();
4025
+ }
4026
+ return;
4027
+ }
3983
4028
  if (currentBlockIndex < expandedBlocks.length - 1) {
3984
4029
  const target = expandedBlocks[currentBlockIndex + 1];
3985
4030
  if (target) {
4031
+ setSlideshowCoverVisible(false);
3986
4032
  seekTo(target.startTime);
3987
4033
  pause();
3988
4034
  }
3989
4035
  }
3990
4036
  },
3991
4037
  prevSlide: () => {
4038
+ if (slideshowHasCover && !slideshowCoverVisible && currentBlockIndex <= 0) {
4039
+ setSlideshowCoverVisible(true);
4040
+ seekTo(0);
4041
+ pause();
4042
+ return;
4043
+ }
3992
4044
  if (currentBlockIndex > 0) {
3993
4045
  const target = expandedBlocks[currentBlockIndex - 1];
3994
4046
  if (target) {
4047
+ setSlideshowCoverVisible(false);
3995
4048
  seekTo(target.startTime);
3996
4049
  pause();
3997
4050
  }
3998
4051
  }
3999
4052
  },
4000
4053
  goToSlide: (index) => {
4054
+ if (slideshowHasCover) {
4055
+ if (index === 0) {
4056
+ setSlideshowCoverVisible(true);
4057
+ seekTo(0);
4058
+ pause();
4059
+ return;
4060
+ }
4061
+ const target = expandedBlocks[index - 1];
4062
+ if (target) {
4063
+ setSlideshowCoverVisible(false);
4064
+ seekTo(target.startTime);
4065
+ pause();
4066
+ }
4067
+ return;
4068
+ }
4001
4069
  if (index >= 0 && index < expandedBlocks.length) {
4002
4070
  const target = expandedBlocks[index];
4003
4071
  if (target) {
@@ -4007,14 +4075,14 @@ function DocPlayerContent({
4007
4075
  }
4008
4076
  }
4009
4077
  }),
4010
- [currentBlockIndex, expandedBlocks, seekTo, pause]
4078
+ [currentBlockIndex, expandedBlocks, seekTo, pause, slideshowHasCover, slideshowCoverVisible]
4011
4079
  );
4012
4080
  const swipeEnabled = isSlideshowMode && !isLinearMode && !renderMode && enableSwipe;
4013
4081
  const swipe = useSlideSwipe({
4014
4082
  enabled: swipeEnabled,
4015
4083
  containerRef,
4016
- canGoNext: currentBlockIndex < expandedBlocks.length - 1,
4017
- canGoPrev: currentBlockIndex > 0,
4084
+ canGoNext: slideshowSlideIndex < slideshowTotalSlides - 1,
4085
+ canGoPrev: slideshowSlideIndex > 0,
4018
4086
  onNext: slideNavActions.nextSlide,
4019
4087
  onPrev: slideNavActions.prevSlide
4020
4088
  });
@@ -4068,7 +4136,7 @@ function DocPlayerContent({
4068
4136
  onBlockMarkers?.(blockMarkers);
4069
4137
  }
4070
4138
  }, [blockMarkers, onBlockMarkers]);
4071
- expandedBlocksLenRef.current = expandedBlocks.length;
4139
+ expandedBlocksLenRef.current = isSlideshowMode ? slideshowTotalSlides : expandedBlocks.length;
4072
4140
  const handleKeyDown = useCallback6(
4073
4141
  (e) => {
4074
4142
  const activeEl = document.activeElement;