diff --git a/packages/office-render/src/presentation/cursor-canvas-runtime.tsx b/packages/office-render/src/presentation/cursor-canvas-runtime.tsx index f65b6bdb4..ecf49826b 100644 --- a/packages/office-render/src/presentation/cursor-canvas-runtime.tsx +++ b/packages/office-render/src/presentation/cursor-canvas-runtime.tsx @@ -64,7 +64,10 @@ export function PresentationCursorCanvas({ 0, slides.findIndex((slide) => asNumber(slide.index, 1) === selectedIndex), ); - const selectedSlide = slides[selectedPosition] ?? slides[0] ?? {}; + const selectedSlide = useMemo( + () => slides[selectedPosition] ?? slides[0] ?? {}, + [slides, selectedPosition], + ); const selectedSlideIndex = asNumber(selectedSlide.index, selectedPosition + 1); const title = asString(artifact.title) || "Presentation"; @@ -77,7 +80,11 @@ export function PresentationCursorCanvas({ if (slides.some((slide) => asNumber(slide.index, 1) === selectedIndex)) { return; } - setSelectedIndex(asNumber(slides[0]?.index, 1)); + const firstIndex = asNumber(slides[0]?.index, 1); + if (firstIndex !== selectedIndex) { + // eslint-disable-next-line react-hooks/set-state-in-effect -- sync when slide set changes and current index is stale + setSelectedIndex(firstIndex); + } }, [selectedIndex, slides]); const goPrevious = useCallback(() => { @@ -151,6 +158,7 @@ export function PresentationCursorCanvas({ > {slideIndex} {thumbnail ? ( + // eslint-disable-next-line @next/next/no-img-element -- office thumbnail, not a Next.js route image (); const entries = Object.entries(media); if (entries.length === 0) { - setImages(next); + // eslint-disable-next-line react-hooks/set-state-in-effect -- sync when media set is empty + if (!cancelled) setImages(next); return; } diff --git a/packages/office-render/src/presentation/presentation-preview.tsx b/packages/office-render/src/presentation/presentation-preview.tsx index 6bbe8304d..82d631fbb 100644 --- a/packages/office-render/src/presentation/presentation-preview.tsx +++ b/packages/office-render/src/presentation/presentation-preview.tsx @@ -385,7 +385,7 @@ function SlideshowOverlay({ const frameSize = useElementSize(frameRef); const didEnterFullscreenRef = useRef(typeof document !== "undefined" && document.fullscreenElement != null); const selectedIndex = Math.min(activeSlideIndex, Math.max(0, slides.length - 1)); - const slide = slides[selectedIndex] ?? {}; + const slide = useMemo(() => slides[selectedIndex] ?? {}, [slides, selectedIndex]); const frame = getSlideFrameSize(slide, layouts); const fit = computePresentationFit(frameSize, frame, { padding: 0 }); const canvasWidth = Math.max(1, fit.width); @@ -396,11 +396,8 @@ function SlideshowOverlay({ const showSpeakerNotesLabel = labels.showSpeakerNotes ?? speakerNotesLabel; const hideSpeakerNotesLabel = labels.hideSpeakerNotes ?? speakerNotesLabel; - useEffect(() => { - if (!hasSpeakerNotes) { - setShowSpeakerNotes(false); - } - }, [hasSpeakerNotes]); + // When there are no speaker notes, the panel cannot be shown. + const canShowSpeakerNotes = hasSpeakerNotes && showSpeakerNotes; const goPrevious = useCallback(() => { setActiveSlideIndex(Math.max(0, selectedIndex - 1)); @@ -508,7 +505,7 @@ function SlideshowOverlay({ {hasSpeakerNotes ? ( -
+
- {showSpeakerNotes && hasSpeakerNotes ? ( + {canShowSpeakerNotes ? (