import type { TimelineItem, TimelineStackingOptions } from '../types/timeline.ts';
/** A single group's stacking options after defaults are applied. */
export interface EffectiveStackingOptions {
    enabled: boolean;
    strategy: TimelineStackingOptions['strategy'];
    compare?: (a: TimelineItem, b: TimelineItem) => number;
    collisionWidth: number;
    maxLanes: number;
}
/** Stacking information for a single item in a group. */
export interface LaneAssignment {
    /** 0-based lane (vertical position) within the group. */
    lane: number;
    /** Number of lanes in this item's overlap cluster. */
    stackSize: number;
    /** Whether this item shares its cluster with at least one other lane. */
    isStacked: boolean;
}
/** Stacking information for a group. */
export interface GroupStackingResult {
    /** Stacking information for each item in the group. */
    laneAssignmentsByItem: Map<TimelineItem['id'], LaneAssignment>;
    /** Number of lanes used by the group (drives the group height). */
    laneCount: number;
}
/** Merge component options, group options and defaults. */
export declare function mergeStackingOptions(componentOptions: TimelineStackingOptions | undefined, groupOptions: TimelineStackingOptions | undefined): EffectiveStackingOptions;
/** Whether an item is stackable. */
export declare function isStackable(item: TimelineItem): boolean;
/**
 * Greedy first-fit lane assignment in processing order (start time, or `compare`).
 * Half-open `[start, end)` spans are widened to at least `minSpanMs`. When
 * `maxLanes` is full and no lane fits, the item goes in the lane that frees up earliest.
 */
export declare function assignLanes(items: TimelineItem[], options?: {
    compare?: (a: TimelineItem, b: TimelineItem) => number;
    minSpanMs?: number;
    maxLanes?: number;
}): GroupStackingResult;
