export interface Rect { x: number; y: number; width: number; height: number; } /** A card's identity plus its provider-relative rect, used for insertion math. */ export interface CardRect { id: string; rect: Rect; } /** True if (px, py) lies inside `r` (left/top inclusive, right/bottom exclusive). */ export declare function withinRect(px: number, py: number, r: Rect): boolean; /** * The id of the top-most zone whose rect contains the point, or null when the point is over no * zone. `order` lists zone ids in registration order; a later-registered zone paints over an * earlier one, so we scan it in reverse and return the first hit. Zones missing from `rects` * (not yet measured) are skipped rather than throwing. */ export declare function hitTestZone(px: number, py: number, rects: ReadonlyMap, order: readonly string[]): string | null; /** * The insertion index for the pointer within a zone. `cards` are the zone's draggable rects in * DATA order (what `sortByMainAxis` returns), EXCLUDING the card being dragged. The index is the * count of cards the pointer has passed the midpoint of along the reading direction: down the Y * axis for a vertical list, and along the X axis for a horizontal one — rightward in LTR, * LEFTWARD in RTL. It runs 0..cards.length: 0 drops before the first card, cards.length after * the last. */ export declare function insertionIndexFor(px: number, py: number, cards: readonly Rect[], horizontal: boolean, rtl: boolean): number; /** * The offset at which to paint the insertion indicator line, given the sorted card rects * (provider-relative, dragged card excluded), the chosen index, the zone's own provider-relative * rect, and a small visual gap. Placing the line at the boundary between card[index-1] and * card[index] keeps it centered in the gutter. * * The offset is measured along the READING axis from the zone's LEADING edge: its top edge for a * vertical list, its left edge for an LTR row, and its RIGHT edge for an RTL row. That is a * LOGICAL inset, so the shell anchors the line with one style (`top` / `insetInlineStart`) that * every platform resolves to the correct physical side, with no branch. It also means a row and * its mirror image produce the same numbers. */ export declare function insertionOffset(cards: readonly Rect[], index: number, zone: Rect, horizontal: boolean, rtl: boolean, gap: number): number; /** * Sort card rects into DATA order along the main axis (a copy; input is not mutated): by Y for a * vertical list, and by X for a horizontal one — ascending in LTR, DESCENDING in RTL, because a * mirrored row puts data index 0 at the largest X. */ export declare function sortByMainAxis(cards: readonly CardRect[], horizontal: boolean, rtl: boolean): CardRect[]; /** * The zone ids in READING order: row by row down the surface, and along the inline axis within a * row — left to right in LTR, RIGHT TO LEFT in RTL — read off the measured rects rather than off * the order the zones happened to register in. Rows always run top to bottom: the block axis * never mirrors, so `rtl` reverses the within-row sweep and nothing else. * * Registration order is MOUNT order, and it never changes again: a zone that moves on screen * (a reordered dashboard cell, a lane a consumer moved) keeps its original slot, because React * reuses the keyed element instead of remounting it. Anything that walks zones the way a user * sees them (the keyboard cursor) must therefore ask the geometry, which the measurement pass * already captured, not the registry. * * Rows are swept, not bucketed by a tolerance: a zone joins the row being built while its top * edge is above the row's running bottom, which is exactly "these boxes share a band of the * screen" and needs no guess about how tall a row is. A wrapped line always starts below the * tallest box of the line above, so it clears the band and opens a new row; lanes of wildly * different heights still read as one row. * * Ids with no rect yet (a zone that mounted after the measure, or measured non-finite) keep * their given relative order and land at the end, and rects that are all zeros (nothing has * been laid out) leave the given order untouched, because every comparison ties and both sorts * are stable. So the worst case degrades to the input order rather than to a scramble. */ export declare function zonesInReadingOrder(order: readonly string[], rects: ReadonlyMap, rtl: boolean): string[]; export interface KeyboardCursor { zoneId: string; index: number; } export interface ZoneCount { id: string; count: number; } export type KeyboardMove = "prevZone" | "nextZone" | "prevIndex" | "nextIndex"; /** * Advance the keyboard drag cursor by one step, clamping at the ends. Moving between zones * clamps the carried index into the destination zone's range; moving the index walks 0..count * within the current zone. Unknown zone ids resolve to the first zone (defensive). */ export declare function keyboardMove(cursor: KeyboardCursor, move: KeyboardMove, zones: readonly ZoneCount[]): KeyboardCursor; //# sourceMappingURL=drag-drop.geometry.d.ts.map