@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 +11 -0
- package/dist/index.js +85 -17
- package/dist/index.js.map +1 -1
- package/dist/squisq-player.global.js +34 -34
- package/dist/squisq-player.global.js.map +1 -1
- package/dist/standalone-source.js +1 -1
- package/package.json +2 -2
- package/src/DocControlsSlideshow.tsx +13 -2
- package/src/DocPlayer.tsx +98 -15
- package/src/__tests__/DocPlayer.test.tsx +51 -2
- package/src/types.ts +6 -0
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 {
|
|
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:
|
|
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
|
|
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:
|
|
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
|
-
|
|
3958
|
-
|
|
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:
|
|
4017
|
-
canGoPrev:
|
|
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;
|