@dreamstack-us/section-flow 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,866 @@
1
+ import React$1 from 'react';
2
+ import { ScrollViewProps, StyleProp, ViewStyle, Animated, View, LayoutChangeEvent, NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
3
+
4
+ /**
5
+ * Core Types
6
+ */
7
+ interface LayoutRect {
8
+ x: number;
9
+ y: number;
10
+ width: number;
11
+ height: number;
12
+ }
13
+ interface Section<TItem> {
14
+ key: string;
15
+ title?: string;
16
+ data: TItem[];
17
+ }
18
+ /**
19
+ * Flattened item types for internal processing
20
+ */
21
+ type FlattenedItemType = "section-header" | "item" | "section-footer";
22
+ interface FlattenedItem<TItem> {
23
+ type: FlattenedItemType;
24
+ key: string;
25
+ sectionKey: string;
26
+ sectionIndex: number;
27
+ itemIndex: number;
28
+ item: TItem | null;
29
+ section: Section<TItem>;
30
+ }
31
+ /**
32
+ * Render info passed to render functions
33
+ */
34
+ interface RenderItemInfo<TItem> {
35
+ item: TItem;
36
+ index: number;
37
+ section: Section<TItem>;
38
+ sectionIndex: number;
39
+ }
40
+ interface RenderSectionHeaderInfo<TItem> {
41
+ section: Section<TItem>;
42
+ sectionIndex: number;
43
+ }
44
+ interface RenderSectionFooterInfo<TItem> {
45
+ section: Section<TItem>;
46
+ sectionIndex: number;
47
+ }
48
+ /**
49
+ * Viewability types
50
+ */
51
+ interface ViewToken<TItem> {
52
+ item: TItem | null;
53
+ key: string;
54
+ index: number;
55
+ isViewable: boolean;
56
+ section: Section<TItem>;
57
+ }
58
+ interface ViewabilityConfig {
59
+ minimumViewTime?: number;
60
+ viewAreaCoveragePercentThreshold?: number;
61
+ itemVisiblePercentThreshold?: number;
62
+ waitForInteraction?: boolean;
63
+ }
64
+ interface ViewabilityConfigCallbackPair<TItem> {
65
+ viewabilityConfig: ViewabilityConfig;
66
+ onViewableItemsChanged: (info: {
67
+ viewableItems: ViewToken<TItem>[]
68
+ changed: ViewToken<TItem>[]
69
+ }) => void;
70
+ }
71
+ /**
72
+ * Cell recycling types
73
+ */
74
+ interface RecycledCell {
75
+ key: string;
76
+ itemType: string;
77
+ flatIndex: number;
78
+ }
79
+ interface RecyclePool {
80
+ type: string;
81
+ cells: RecycledCell[];
82
+ maxSize: number;
83
+ }
84
+ /**
85
+ * Section layout types
86
+ */
87
+ interface SectionLayoutInfo {
88
+ sectionKey: string;
89
+ sectionIndex: number;
90
+ headerLayout: LayoutRect;
91
+ footerLayout: LayoutRect | null;
92
+ itemsStartOffset: number;
93
+ itemsEndOffset: number;
94
+ itemCount: number;
95
+ isCollapsed: boolean;
96
+ }
97
+ /**
98
+ * Scroll types
99
+ */
100
+ interface ScrollToSectionOptions {
101
+ sectionKey?: string;
102
+ sectionIndex?: number;
103
+ animated?: boolean;
104
+ viewPosition?: number;
105
+ }
106
+ interface ScrollToItemOptions {
107
+ sectionKey?: string;
108
+ sectionIndex?: number;
109
+ itemIndex: number;
110
+ animated?: boolean;
111
+ viewPosition?: number;
112
+ }
113
+ /**
114
+ * Main component props
115
+ */
116
+ interface SectionFlowProps<TItem> extends Omit<ScrollViewProps, "children"> {
117
+ sections: Section<TItem>[];
118
+ renderItem: (info: RenderItemInfo<TItem>) => React.ReactElement | null;
119
+ renderSectionHeader?: (info: RenderSectionHeaderInfo<TItem>) => React.ReactElement | null;
120
+ renderSectionFooter?: (info: RenderSectionFooterInfo<TItem>) => React.ReactElement | null;
121
+ keyExtractor?: (item: TItem, index: number) => string;
122
+ getItemType?: (item: TItem, index: number, section: Section<TItem>) => string;
123
+ estimatedItemSize?: number;
124
+ estimatedSectionHeaderSize?: number;
125
+ estimatedSectionFooterSize?: number;
126
+ horizontal?: boolean;
127
+ stickySectionHeadersEnabled?: boolean;
128
+ stickyHeaderStyle?: StyleProp<ViewStyle>;
129
+ collapsible?: boolean;
130
+ defaultCollapsed?: string[];
131
+ onSectionToggle?: (sectionKey: string, collapsed: boolean) => void;
132
+ maxItemsInRecyclePool?: number;
133
+ drawDistance?: number;
134
+ viewabilityConfig?: ViewabilityConfig;
135
+ onViewableItemsChanged?: (info: {
136
+ viewableItems: ViewToken<TItem>[]
137
+ changed: ViewToken<TItem>[]
138
+ }) => void;
139
+ viewabilityConfigCallbackPairs?: ViewabilityConfigCallbackPair<TItem>[];
140
+ onEndReached?: (info: {
141
+ distanceFromEnd: number
142
+ }) => void;
143
+ onEndReachedThreshold?: number;
144
+ onScrollBeginDrag?: ScrollViewProps["onScrollBeginDrag"];
145
+ onScrollEndDrag?: ScrollViewProps["onScrollEndDrag"];
146
+ onMomentumScrollBegin?: ScrollViewProps["onMomentumScrollBegin"];
147
+ onMomentumScrollEnd?: ScrollViewProps["onMomentumScrollEnd"];
148
+ style?: StyleProp<ViewStyle>;
149
+ contentContainerStyle?: StyleProp<ViewStyle>;
150
+ ListHeaderComponent?: React.ComponentType | React.ReactElement | null;
151
+ ListFooterComponent?: React.ComponentType | React.ReactElement | null;
152
+ ListEmptyComponent?: React.ComponentType | React.ReactElement | null;
153
+ ItemSeparatorComponent?: React.ComponentType<{
154
+ section: Section<TItem>
155
+ leadingItem: TItem
156
+ }> | null;
157
+ SectionSeparatorComponent?: React.ComponentType<{
158
+ section: Section<TItem>
159
+ leadingSection: Section<TItem> | null
160
+ trailingSection: Section<TItem> | null
161
+ }> | null;
162
+ refreshing?: boolean;
163
+ onRefresh?: () => void;
164
+ extraData?: unknown;
165
+ debug?: boolean;
166
+ }
167
+ /**
168
+ * Ref methods
169
+ */
170
+ interface SectionFlowRef<TItem = unknown> {
171
+ scrollToSection: (options: ScrollToSectionOptions) => void;
172
+ scrollToItem: (options: ScrollToItemOptions) => void;
173
+ scrollToOffset: (options: {
174
+ offset: number
175
+ animated?: boolean
176
+ }) => void;
177
+ scrollToEnd: (options?: {
178
+ animated?: boolean
179
+ }) => void;
180
+ toggleSection: (sectionKey: string) => void;
181
+ getSectionLayouts: () => SectionLayoutInfo[];
182
+ getVisibleItems: () => ViewToken<TItem>[];
183
+ recordInteraction: () => void;
184
+ flashScrollIndicators: () => void;
185
+ }
186
+ /**
187
+ * Layout positioner interface (for future layout strategies)
188
+ */
189
+ interface LayoutPositioner {
190
+ getLayoutForIndex(index: number): LayoutRect;
191
+ getContentSize(): {
192
+ width: number
193
+ height: number
194
+ };
195
+ getVisibleRange(scrollOffset: number, viewportSize: number, overscan: number): {
196
+ startIndex: number
197
+ endIndex: number
198
+ };
199
+ updateItemLayout(index: number, layout: LayoutRect): void;
200
+ invalidateFrom(index: number): void;
201
+ getIndexForOffset(offset: number): number;
202
+ getTotalItemCount(): number;
203
+ }
204
+ /**
205
+ * Cell recycler interface
206
+ */
207
+ interface CellRecyclerInterface {
208
+ acquireCell(type: string, flatIndex: number): RecycledCell | null;
209
+ releaseCell(cell: RecycledCell): void;
210
+ clearPools(): void;
211
+ setMaxPoolSize(type: string, size: number): void;
212
+ getPoolStats(): Map<string, {
213
+ available: number
214
+ inUse: number
215
+ }>;
216
+ }
217
+ /**
218
+ * Viewability tracker interface
219
+ */
220
+ interface ViewabilityTrackerInterface<TItem> {
221
+ updateScrollOffset(offset: number): void;
222
+ getVisibleIndices(): number[];
223
+ isIndexVisible(index: number): boolean;
224
+ getFirstVisibleIndex(): number;
225
+ getLastVisibleIndex(): number;
226
+ onViewableItemsChanged(callback: (info: {
227
+ viewableItems: ViewToken<TItem>[]
228
+ changed: ViewToken<TItem>[]
229
+ }) => void): () => void;
230
+ }
231
+
232
+ /**
233
+ * Export with proper generic typing.
234
+ * Usage: <SectionFlow<MyItemType> sections={...} renderItem={...} />
235
+ */
236
+ declare const SectionFlow: <TItem>(props: SectionFlowProps<TItem> & {
237
+ ref?: React$1.ForwardedRef<SectionFlowRef<TItem>>
238
+ }) => React$1.ReactElement;
239
+
240
+ interface RecyclerCellProps {
241
+ cell: RecycledCell;
242
+ layout: LayoutRect;
243
+ children: React$1.ReactNode;
244
+ onLayout: (key: string, flatIndex: number, layout: LayoutRect) => void;
245
+ debug?: boolean;
246
+ }
247
+ /**
248
+ * RecyclerCell wraps each item with absolute positioning.
249
+ * This is the fundamental unit of the recycling system.
250
+ *
251
+ * Key responsibilities:
252
+ * 1. Position the item at the correct x/y coordinates
253
+ * 2. Report layout measurements back to the system
254
+ * 3. Maintain stable identity for recycling (via key)
255
+ */
256
+ declare function RecyclerCellComponent({ cell, layout, children, onLayout, debug }: RecyclerCellProps): React$1.ReactElement;
257
+ /**
258
+ * Memoized cell component to prevent unnecessary re-renders.
259
+ * Only re-renders when:
260
+ * - Cell key changes (different item)
261
+ * - Layout position changes
262
+ * - Children change (new render)
263
+ */
264
+ declare const RecyclerCell: React$1.MemoExoticComponent<typeof RecyclerCellComponent>;
265
+
266
+ interface RecyclerContainerProps<TItem> {
267
+ flattenedData: FlattenedItem<TItem>[];
268
+ visibleRange: {
269
+ startIndex: number
270
+ endIndex: number
271
+ };
272
+ getLayoutForIndex: (index: number) => LayoutRect;
273
+ getCell: (flatIndex: number) => RecycledCell;
274
+ contentSize: {
275
+ width: number
276
+ height: number
277
+ };
278
+ renderItem: (info: RenderItemInfo<TItem>) => React$1.ReactElement | null;
279
+ renderSectionHeader?: (info: RenderSectionHeaderInfo<TItem>) => React$1.ReactElement | null;
280
+ renderSectionFooter?: (info: RenderSectionFooterInfo<TItem>) => React$1.ReactElement | null;
281
+ onCellLayout: (key: string, flatIndex: number, layout: LayoutRect) => void;
282
+ horizontal?: boolean;
283
+ debug?: boolean;
284
+ }
285
+ /**
286
+ * RecyclerContainer manages the absolute-positioned content area.
287
+ * It renders only the visible items within the current scroll window.
288
+ *
289
+ * Key responsibilities:
290
+ * 1. Set content size for scroll container
291
+ * 2. Render visible items at correct positions
292
+ * 3. Coordinate cell recycling
293
+ */
294
+ declare function RecyclerContainerComponent<TItem>({ flattenedData, visibleRange, getLayoutForIndex, getCell, contentSize, renderItem, renderSectionHeader, renderSectionFooter, onCellLayout, horizontal, debug }: RecyclerContainerProps<TItem>): React$1.ReactElement;
295
+ declare const RecyclerContainer: typeof RecyclerContainerComponent;
296
+
297
+ interface SectionHeaderProps<TItem> {
298
+ section: Section<TItem>;
299
+ sectionIndex: number;
300
+ isCollapsed?: boolean;
301
+ collapsible?: boolean;
302
+ onToggle?: (sectionKey: string) => void;
303
+ renderContent?: (info: {
304
+ section: Section<TItem>
305
+ sectionIndex: number
306
+ isCollapsed: boolean
307
+ }) => React$1.ReactElement | null;
308
+ style?: ViewStyle;
309
+ }
310
+ /**
311
+ * Default section header component.
312
+ * Can be overridden by providing renderSectionHeader prop to SectionFlow.
313
+ */
314
+ declare function SectionHeaderComponent<TItem>({ section, sectionIndex, isCollapsed, collapsible, onToggle, renderContent, style }: SectionHeaderProps<TItem>): React$1.ReactElement;
315
+ declare const SectionHeader: typeof SectionHeaderComponent;
316
+
317
+ interface StickyHeaderContainerProps<TItem> {
318
+ stickySection: SectionLayoutInfo | null;
319
+ translateY: number;
320
+ sections: Section<TItem>[];
321
+ renderSectionHeader: (info: RenderSectionHeaderInfo<TItem>) => React$1.ReactElement | null;
322
+ horizontal?: boolean;
323
+ style?: ViewStyle;
324
+ }
325
+ /**
326
+ * Container for the sticky section header.
327
+ * Positioned at the top (or left for horizontal) of the viewport.
328
+ * Handles the "push" effect when the next section approaches.
329
+ */
330
+ declare function StickyHeaderContainerComponent<TItem>({ stickySection, translateY, sections, renderSectionHeader, horizontal, style }: StickyHeaderContainerProps<TItem>): React$1.ReactElement | null;
331
+ declare const StickyHeaderContainer: typeof StickyHeaderContainerComponent;
332
+ /**
333
+ * Animated version of sticky header for smoother transitions.
334
+ * Uses Animated API for better performance on the native thread.
335
+ */
336
+ interface AnimatedStickyHeaderProps<TItem> extends StickyHeaderContainerProps<TItem> {
337
+ animatedTranslateY: Animated.Value;
338
+ }
339
+ declare function AnimatedStickyHeaderContainerComponent<TItem>({ stickySection, animatedTranslateY, sections, renderSectionHeader, horizontal, style }: AnimatedStickyHeaderProps<TItem>): React$1.ReactElement | null;
340
+ declare const AnimatedStickyHeaderContainer: typeof AnimatedStickyHeaderContainerComponent;
341
+
342
+ interface UseMeasurementOptions {
343
+ onMeasure: (layout: LayoutRect) => void;
344
+ enabled?: boolean;
345
+ }
346
+ interface MeasurementResult {
347
+ ref: React.RefObject<View | null>;
348
+ onLayout: (event: LayoutChangeEvent) => void;
349
+ measure: () => void;
350
+ }
351
+ /**
352
+ * Hook for synchronous layout measurement using New Architecture features.
353
+ *
354
+ * In React Native's New Architecture with Fabric, useLayoutEffect runs synchronously
355
+ * before paint, allowing us to measure and correct layouts without visible glitches.
356
+ *
357
+ * This hook provides:
358
+ * 1. A ref to attach to the View
359
+ * 2. An onLayout callback for initial/resize measurements
360
+ * 3. A measure function for on-demand measurement
361
+ */
362
+ declare function useLayoutMeasurement(options: UseMeasurementOptions): MeasurementResult;
363
+ /**
364
+ * Hook for measuring a cell's layout and reporting to the layout system.
365
+ * Uses synchronous measurement in New Architecture for smooth corrections.
366
+ */
367
+ declare function useCellMeasurement(cellKey: string, onCellMeasured: (key: string, layout: LayoutRect) => void, enabled?: boolean): MeasurementResult;
368
+ /**
369
+ * Hook for progressive rendering - measures initial items and expands.
370
+ * Implements FlashList v2's progressive rendering strategy.
371
+ */
372
+ declare function useProgressiveRender(totalItems: number, initialCount: number, batchSize: number, onRenderCountChange: (count: number) => void): {
373
+ renderCount: number
374
+ onItemMeasured: (index: number) => void
375
+ };
376
+
377
+ interface ScrollState {
378
+ offset: number;
379
+ velocity: number;
380
+ direction: "forward" | "backward" | "idle";
381
+ isScrolling: boolean;
382
+ contentSize: number;
383
+ viewportSize: number;
384
+ }
385
+ interface UseScrollHandlerOptions {
386
+ horizontal?: boolean;
387
+ onScrollStateChange?: (state: ScrollState) => void;
388
+ onEndReached?: (distanceFromEnd: number) => void;
389
+ onEndReachedThreshold?: number;
390
+ }
391
+ interface ScrollHandlerResult {
392
+ scrollState: React.RefObject<ScrollState>;
393
+ onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
394
+ onScrollBeginDrag: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
395
+ onScrollEndDrag: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
396
+ onMomentumScrollBegin: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
397
+ onMomentumScrollEnd: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
398
+ onContentSizeChange: (width: number, height: number) => void;
399
+ }
400
+ /**
401
+ * Hook for tracking scroll state with velocity and direction detection.
402
+ * Used for adaptive buffering and scroll optimization.
403
+ */
404
+ declare function useScrollHandler(options?: UseScrollHandlerOptions): ScrollHandlerResult;
405
+ /**
406
+ * Hook to calculate adaptive draw distance based on scroll velocity.
407
+ * Increases buffer for fast scrolling to reduce blank areas.
408
+ */
409
+ declare function useAdaptiveDrawDistance(baseDistance: number, scrollVelocity: number): number;
410
+
411
+ interface UseRecyclerOptions<TItem> {
412
+ flattenedData: FlattenedItem<TItem>[];
413
+ getItemType?: (item: TItem, index: number) => string;
414
+ maxPoolSize?: number;
415
+ }
416
+ interface RecyclerResult {
417
+ getCell: (flatIndex: number) => RecycledCell;
418
+ releaseCell: (cell: RecycledCell) => void;
419
+ updateVisibleRange: (startIndex: number, endIndex: number) => void;
420
+ clearPools: () => void;
421
+ getPoolStats: () => Map<string, {
422
+ available: number
423
+ inUse: number
424
+ }>;
425
+ }
426
+ /**
427
+ * Hook for managing cell recycling state.
428
+ * Provides methods to acquire and release cells based on visibility.
429
+ */
430
+ declare function useRecycler<TItem>(options: UseRecyclerOptions<TItem>): RecyclerResult;
431
+ /**
432
+ * Hook to determine which item type to use for rendering.
433
+ * Returns a stable function that maps flat indices to type strings.
434
+ */
435
+ declare function useItemTypeResolver<TItem>(flattenedData: FlattenedItem<TItem>[], getItemType?: (item: TItem, index: number) => string): (flatIndex: number) => string;
436
+
437
+ interface StickyHeaderState {
438
+ sectionKey: string | null;
439
+ sectionIndex: number;
440
+ translateY: number;
441
+ isSticky: boolean;
442
+ headerLayout: LayoutRect | null;
443
+ }
444
+ interface UseStickyHeaderOptions {
445
+ sectionLayouts: SectionLayoutInfo[];
446
+ scrollOffset: number;
447
+ viewportHeight: number;
448
+ horizontal?: boolean;
449
+ enabled?: boolean;
450
+ }
451
+ /**
452
+ * Hook for computing sticky header positioning.
453
+ * Handles the "pushing" effect when the next section header approaches.
454
+ */
455
+ declare function useStickyHeader(options: UseStickyHeaderOptions): StickyHeaderState;
456
+ /**
457
+ * Hook for tracking multiple sticky headers (e.g., for multi-level sections).
458
+ */
459
+ declare function useMultipleStickyHeaders(sectionLayouts: SectionLayoutInfo[], scrollOffset: number, levels?: number): StickyHeaderState[];
460
+ /**
461
+ * Hook for determining sticky header opacity during transitions.
462
+ */
463
+ declare function useStickyHeaderOpacity(stickyState: StickyHeaderState, fadeDistance?: number): number;
464
+
465
+ interface UseViewabilityOptions<TItem> {
466
+ flattenedData: FlattenedItem<TItem>[];
467
+ layoutPositioner: LayoutPositioner;
468
+ scrollOffset: number;
469
+ viewportSize: number;
470
+ horizontal?: boolean;
471
+ viewabilityConfig?: ViewabilityConfig;
472
+ onViewableItemsChanged?: (info: {
473
+ viewableItems: ViewToken<TItem>[]
474
+ changed: ViewToken<TItem>[]
475
+ }) => void;
476
+ }
477
+ interface ViewabilityResult<TItem> {
478
+ visibleIndices: number[];
479
+ firstVisibleIndex: number;
480
+ lastVisibleIndex: number;
481
+ getVisibleItems: () => ViewToken<TItem>[];
482
+ recordInteraction: () => void;
483
+ }
484
+ /**
485
+ * Hook for tracking item viewability and triggering callbacks.
486
+ */
487
+ declare function useViewability<TItem>(options: UseViewabilityOptions<TItem>): ViewabilityResult<TItem>;
488
+ /**
489
+ * Hook for handling multiple viewability configs with different callbacks.
490
+ */
491
+ declare function useMultipleViewabilityConfigs<TItem>(flattenedData: FlattenedItem<TItem>[], layoutPositioner: LayoutPositioner, scrollOffset: number, viewportSize: number, configs: Array<{
492
+ viewabilityConfig: ViewabilityConfig
493
+ onViewableItemsChanged: (info: {
494
+ viewableItems: ViewToken<TItem>[]
495
+ changed: ViewToken<TItem>[]
496
+ }) => void
497
+ }>, horizontal?: boolean): void;
498
+
499
+ /**
500
+ * LayoutCache stores measured layout information for items.
501
+ * This is used for:
502
+ * 1. Caching measured sizes to avoid re-measurement
503
+ * 2. Tracking which items have been measured vs estimated
504
+ * 3. Computing average sizes per item type for better predictions
505
+ */
506
+ interface LayoutCache {
507
+ get(key: string): LayoutRect | undefined;
508
+ set(key: string, layout: LayoutRect): void;
509
+ has(key: string): boolean;
510
+ delete(key: string): void;
511
+ clear(): void;
512
+ invalidateFrom(flatIndex: number, keyToIndexMap: Map<string, number>): void;
513
+ getAverageSize(itemType: string): number | undefined;
514
+ recordMeasurement(itemType: string, size: number): void;
515
+ size: number;
516
+ }
517
+ /**
518
+ * Factory function to create a LayoutCache instance.
519
+ */
520
+ declare function createLayoutCache(): LayoutCache;
521
+
522
+ interface LinearLayoutPositionerOptions {
523
+ horizontal?: boolean;
524
+ estimatedItemSize?: number;
525
+ estimatedHeaderSize?: number;
526
+ estimatedFooterSize?: number;
527
+ containerWidth?: number;
528
+ containerHeight?: number;
529
+ }
530
+ /**
531
+ * LinearLayoutPositioner implements the LayoutPositioner interface for
532
+ * standard vertical or horizontal list layouts.
533
+ *
534
+ * It computes absolute positions for each item based on:
535
+ * 1. Measured sizes from LayoutCache (when available)
536
+ * 2. Estimated sizes (when not yet measured)
537
+ * 3. Type-specific size predictions
538
+ */
539
+ declare class LinearLayoutPositioner implements LayoutPositioner {
540
+ private horizontal;
541
+ private estimatedItemSize;
542
+ private estimatedHeaderSize;
543
+ private estimatedFooterSize;
544
+ private containerWidth;
545
+ private containerHeight;
546
+ private flattenedData;
547
+ private layoutCache;
548
+ private getItemType;
549
+ private computedLayouts;
550
+ private totalContentSize;
551
+ private layoutsValid;
552
+ constructor(layoutCache: LayoutCache, getItemType: (flatIndex: number) => string, options?: LinearLayoutPositionerOptions);
553
+ /**
554
+ * Update the flattened data and invalidate layouts.
555
+ */
556
+ setData(flattenedData: FlattenedItem<unknown>[]): void;
557
+ /**
558
+ * Update container dimensions.
559
+ */
560
+ setContainerSize(width: number, height: number): void;
561
+ /**
562
+ * Get the estimated size for an item based on its type.
563
+ */
564
+ private getEstimatedSize;
565
+ /**
566
+ * Get the actual or estimated size for an item.
567
+ */
568
+ private getItemSize;
569
+ /**
570
+ * Compute layouts for all items if not already computed.
571
+ */
572
+ private ensureLayoutsComputed;
573
+ /**
574
+ * Get the layout for a specific index.
575
+ */
576
+ getLayoutForIndex(index: number): LayoutRect;
577
+ /**
578
+ * Get the total content size.
579
+ */
580
+ getContentSize(): {
581
+ width: number
582
+ height: number
583
+ };
584
+ /**
585
+ * Get the range of visible indices for the given scroll position.
586
+ * Uses binary search for efficiency with large lists.
587
+ */
588
+ getVisibleRange(scrollOffset: number, viewportSize: number, overscan: number): {
589
+ startIndex: number
590
+ endIndex: number
591
+ };
592
+ /**
593
+ * Binary search to find first item that ends after the given offset.
594
+ */
595
+ private binarySearchStart;
596
+ /**
597
+ * Binary search to find last item that starts before the given offset.
598
+ */
599
+ private binarySearchEnd;
600
+ /**
601
+ * Update the layout for a specific index after measurement.
602
+ */
603
+ updateItemLayout(index: number, layout: LayoutRect): void;
604
+ /**
605
+ * Invalidate layouts from a given index.
606
+ */
607
+ invalidateFrom(index: number): void;
608
+ /**
609
+ * Invalidate all layouts.
610
+ */
611
+ invalidateAll(): void;
612
+ /**
613
+ * Get the index of the item at or just before the given offset.
614
+ */
615
+ getIndexForOffset(offset: number): number;
616
+ /**
617
+ * Get the total number of items.
618
+ */
619
+ getTotalItemCount(): number;
620
+ }
621
+ /**
622
+ * Factory function to create a LinearLayoutPositioner.
623
+ */
624
+ declare function createLayoutPositioner(layoutCache: LayoutCache, getItemType: (flatIndex: number) => string, options?: LinearLayoutPositionerOptions): LinearLayoutPositioner;
625
+
626
+ /**
627
+ * CellRecycler manages pools of recycled cell instances per item type.
628
+ * This is the core of FlashList-style performance - reusing view components
629
+ * instead of destroying and recreating them.
630
+ */
631
+ declare class CellRecyclerImpl implements CellRecyclerInterface {
632
+ private pools;
633
+ private inUse;
634
+ private defaultMaxPoolSize;
635
+ private cellCounter;
636
+ constructor(defaultMaxPoolSize?: number);
637
+ /**
638
+ * Acquire a cell from the pool for the given type.
639
+ * Returns null if no recycled cells are available (caller should create new).
640
+ */
641
+ acquireCell(type: string, flatIndex: number): RecycledCell | null;
642
+ /**
643
+ * Release a cell back to its pool for recycling.
644
+ */
645
+ releaseCell(cell: RecycledCell): void;
646
+ /**
647
+ * Clear all recycled cells from all pools.
648
+ * Useful when data changes significantly.
649
+ */
650
+ clearPools(): void;
651
+ /**
652
+ * Set the maximum pool size for a specific item type.
653
+ */
654
+ setMaxPoolSize(type: string, size: number): void;
655
+ /**
656
+ * Get statistics about pool usage for debugging.
657
+ */
658
+ getPoolStats(): Map<string, {
659
+ available: number
660
+ inUse: number
661
+ }>;
662
+ /**
663
+ * Generate a unique key for a new cell.
664
+ */
665
+ generateCellKey(type: string): string;
666
+ /**
667
+ * Create a new cell (when pool is empty).
668
+ */
669
+ createCell(type: string, flatIndex: number): RecycledCell;
670
+ /**
671
+ * Get or create a cell - the main method used during rendering.
672
+ * First tries to acquire from pool, then creates new if needed.
673
+ */
674
+ getCell(type: string, flatIndex: number): RecycledCell;
675
+ }
676
+ /**
677
+ * Factory function to create a CellRecycler instance.
678
+ */
679
+ declare function createCellRecycler(defaultMaxPoolSize?: number): CellRecyclerImpl;
680
+
681
+ /**
682
+ * ViewabilityTracker monitors which items are currently visible in the viewport
683
+ * and triggers callbacks when viewability changes.
684
+ */
685
+ interface ViewabilityTracker<TItem> {
686
+ updateScrollOffset(offset: number): void;
687
+ setViewportSize(size: number): void;
688
+ setData(flattenedData: FlattenedItem<TItem>[]): void;
689
+ getVisibleIndices(): number[];
690
+ isIndexVisible(index: number): boolean;
691
+ getFirstVisibleIndex(): number;
692
+ getLastVisibleIndex(): number;
693
+ onViewableItemsChanged(callback: (info: {
694
+ viewableItems: ViewToken<TItem>[]
695
+ changed: ViewToken<TItem>[]
696
+ }) => void): () => void;
697
+ recordInteraction(): void;
698
+ dispose(): void;
699
+ }
700
+ /**
701
+ * Factory function to create a ViewabilityTracker.
702
+ */
703
+ declare function createViewabilityTracker<TItem>(layoutPositioner: LayoutPositioner, flattenedData: FlattenedItem<TItem>[], config?: ViewabilityConfig, horizontal?: boolean): ViewabilityTracker<TItem>;
704
+
705
+ /**
706
+ * SectionLayoutManager provides section-aware layout operations on top of
707
+ * the LinearLayoutPositioner. It handles:
708
+ * - Mapping between section/item coordinates and flat indices
709
+ * - Tracking section boundaries and layouts
710
+ * - Managing collapsed section state
711
+ */
712
+ interface SectionLayoutManager {
713
+ getFlatIndex(sectionIndex: number, itemIndex: number): number;
714
+ getSectionItemIndex(flatIndex: number): {
715
+ sectionIndex: number
716
+ itemIndex: number
717
+ isHeader: boolean
718
+ isFooter: boolean
719
+ };
720
+ getSectionLayout(sectionKey: string): SectionLayoutInfo | null;
721
+ getSectionAtOffset(offset: number): SectionLayoutInfo | null;
722
+ getAllSectionLayouts(): SectionLayoutInfo[];
723
+ setSectionCollapsed(sectionKey: string, collapsed: boolean): void;
724
+ isSectionCollapsed(sectionKey: string): boolean;
725
+ getCollapsedSections(): Set<string>;
726
+ updateData(sections: Section<unknown>[], collapsedSections: Set<string>): FlattenedItem<unknown>[];
727
+ getLayoutPositioner(): LinearLayoutPositioner;
728
+ }
729
+ /**
730
+ * Factory function to create a SectionLayoutManager.
731
+ */
732
+ declare function createSectionLayoutManager(layoutCache: LayoutCache, options?: {
733
+ horizontal?: boolean
734
+ estimatedItemSize?: number
735
+ estimatedHeaderSize?: number
736
+ estimatedFooterSize?: number
737
+ hasSectionFooters?: boolean
738
+ }): SectionLayoutManager;
739
+
740
+ interface FlattenOptions {
741
+ collapsedSections?: Set<string>;
742
+ includeSectionFooters?: boolean;
743
+ }
744
+ /**
745
+ * Flatten sections into a single array of items for virtualization.
746
+ * Each item includes metadata about its section and position.
747
+ */
748
+ declare function flattenSections<TItem>(sections: Section<TItem>[], options?: FlattenOptions): FlattenedItem<TItem>[];
749
+ /**
750
+ * Get the flat index for a specific section and item index.
751
+ */
752
+ declare function getFlatIndex<TItem>(sections: Section<TItem>[], sectionIndex: number, itemIndex: number, collapsedSections?: Set<string>, includeSectionFooters?: boolean): number;
753
+ /**
754
+ * Get section and item index from a flat index.
755
+ */
756
+ declare function getSectionItemFromFlatIndex<TItem>(sections: Section<TItem>[], flatIndex: number, collapsedSections?: Set<string>, includeSectionFooters?: boolean): {
757
+ sectionIndex: number
758
+ itemIndex: number
759
+ type: "header" | "item" | "footer"
760
+ } | null;
761
+
762
+ /**
763
+ * Key extraction utilities for list items.
764
+ */
765
+ /**
766
+ * Default key extractor that uses index as string.
767
+ * Note: Using indices as keys is not recommended for dynamic lists.
768
+ */
769
+ declare function defaultKeyExtractor<TItem>(item: TItem, index: number): string;
770
+ /**
771
+ * Create a key extractor function with a custom field name.
772
+ */
773
+ declare function createKeyExtractor<TItem>(field: keyof TItem): (item: TItem, index: number) => string;
774
+ /**
775
+ * Create a composite key from multiple fields.
776
+ */
777
+ declare function createCompositeKeyExtractor<TItem>(fields: (keyof TItem)[]): (item: TItem, index: number) => string;
778
+ /**
779
+ * Validate that keys are unique within a list.
780
+ * Throws an error if duplicates are found.
781
+ */
782
+ declare function validateUniqueKeys<TItem>(items: TItem[], keyExtractor: (item: TItem, index: number) => string): void;
783
+
784
+ /**
785
+ * Binary search utilities for efficient offset-to-index lookups.
786
+ */
787
+ /**
788
+ * Binary search to find the index of an item with a specific value.
789
+ * Returns -1 if not found.
790
+ */
791
+ declare function binarySearch<T>(array: T[], target: number, getValue: (item: T) => number): number;
792
+ /**
793
+ * Binary search to find the insertion position for a value.
794
+ * Returns the index where the value should be inserted to maintain sorted order.
795
+ */
796
+ declare function binarySearchInsertPosition<T>(array: T[], target: number, getValue: (item: T) => number): number;
797
+
798
+ /**
799
+ * Default configuration values for SectionFlow
800
+ */
801
+ declare const DEFAULT_ESTIMATED_ITEM_SIZE = 50;
802
+ declare const DEFAULT_ESTIMATED_HEADER_SIZE = 40;
803
+ declare const DEFAULT_DRAW_DISTANCE = 250;
804
+ declare const DEFAULT_MAX_POOL_SIZE = 10;
805
+ declare const DEFAULT_ITEM_TYPE = "default";
806
+ declare const SECTION_HEADER_TYPE = "__section_header__";
807
+ declare const SECTION_FOOTER_TYPE = "__section_footer__";
808
+
809
+ /**
810
+ * Internal context value for SectionFlow components.
811
+ */
812
+ interface SectionFlowContextValue<TItem> {
813
+ sections: Section<TItem>[];
814
+ flattenedData: FlattenedItem<TItem>[];
815
+ layoutManager: SectionLayoutManager;
816
+ layoutCache: LayoutCache;
817
+ horizontal: boolean;
818
+ collapsedSections: Set<string>;
819
+ scrollOffset: number;
820
+ viewportWidth: number;
821
+ viewportHeight: number;
822
+ stickySectionHeadersEnabled: boolean;
823
+ estimatedItemSize: number;
824
+ drawDistance: number;
825
+ debug: boolean;
826
+ renderItem: (info: RenderItemInfo<TItem>) => React$1.ReactElement | null;
827
+ renderSectionHeader?: (info: RenderSectionHeaderInfo<TItem>) => React$1.ReactElement | null;
828
+ renderSectionFooter?: (info: RenderSectionFooterInfo<TItem>) => React$1.ReactElement | null;
829
+ onCellMeasured: (key: string, flatIndex: number, layout: LayoutRect) => void;
830
+ onSectionToggle?: (sectionKey: string, collapsed: boolean) => void;
831
+ getItemType: (flatIndex: number) => string;
832
+ }
833
+ /**
834
+ * Hook to access SectionFlow context.
835
+ * Must be used within a SectionFlowProvider.
836
+ */
837
+ declare function useSectionFlowContext<TItem>(): SectionFlowContextValue<TItem>;
838
+ interface SectionFlowProviderProps<TItem> {
839
+ children: React$1.ReactNode;
840
+ sections: Section<TItem>[];
841
+ flattenedData: FlattenedItem<TItem>[];
842
+ layoutManager: SectionLayoutManager;
843
+ layoutCache: LayoutCache;
844
+ horizontal: boolean;
845
+ collapsedSections: Set<string>;
846
+ scrollOffset: number;
847
+ viewportWidth: number;
848
+ viewportHeight: number;
849
+ stickySectionHeadersEnabled: boolean;
850
+ estimatedItemSize: number;
851
+ drawDistance: number;
852
+ debug: boolean;
853
+ renderItem: (info: RenderItemInfo<TItem>) => React$1.ReactElement | null;
854
+ renderSectionHeader?: (info: RenderSectionHeaderInfo<TItem>) => React$1.ReactElement | null;
855
+ renderSectionFooter?: (info: RenderSectionFooterInfo<TItem>) => React$1.ReactElement | null;
856
+ onCellMeasured: (key: string, flatIndex: number, layout: LayoutRect) => void;
857
+ onSectionToggle?: (sectionKey: string, collapsed: boolean) => void;
858
+ getItemType: (flatIndex: number) => string;
859
+ }
860
+ /**
861
+ * Provider component for SectionFlow context.
862
+ */
863
+ declare function SectionFlowProvider<TItem>({ children, sections, flattenedData, layoutManager, layoutCache, horizontal, collapsedSections, scrollOffset, viewportWidth, viewportHeight, stickySectionHeadersEnabled, estimatedItemSize, drawDistance, debug, renderItem, renderSectionHeader, renderSectionFooter, onCellMeasured, onSectionToggle, getItemType }: SectionFlowProviderProps<TItem>): React$1.ReactElement;
864
+
865
+ export { AnimatedStickyHeaderContainer, DEFAULT_DRAW_DISTANCE, DEFAULT_ESTIMATED_HEADER_SIZE, DEFAULT_ESTIMATED_ITEM_SIZE, DEFAULT_ITEM_TYPE, DEFAULT_MAX_POOL_SIZE, LinearLayoutPositioner, RecyclerCell, RecyclerContainer, SECTION_FOOTER_TYPE, SECTION_HEADER_TYPE, SectionFlow, SectionFlowProvider, SectionHeader, StickyHeaderContainer, binarySearch, binarySearchInsertPosition, createCellRecycler, createCompositeKeyExtractor, createKeyExtractor, createLayoutCache, createLayoutPositioner, createSectionLayoutManager, createViewabilityTracker, defaultKeyExtractor, flattenSections, getFlatIndex, getSectionItemFromFlatIndex, useAdaptiveDrawDistance, useCellMeasurement, useItemTypeResolver, useLayoutMeasurement, useMultipleStickyHeaders, useMultipleViewabilityConfigs, useProgressiveRender, useRecycler, useScrollHandler, useSectionFlowContext, useStickyHeader, useStickyHeaderOpacity, useViewability, validateUniqueKeys };
866
+ export type { CellRecyclerInterface, FlattenedItem, FlattenedItemType, LayoutCache, LayoutPositioner, LayoutRect, RecyclePool, RecycledCell, RenderItemInfo, RenderSectionFooterInfo, RenderSectionHeaderInfo, ScrollToItemOptions, ScrollToSectionOptions, Section, SectionFlowProps, SectionFlowRef, SectionLayoutInfo, SectionLayoutManager, ViewToken, ViewabilityConfig, ViewabilityConfigCallbackPair, ViewabilityTracker, ViewabilityTrackerInterface };