import type { EngineContext } from '../../wire'; import type { default as Overlays } from '../overlays'; import type { StickyScrollStrategy } from '../strategies/stickyScrollStrategy'; /** * Assembles the ScrollSync's dependencies. Most come from the engine composition context; the ones * that drive the owning Overlays coordinator (`refreshAll`/`registerListeners`/`eventManager`/the * `destroyed` flag) and the sticky-scroll strategy (`tryActivate`/`syncOffsets`) come from the * Overlays instance and its already-built `StickyScrollStrategy` — passed as callbacks so ScrollSync * never imports either at runtime (only as a type), keeping the scroll slice free of an overlay cycle. * * @param {EngineContext} ctx The engine composition context. * @param {Overlays} overlays The owning Overlays coordinator. * @param {StickyScrollStrategy} stickyScroll The overlays' sticky-scroll strategy. * @returns {object} The ScrollSync dependency set. */ export declare function createScrollSyncDeps(ctx: EngineContext, overlays: Overlays, stickyScroll: StickyScrollStrategy): { wtSettings: import("../../settings").default; rootWindow: Window; geometryReader: import("../../domMeasure/geometryReader").GeometryReader; wtTable: import("../../table/baseTable").default; getWtViewport: () => import("../../viewport/viewport").default; getTopOverlay: () => import("..").Overlay; getInlineStartOverlay: () => import("..").Overlay; getBottomOverlay: () => import("..").Overlay; eventManager: import("../../../../../eventManager").default; getDestroyed: () => boolean; refreshAll: () => void; registerListeners: () => void; tryActivateStickyScroll: (verticalScrolling: boolean, horizontalScrolling: boolean) => void; syncStickyScrollOffsets: () => void; }; /** * The ScrollSync dependencies, inferred from `createScrollSyncDeps`. */ export type ScrollSyncDeps = ReturnType; /** * Owns the scroll state shared across the overlays and the master<->clone scroll synchronization: * which element scrolls the table (`scrollableElement`), the per-frame scroll-direction flags, the * last scroll offsets, and the callback-position cache that deduplicates the `onScroll*` hooks. * * It reacts to a scroll event by mirroring the master scroll position onto the overlay clone holders * (`syncScrollPositions`), pushes the master scroll position onto the clones after a rendering-state * change (`syncScrollWithMaster`), and recomputes the scrollable element + re-binds listeners when * the trimming container changes (`updateMainScrollableElements`). * * Extracted from the Overlays coordinator so the scroll-position lifecycle is self-contained; the * coordinator keeps thin public delegates and get/set accessors for the state that its own draw * participation and the whitebox tests rely on. * * @class ScrollSync */ export declare class ScrollSync { #private; /** * @param {ScrollSyncDeps} deps The ScrollSync dependencies. */ constructor(deps: ScrollSyncDeps); /** * The element that scrolls the table. * * @returns {HTMLElement | Window} */ get scrollableElement(): HTMLElement | Window; /** * Whether the scrollable element was resolved against a table that had no layout at that moment, * so the answer is provisional and has to be retaken once the table is rendered. * * @returns {boolean} */ get isScrollableElementProvisional(): boolean; /** * Whether a vertical scroll happened in the current frame. * * @returns {boolean} */ get verticalScrolling(): boolean; /** * @param {boolean} value Whether a vertical scroll happened in the current frame. */ set verticalScrolling(value: boolean); /** * Whether a horizontal scroll happened in the current frame. * * @returns {boolean} */ get horizontalScrolling(): boolean; /** * @param {boolean} value Whether a horizontal scroll happened in the current frame. */ set horizontalScrolling(value: boolean); /** * Records whether any overlay's rendering state changed in the current draw. Set from the * coordinator's `beforeDraw`; consumed by `syncScrollWithMaster`. * * @param {boolean} value Whether any overlay's rendering state changed. */ setRenderingStateChanged(value: boolean): void; /** * Caches the initial vertical and horizontal scroll positions for callback deduplication. */ cacheScrollCallbackPositions(): void; /** * Synchronize scroll position between master table and overlay table. */ syncScrollPositions(): void; /** * Fires the `onScroll*` overlay hooks when the scroll position changed since they last fired, then * resets the per-frame scroll-direction flags. Called by the coordinator from `refreshAll`. */ fireScrollCallbacksAndReset(): void; /** * Synchronize overlay scrollbars with the master scrollbar. */ syncScrollWithMaster(): void; /** * Drops the sizes measured before the layout settled, if `resolveProvisionalLayout()` found any. * * Called from `Overlays#beforeDraw`, so the draw that follows re-measures the row heights it just * invalidated and resizes the elements from the results. Doing it the other way round – dropping * the sizes and then asking for a redraw – leaves the row heights dropped for good whenever that * redraw renders no cells. * * "Sizes" is the engine's own record of them: the oversized-row heights and the column-width * prefix sum. A rebuilt width cache re-asks `wtTable.getColumnWidth`, so it re-enters * `modifyColWidth` and `AutoColumnSize` answers from its own map – a width that plugin measured * while the table had no layout is not dropped by this and outlives the settle. That gap is the * narrow-container `AutoColumnSize` follow-up, filed separately. * * The mark is not spent here, because a draw that got this far can still render nothing: a * `beforeDraw` hook that sets `skipRender` (NestedRows does this, and so can any user hook) cancels * the cell render, and then `markOversizedRows` never runs to take the heights again. It is spent * by `confirmSizesRemeasured()`, from the `afterDraw` of a draw that did render the band. The drop * is idempotent, so repeating it on the next draw costs one invalidation. */ resetSizesMeasuredBeforeLayoutSettled(): void; /** * Spends the mark left by `resolveProvisionalLayout()`, once a draw has rendered the cell band and * therefore re-measured the sizes that `resetSizesMeasuredBeforeLayoutSettled()` dropped on its way * in. Called from `Overlays#afterDraw`. * * A draw that rendered the cells without having dropped anything spends nothing: the two gates read * different values of the same fast/full question (the reset gate reads it at draw entry, the render * gate after `createCalculators` could downgrade it), so an escalated scroll draw satisfies the * second without ever passing the first. */ confirmSizesRemeasured(): void; /** * Settles the layout decisions and measurements of a table that was constructed while it had no * layout – most often a light-DOM child of a shadow host whose `` renders later, or a subtree * assembled before it was appended to the document. Such a table reads every ancestor style as an * empty declaration and measures every size against nothing, so two things are wrong at once: * the scrollable element resolves to the window, and the row heights and column widths describe a * layout the table never had. * * Runs from the `afterDraw` of a full draw, so the overlays have already refreshed their trimming * containers and the holder has its final overflow; in `beforeDraw`, and on a fast draw that never * aligned the overlays at all, both are still stale and the scrollable element would settle on the * window again. While the answer is still the window even though an element * trims the table, the layout has not settled yet and the pass is retried on the next draw – but * only while the answer keeps changing. `getTrimmingContainer` counts `overflow: hidden` and * `getScrollableElement` does not, so the two can disagree permanently, and a table in an iframe * driven from the parent realm does exactly that: `MasterTable#alignOverlaysWithTrimmingContainer` * misses it with a realm-bound `instanceof` and leaves the holder `overflow: visible`. Retrying * such a table forever would rebind every listener on every draw. * * Once it does settle, the sizes measured before it are marked for dropping, which the next draw * does on its way in (`resetSizesMeasuredBeforeLayoutSettled`). Left in place they survive until * something else redraws the grid, which is what made it fill short of its container and look like * it needed a click to finish loading (DEV-2515). */ resolveProvisionalLayout(): void; /** * Update the main scrollable elements for all the overlays. */ updateMainScrollableElements(): void; }