diff --git a/packages/runtime/actor/setup.ts b/packages/runtime/actor/setup.ts index a1967c0..89a2318 100644 --- a/packages/runtime/actor/setup.ts +++ b/packages/runtime/actor/setup.ts @@ -29,17 +29,24 @@ export const machineBase = setup({ * Smooth-scroll the audience-mode viewport to the current slide. * Used as a side effect of navigation events (toolbar buttons, * keyboard, broadcast from the presenter tab) so the audience - * sees a clean animation between slides. No-op in presenter mode - * (no scrolling there) and on empty decks. + * sees a clean animation between slides. + * + * Scrolls the `` container directly via + * scrollTo rather than slide.scrollIntoView. The slide-snap + * container's `scroll-snap-type: y mandatory` can race with + * scrollIntoView's smooth animation in some browsers, snapping + * instantly; calling scrollTo with an explicit offset gives the + * smooth path a direct, snap-friendly target. */ scrollToSlide({ context }) { if (context.role !== "audience") return; if (context.slides.length === 0) return; const slide = context.slides[context.currentIndex]; if (!slide) return; - document.querySelector(`#${slide.id}`)?.scrollIntoView({ - behavior: "smooth", - }); + const host = document.querySelector("morkdeck-presentation"); + const target = document.getElementById(slide.id); + if (!host || !target) return; + host.scrollTo({ top: target.offsetTop, behavior: "smooth" }); }, /** @@ -52,9 +59,10 @@ export const machineBase = setup({ if (context.slides.length === 0) return; const slide = context.slides[context.currentIndex]; if (!slide) return; - document.querySelector(`#${slide.id}`)?.scrollIntoView({ - behavior: "instant", - }); + const host = document.querySelector("morkdeck-presentation"); + const target = document.getElementById(slide.id); + if (!host || !target) return; + host.scrollTo({ top: target.offsetTop, behavior: "instant" }); }, updateUrl({ context }) { const url = new URL(document.URL);