SheetXL - v0.8.0-beta.9+sites.210.e2d420901
    Preparing search index...

    Interface IViewport

    A drivable viewport: the read ViewportStore plus the write methods the grid and ScrollPane call. Implemented by Viewport (a single store) and AxisViewport (a per-axis composition of two controllers). This is the single object type that flows between a ScrollPane and its content — pass the SAME instance to both and they stay in sync through it.

    interface IViewport {
        getClient(): Size;
        getMetrics(): ViewportMetrics;
        getScroll(): TopLeft;
        getSnapshot(): TopLeft;
        getTarget(): TopLeft;
        getZoom(): number;
        isReady(): boolean;
        isSettled(): boolean;
        observe(el: Element | null): () => void;
        requestZoom(step: ViewportZoomStep): void;
        setBounds(bounds: ClampBounds): void;
        setContent(
            totalWidth: number,
            totalHeight: number,
            minLeft?: number,
            minTop?: number,
        ): void;
        setSizes(
            width: number,
            height: number,
            totalWidth: number,
            totalHeight: number,
        ): void;
        setTarget(left: number, top: number, animate?: boolean): boolean;
        setZoom(zoom: number, left?: number, top?: number): void;
        subscribe(listener: () => void): () => void;
        subscribeZoom(listener: (step: ViewportZoomStep) => void): () => void;
    }

    Hierarchy (View Summary)

    Implemented by

    Index
    • The raw cell-area client size = the measured client (uncapped by content). The grid reads this for its own pane layout (min(client, content)); getMetrics caps it at content.

      Returns Size

    • Convenience { left, top } of the current (rendered) scroll.

      Returns TopLeft

    • The current (rendered) scroll snapshot. The returned object is identity-stable until the scroll changes, so it is safe as a useSyncExternalStore snapshot.

      Returns TopLeft

    • The scroll TARGET the ticker is easing toward (equals current when settled).

      Returns TopLeft

    • The zoom factor (1 = none). Part of the viewport shape so a shared/synced viewport carries it.

      Returns number

    • Whether the viewport has everything it needs to clamp + emit: a measured client (observer fired or manual sizes pushed) AND real content AND a positive client. The shared readiness signal that replaces each grid's "pending until ready" gate.

      Returns boolean

    • Whether the current (rendered) position has reached the target — no easing in progress.

      Returns boolean

    • START measuring: attach a ResizeObserver to el (the scroll-client box) so the viewport owns its own client-size measurement and derives its clamp bounds internally. Returns an unobserve fn — symmetric with subscribe/unsubscribe, and the ONLY teardown the viewport has (there is no dispose; the rAF ticker is self-terminating and listeners each remove themselves).

      Parameters

      • el: Element | null

      Returns () => void

      Each call is SELF-CONTAINED (its own observer, its own detach), so multiple elements can observe the same viewport concurrently — e.g. split peers each reporting the shared axis (they report the same value by construction; last write wins). A caller tears down exactly what it set up, nothing else — StrictMode mount→cleanup→mount is naturally symmetric. Guarded for absence exactly like the rAF ticker: with no ResizeObserver (SSR / non-DOM tests) it resolves an immediate default client so isReady still becomes true. null is a no-op (returns a no-op detach).

    • Relay a zoom-gesture step to the zoom's owner. The ScrollPane that runs the gesture calls this (as it calls setTarget for a scroll); the viewport does NOT apply it — zoom is a whole percent owned by a model the viewport knows nothing about — it hands the step to subscribeZoom listeners, who commit it and push the result back in through setZoom.

      Parameters

      Returns void

    • Set the clamp bounds (structural — total size, viewport size, frozen floors). Re-clamps the current target into the new bounds (e.g. the viewport shrank) and eases to it. Pushed by the grid; the controller, not the grid, owns the clamp.

      Parameters

      Returns void

    • Declare the content geometry (the host — a grid — pushes this): the total scroll extent plus the frozen-pane floors (min*, the same minLeft/minTop a manual setBounds carries). Calling it switches the viewport into DERIVED-bounds mode — it computes its own bounds from content − client and no longer needs the host to push setBounds. Emits + re-derives.

      Parameters

      • totalWidth: number
      • totalHeight: number
      • OptionalminLeft: number
      • OptionalminTop: number

      Returns void

    • Push the measured viewport sizes (the grid measures them where it pushes setBounds; a subscribed ScrollPane reads them via getViewport to size its scrollbar thumbs). Emits on change.

      Parameters

      • width: number
      • height: number
      • totalWidth: number
      • totalHeight: number

      Returns void

      This is the MANUAL input path — used by a standalone ScrollPane driving arbitrary content (no grid to declare setContent). Calling it marks the viewport "manual provenance": the manually pushed sizes/bounds win over anything observe/setContent would derive.

    • Set the scroll TARGET (clamped) and start the ticker if needed.

      Parameters

      • left: number
      • top: number
      • Optionalanimate: boolean

        Animation is a property of the REQUEST, not a global policy: true glides to the target (fixed ~SCROLL_ANIMATION_MS ease-out, long jumps clamped to animate only the arrival — a wheel notch, PageDown, or goto). Omit/false for position control (a thumb drag, the touch scroller's per-frame writes, a model restore) — the classic immediate scroll.

      Returns boolean

      true if the target changed (caller fires its immediate-scroll side effects), else false (a no-op move — caller bails).

    • Set the zoom factor and notify subscribers on a change. Zoom is structural (it changes every pane's geometry), so the grid re-renders when this emits. The scroll position (current + target) is rescaled by the zoom ratio so the same cell stays anchored at the top-left and so scroll / zoom (the zoom-independent base position) is preserved. Because zoom and scroll are mutated together before the single emit, a listener that reads scroll on this emit sees screen px already consistent with the new zoom.

      With left/top (screen px for the NEW zoom) the position is set to them instead of the ratio-rescale, current and target alike, in the same single emit — a focal-point zoom lands zoom and scroll together, with no frame painted at the top-left-anchored position in between.

      Parameters

      • zoom: number
      • Optionalleft: number
      • Optionaltop: number

      Returns void

    • Subscribe to scroll changes. Driven by the rAF ticker, so the listener fires at most once per animation frame (and only while current is advancing toward target). Returns a remover.

      Parameters

      • listener: () => void

      Returns () => void