diff --git a/src/uix/soma/components/carousel/carousel-provider.svelte.ts b/src/uix/soma/components/carousel/carousel-provider.svelte.ts index ee6da174b..e64fc5b06 100644 --- a/src/uix/soma/components/carousel/carousel-provider.svelte.ts +++ b/src/uix/soma/components/carousel/carousel-provider.svelte.ts @@ -201,17 +201,26 @@ export class CarouselProvider { // ── Geometry ───────────────────────────────────────────────────────────── /** - * Size (px) of the viewport along the primary axis. Sourced from the - * `viewportClient{Width,Height}` reactive mirrors (populated by the - * ResizeObserver above) so that layout-only changes — like flipping - * orientation, which rewrites the viewport's block-size via the eidos - * recipe — propagate to translate calc on the next reactive tick. + * Size (px) of the viewport along the primary axis. + * + * Two-tier read: the ResizeObserver mirrors (`viewportClient{Width, + * Height}`) are the steady-state source — they pick up layout reshape + * (orientation flip, container resize, font scaling) on the next + * frame. BUT the observer is async, so on first paint — or on the very + * first user interaction after mount — those mirrors may still be `0`. + * Falling back to the live `clientWidth/Height` reads synchronously + * from the DOM so the first click translates to a real pixel offset + * instead of `value * 0 = 0` (the bug that made early clicks look like + * dead-no-ops while the index actually advanced). */ - readonly viewportSize = $derived.by(() => - this.opts.orientation.current === 'horizontal' - ? this.viewportClientWidth - : this.viewportClientHeight - ); + readonly viewportSize = $derived.by(() => { + const horizontal = this.opts.orientation.current === 'horizontal'; + const tracked = horizontal ? this.viewportClientWidth : this.viewportClientHeight; + if (tracked > 0) return tracked; + const vp = this.viewportRef; + if (!vp) return 0; + return horizontal ? vp.clientWidth : vp.clientHeight; + }); /** Slide size (px) along the primary axis = viewport / slidesPerView. */ readonly slideSize = $derived.by(() => {