import React from "react"; import type { ReactNode } from "react"; import { type SharedValue, type AnimatedRef } from "react-native-reanimated"; import type Animated from "react-native-reanimated"; import type { FlashListRef } from "@shopify/flash-list"; import type { DragConfig } from "../types"; /** * Centralized drag state for coordinating animations across list items. * All animation values are Reanimated SharedValues for 60fps UI thread performance. * * Architecture: * - Single source of truth for all drag state (no per-item local state) * - Dragged item identified by draggedIndex, reads/writes centralized values * - Non-dragged items read draggedIndex/currentTranslateY to calculate shift * - Scroll state enables viewport-aware hover calculations and autoscroll */ export interface DragStateContextValue { /** Is any item currently being dragged? */ isDragging: SharedValue; /** Original index of the item being dragged (-1 if not dragging) */ draggedIndex: SharedValue; /** ID of the item being dragged (for stable identity across FlashList recycling) */ draggedItemId: SharedValue; /** Current Y translation of the dragged item (for calculating hover position) */ currentTranslateY: SharedValue; /** Scale of the dragged item (1.0 = normal, configured = dragging) */ draggedScale: SharedValue; /** Current scroll offset of the list (updated via onScroll) */ scrollOffset: SharedValue; /** Scroll offset when drag started (for scroll delta calculation during autoscroll) */ dragStartScrollOffset: SharedValue; /** Total content height of the list (updated via onContentSizeChange) */ contentHeight: SharedValue; /** Visible viewport height (updated via onLayout) */ visibleHeight: SharedValue; /** Y position of FlashList top on screen (for autoscroll coordinate conversion) */ listTopY: SharedValue; /** X position of FlashList left on screen (for overlay positioning) */ listLeftX: SharedValue; /** Measured height of the dragged item (for dynamic height calculations) */ measuredItemHeight: SharedValue; /** Flag to freeze shift values during drop transition */ isDropping: SharedValue; /** Counter incremented on each drag start, used to force shift recalculation */ dragSequence: SharedValue; /** Expected index after drop (for handoff detection) */ expectedDropIndex: SharedValue; /** Frozen mismatch offset computed at drop time to prevent double compensation */ dropMismatchOffset: SharedValue; /** Signal incremented when FlashList commits a layout pass */ layoutCommitSignal: SharedValue; /** UI-thread-only signal incremented when native layout commit is detected */ uiLayoutCommitSignal: SharedValue; /** Layout commit signal value captured when drop starts (for guarding original fade-in) */ dropStartCommitSignal: SharedValue; /** Register the FlashList ref for autoscroll operations */ setListRef: (ref: FlashListRef | null) => void; /** Scroll the list to a specific offset (for autoscroll during drag) */ scrollToOffset: (offset: number, animated?: boolean) => void; /** Ask FlashList to prepare cells for layout animation on the next render */ prepareForLayoutAnimationRender: () => void; /** Notify drag system that FlashList committed a layout pass */ notifyLayoutCommit: () => void; /** Reset drag state after drop animation completes */ resetDragState: () => void; /** Current drag configuration */ config: DragConfig; /** * Index registry for tracking itemId -> index mapping. * Updated on every item render to handle FlashList recycling. * Stored on UI thread as SharedValue for worklet access. */ itemIndexRegistry: SharedValue>; /** Update an item's index in the registry (call from JS thread) */ updateItemIndex: (itemId: string, index: number) => void; /** Get an item's index from the registry */ getItemIndex: (itemId: string) => number | undefined; /** * Snapshot of itemIndexRegistry taken at drag start. * Used during drag to ensure consistent index lookup regardless of * React re-renders or FlashList recycling. */ dragStartIndexSnapshot: SharedValue>; /** * Capture a snapshot of the current itemIndexRegistry for use during drag. * Call this at the start of a drag operation. */ snapshotRegistryForDrag: () => void; /** * Update registry after reorder to handle FlashList not re-rendering. * Call this when reorder completes to keep indices accurate. */ applyReorderToRegistry: (fromId: string, fromIndex: number, toIndex: number) => void; /** Total number of items in the list (synced from data.length) */ totalItems: SharedValue; /** * Signal incremented after reorder callback completes and React has had * time to commit. useDragShift watches this to unfreeze shifted items. */ reorderCompleteSignal: SharedValue; /** Signal incremented when a drop is ready to reorder */ reorderRequestSignal: SharedValue; /** True while a reorder has been requested and layout commit is pending */ reorderInFlight: SharedValue; /** Layout commit version captured when reorder is requested */ dropCommitVersion: SharedValue; /** UI-thread layout commit version captured when reorder is requested */ dropCommitVersionUI: SharedValue; /** Current hovered index while dragging (UI-thread) */ hoveredIndex: SharedValue; /** True while a drag overlay should be shown */ overlayActive: SharedValue; /** Item id currently rendered in overlay */ overlayItemId: SharedValue; /** Overlay base X position (relative to list container) */ overlayBaseX: SharedValue; /** Overlay base Y position (relative to list container) */ overlayBaseY: SharedValue; /** Overlay width */ overlayWidth: SharedValue; /** Overlay height */ overlayHeight: SharedValue; /** Overlay translateY (finger translation) */ overlayTranslateY: SharedValue; /** Overlay ready flag (base position measured) */ overlayReady: SharedValue; /** Overlay visible flag (JS overlay rendered) */ overlayVisible: SharedValue; /** Global layout delta for drop commit timing */ layoutDeltaY: SharedValue; /** Overlay container X position on screen */ overlayContainerX: SharedValue; /** Overlay container Y position on screen */ overlayContainerY: SharedValue; /** Overlay container Y position from layout (measureInWindow value, for shifted overlay calculations) */ overlayContainerYLayout: SharedValue; /** Overlay container measured flag */ overlayContainerReady: SharedValue; /** Finger Y offset within the item at drag start (for absolute positioning) */ overlayTouchOffset: SharedValue; /** Current finger absoluteY during drag (for absolute positioning) */ overlayAbsoluteY: SharedValue; /** Animated ref for the drag container (for UI-thread measure()) */ dragContainerRef: AnimatedRef; /** Mark that a JS reorder callback just executed */ markReorderToken: () => void; /** Read the current reorder token (JS-only) */ getReorderToken: () => number; /** * Flag indicating the dragged item's settle animation has completed. * Used to know when it's safe to trigger reorder. */ draggedItemSettled: SharedValue; /** * Shifted item overlay positions captured at drop time. * Key is itemId, value is visual position info at capture time. * Used to render overlay copies that mask the FlashList repositioning glitch. */ shiftedOverlays: SharedValue>; /** * Whether shifted item overlays are currently active. * When true, real shifted items are hidden and overlays are shown. */ shiftedOverlaysActive: SharedValue; /** * v40.6: Whether shifted item overlays have actually rendered (JS thread confirmation). * Only hide real items when this is true to prevent flicker. */ shiftedOverlaysRendered: SharedValue; /** * Counter for atomic unmask - tracks how many items have captured overlays. * Overlays are only cleared when this reaches 0 (all items have snapped). */ pendingOverlayCount: SharedValue; /** * v40.3: Flag indicating reorder has been requested after settle. * Phase gate: cleanup requires BOTH reorderRequested=true AND pendingOverlayCount=0. * This prevents premature cleanup before reorder actually executes. */ reorderRequested: SharedValue; /** * Crossfade opacity for drag overlay (0..1). * Animated on UI thread to create smooth crossfade between overlay and original. * Original item uses (1 - dragOverlayOpacity) for perfect crossfade. */ dragOverlayOpacity: SharedValue; /** * Frozen item ID that keeps overlay renderable during fade-out. * Set when fade-out starts, cleared when fade completes. * This prevents overlay from unmounting before crossfade finishes. */ overlayFrozenItemId: SharedValue; /** * UI-thread signal that is set to true when the overlay has actually rendered. * Set from useAnimatedStyle in DragOverlay (UI thread), not from useEffect (JS thread). * This prevents the original from fading out before the overlay appears. */ overlayRenderedOnUI: SharedValue; } /** * Hook to access shared drag state from context. * Must be used within DragStateProvider. */ export declare const useDragState: () => DragStateContextValue; interface DragStateProviderProps { children: ReactNode; /** Optional drag configuration overrides */ config?: Partial; } export declare const DragStateProvider: React.FC; export {}; //# sourceMappingURL=DragStateContext.d.ts.map