/** * Coordinates every mounted `Sticky` so ones that overlap horizontally stack * underneath each other (in DOM order) instead of pinning to the same spot. * Non-overlapping ones (e.g. side-by-side halves under a full-width one) land * at the same top instead of being pushed down by each other. */ export interface StickyStackMetrics { /** Current (unstuck-flow) top of the root element, from getBoundingClientRect. */ top: number; left: number; width: number; contentHeight: number; /** The element this entry sticks relative to (its scroll parent), or null for the viewport. * Stacking only considers overlap between entries sharing the same container — two Stickies * in unrelated scroll panels should never push each other down just because they happen to * share horizontal DOM coordinates. */ container: HTMLElement | null; /** The element the entry is confined to, or null when nothing confines it. * Entries sharing one leave together. */ boundary: HTMLElement | null; /** Bottom edge of that element (less its inset), in the same coordinate space as `top`. */ boundaryBottom: number | null; } export interface StickyStackEntry { node: HTMLElement; offsetTop: number; disabled: boolean; getMetrics: () => StickyStackMetrics | null; } export interface StickyStackResult { isStuck: boolean; /** Effective `top` to pin at while stuck — offsetTop plus the height of any stuck, overlapping entries above it. */ top: number; } type ResultListener = (result: StickyStackResult) => void; declare class StickyStack { private entries; private listeners; private results; private rafId; private listenerCount; schedule: () => void; register(entry: StickyStackEntry, onChange: ResultListener): symbol; updateEntry(id: symbol, patch: Partial>): void; unregister(id: symbol): void; recompute: () => void; private startListening; private stopListening; } export declare const stickyStack: StickyStack; export {};