@dreamstack-us/section-flow 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +41 -0
- package/dist/index.cjs +2281 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +866 -0
- package/dist/index.d.ts +866 -0
- package/dist/index.js +2217 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["key: string","layout: LayoutRect","flatIndex: number","keyToIndexMap: Map<string, number>","itemType: string","size: number","layoutCache: LayoutCache","getItemType: (flatIndex: number) => string","options: LinearLayoutPositionerOptions","flattenedData: FlattenedItem<unknown>[]","width: number","height: number","flatIndex: number","layout: LayoutRect","index: number","scrollOffset: number","viewportSize: number","overscan: number","offset: number","options?: LinearLayoutPositionerOptions","layoutCache: LayoutCache","options: {\n horizontal?: boolean;\n estimatedItemSize?: number;\n estimatedHeaderSize?: number;\n estimatedFooterSize?: number;\n hasSectionFooters?: boolean;\n }","flatIndex: number","sections: Section<unknown>[]","collapsedSections: Set<string>","boundary: SectionBoundary","sectionIndex: number","itemIndex: number","sectionKey: string","footerLayout: LayoutRect | null","offset: number","layouts: SectionLayoutInfo[]","collapsed: boolean","options?: {\n horizontal?: boolean;\n estimatedItemSize?: number;\n estimatedHeaderSize?: number;\n estimatedFooterSize?: number;\n hasSectionFooters?: boolean;\n }","options: UseScrollHandlerOptions","newOffset: number","velocity: number","event: NativeScrollEvent","isScrolling: boolean","event: NativeSyntheticEvent<NativeScrollEvent>","width: number","height: number","baseDistance: number","scrollVelocity: number","defaultMaxPoolSize: number","type: string","flatIndex: number","cell: RecycledCell","size: number","options: UseRecyclerOptions<TItem>","flatIndex: number","cell: RecycledCell","startIndex: number","endIndex: number","flattenedData: FlattenedItem<TItem>[]","getItemType?: (item: TItem, index: number) => string","options: UseStickyHeaderOptions","currentSection: SectionLayoutInfo | null","nextSection: SectionLayoutInfo | null","sectionLayouts: SectionLayoutInfo[]","scrollOffset: number","levels: number","states: StickyHeaderState[]","stickyState: StickyHeaderState","fadeDistance: number","layoutPositioner: LayoutPositioner","flattenedData: FlattenedItem<TItem>[]","config: ViewabilityConfig","offset: number","size: number","changed: ViewToken<TItem>[]","flatIndex: number","layout: { x: number; y: number; width: number; height: number }","isViewable: boolean","index: number","callback: (info: { viewableItems: ViewToken<TItem>[]; changed: ViewToken<TItem>[] }) => void","config?: ViewabilityConfig","horizontal?: boolean","options: UseViewabilityOptions<TItem>","flattenedData: FlattenedItem<TItem>[]","layoutPositioner: LayoutPositioner","scrollOffset: number","viewportSize: number","configs: Array<{\n viewabilityConfig: ViewabilityConfig;\n onViewableItemsChanged: (info: {\n viewableItems: ViewToken<TItem>[];\n changed: ViewToken<TItem>[];\n }) => void;\n }>","event: LayoutChangeEvent","positionStyle: ViewStyle","styles: { debug: ViewStyle }","RecyclerCell: React.MemoExoticComponent<typeof RecyclerCellComponent>","result: React.ReactElement[]","content: React.ReactElement | null","containerStyle: ViewStyle","containerStyle: ViewStyle","props: SectionFlowProps<TItem>","ref: React.ForwardedRef<SectionFlowRef<TItem>>","flatIndex: number","key: string","layout: LayoutRect","event: LayoutChangeEvent","sectionKey: string","options: { offset: number; animated?: boolean }","options: ScrollToSectionOptions","targetSection: SectionLayoutInfo | null","options: ScrollToItemOptions","options?: { animated?: boolean }","options: UseMeasurementOptions","layout: LayoutRect","event: LayoutChangeEvent","cellKey: string","onCellMeasured: (key: string, layout: LayoutRect) => void","totalItems: number","initialCount: number","batchSize: number","onRenderCountChange: (count: number) => void","index: number","sections: Section<TItem>[]","options: FlattenOptions","result: FlattenedItem<TItem>[]","sectionIndex: number","itemIndex: number","collapsedSections: Set<string>","flatIndex: number","item: TItem","index: number","field: keyof TItem","fields: (keyof TItem)[]","items: TItem[]","keyExtractor: (item: TItem, index: number) => string","array: T[]","target: number","getValue: (item: T) => number","offsets: number[]","sizes: number[]"],"sources":["../src/constants.ts","../src/core/LayoutCache.ts","../src/core/LinearLayoutPositioner.ts","../src/core/SectionLayoutManager.ts","../src/hooks/useScrollHandler.ts","../src/core/CellRecycler.ts","../src/hooks/useRecycler.ts","../src/hooks/useStickyHeader.ts","../src/core/ViewabilityTracker.ts","../src/hooks/useViewability.ts","../src/state/SectionFlowContext.tsx","../src/components/RecyclerCell.tsx","../src/components/RecyclerContainer.tsx","../src/components/StickyHeaderContainer.tsx","../src/components/SectionFlow.tsx","../src/components/SectionHeader.tsx","../src/hooks/useLayoutMeasurement.ts","../src/utils/flattenSections.ts","../src/utils/keyExtractor.ts","../src/utils/binarySearch.ts"],"sourcesContent":["/**\n * Default configuration values for SectionFlow\n */\n\nexport const DEFAULT_ESTIMATED_ITEM_SIZE = 50;\nexport const DEFAULT_ESTIMATED_HEADER_SIZE = 40;\nexport const DEFAULT_ESTIMATED_FOOTER_SIZE = 0;\n\nexport const DEFAULT_DRAW_DISTANCE = 250; // pixels of overscan\n\nexport const DEFAULT_MAX_POOL_SIZE = 10; // max recycled cells per type\n\nexport const DEFAULT_ITEM_TYPE = 'default';\nexport const SECTION_HEADER_TYPE = '__section_header__';\nexport const SECTION_FOOTER_TYPE = '__section_footer__';\n\nexport const DEFAULT_END_REACHED_THRESHOLD = 0.5;\n\nexport const DEFAULT_VIEWABILITY_CONFIG = {\n minimumViewTime: 250,\n viewAreaCoveragePercentThreshold: 0,\n itemVisiblePercentThreshold: 50,\n waitForInteraction: false,\n} as const;\n\nexport const PROGRESSIVE_RENDER_INITIAL_COUNT = 2;\nexport const PROGRESSIVE_RENDER_BATCH_SIZE = 5;\n\nexport const SCROLL_VELOCITY_THRESHOLD = 2; // pixels per ms for fast scroll detection\n\nexport const MEASUREMENT_DEBOUNCE_MS = 16; // ~1 frame at 60fps\n","import type { LayoutRect } from '../types';\n\n/**\n * LayoutCache stores measured layout information for items.\n * This is used for:\n * 1. Caching measured sizes to avoid re-measurement\n * 2. Tracking which items have been measured vs estimated\n * 3. Computing average sizes per item type for better predictions\n */\nexport interface LayoutCache {\n get(key: string): LayoutRect | undefined;\n set(key: string, layout: LayoutRect): void;\n has(key: string): boolean;\n delete(key: string): void;\n clear(): void;\n invalidateFrom(flatIndex: number, keyToIndexMap: Map<string, number>): void;\n getAverageSize(itemType: string): number | undefined;\n recordMeasurement(itemType: string, size: number): void;\n size: number;\n}\n\ninterface TypeStats {\n totalSize: number;\n count: number;\n}\n\nclass LayoutCacheImpl implements LayoutCache {\n private cache: Map<string, LayoutRect> = new Map();\n private typeStats: Map<string, TypeStats> = new Map();\n\n get(key: string): LayoutRect | undefined {\n return this.cache.get(key);\n }\n\n set(key: string, layout: LayoutRect): void {\n this.cache.set(key, layout);\n }\n\n has(key: string): boolean {\n return this.cache.has(key);\n }\n\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n clear(): void {\n this.cache.clear();\n this.typeStats.clear();\n }\n\n /**\n * Invalidate all cached layouts from a given flat index onwards.\n * Used when items are inserted/removed and positions need recalculation.\n */\n invalidateFrom(flatIndex: number, keyToIndexMap: Map<string, number>): void {\n for (const [key, index] of keyToIndexMap) {\n if (index >= flatIndex) {\n this.cache.delete(key);\n }\n }\n }\n\n /**\n * Get the average measured size for items of a given type.\n * Used for predicting unmeasured item sizes.\n */\n getAverageSize(itemType: string): number | undefined {\n const stats = this.typeStats.get(itemType);\n if (!stats || stats.count === 0) {\n return undefined;\n }\n return stats.totalSize / stats.count;\n }\n\n /**\n * Record a measurement for computing type averages.\n */\n recordMeasurement(itemType: string, size: number): void {\n let stats = this.typeStats.get(itemType);\n if (!stats) {\n stats = { totalSize: 0, count: 0 };\n this.typeStats.set(itemType, stats);\n }\n stats.totalSize += size;\n stats.count += 1;\n }\n\n get size(): number {\n return this.cache.size;\n }\n}\n\n/**\n * Factory function to create a LayoutCache instance.\n */\nexport function createLayoutCache(): LayoutCache {\n return new LayoutCacheImpl();\n}\n","import type { LayoutRect, LayoutPositioner, FlattenedItem } from '../types';\nimport type { LayoutCache } from './LayoutCache';\nimport {\n DEFAULT_ESTIMATED_ITEM_SIZE,\n DEFAULT_ESTIMATED_HEADER_SIZE,\n DEFAULT_ESTIMATED_FOOTER_SIZE,\n SECTION_HEADER_TYPE,\n SECTION_FOOTER_TYPE,\n} from '../constants';\n\ninterface LinearLayoutPositionerOptions {\n horizontal?: boolean;\n estimatedItemSize?: number;\n estimatedHeaderSize?: number;\n estimatedFooterSize?: number;\n containerWidth?: number;\n containerHeight?: number;\n}\n\n/**\n * LinearLayoutPositioner implements the LayoutPositioner interface for\n * standard vertical or horizontal list layouts.\n *\n * It computes absolute positions for each item based on:\n * 1. Measured sizes from LayoutCache (when available)\n * 2. Estimated sizes (when not yet measured)\n * 3. Type-specific size predictions\n */\nexport class LinearLayoutPositioner implements LayoutPositioner {\n private horizontal: boolean;\n private estimatedItemSize: number;\n private estimatedHeaderSize: number;\n private estimatedFooterSize: number;\n private containerWidth: number;\n private containerHeight: number;\n\n private flattenedData: FlattenedItem<unknown>[] = [];\n private layoutCache: LayoutCache;\n private getItemType: (flatIndex: number) => string;\n\n // Cached computed layouts (invalidated on data change)\n private computedLayouts: Map<number, LayoutRect> = new Map();\n private totalContentSize: { width: number; height: number } = { width: 0, height: 0 };\n private layoutsValid = false;\n\n constructor(\n layoutCache: LayoutCache,\n getItemType: (flatIndex: number) => string,\n options: LinearLayoutPositionerOptions = {}\n ) {\n this.layoutCache = layoutCache;\n this.getItemType = getItemType;\n this.horizontal = options.horizontal ?? false;\n this.estimatedItemSize = options.estimatedItemSize ?? DEFAULT_ESTIMATED_ITEM_SIZE;\n this.estimatedHeaderSize = options.estimatedHeaderSize ?? DEFAULT_ESTIMATED_HEADER_SIZE;\n this.estimatedFooterSize = options.estimatedFooterSize ?? DEFAULT_ESTIMATED_FOOTER_SIZE;\n this.containerWidth = options.containerWidth ?? 0;\n this.containerHeight = options.containerHeight ?? 0;\n }\n\n /**\n * Update the flattened data and invalidate layouts.\n */\n setData(flattenedData: FlattenedItem<unknown>[]): void {\n this.flattenedData = flattenedData;\n this.invalidateAll();\n }\n\n /**\n * Update container dimensions.\n */\n setContainerSize(width: number, height: number): void {\n if (this.containerWidth !== width || this.containerHeight !== height) {\n this.containerWidth = width;\n this.containerHeight = height;\n this.invalidateAll();\n }\n }\n\n /**\n * Get the estimated size for an item based on its type.\n */\n private getEstimatedSize(flatIndex: number): number {\n const item = this.flattenedData[flatIndex];\n if (!item) {\n return this.estimatedItemSize;\n }\n\n // Check for type-specific average from cache\n const itemType = this.getItemType(flatIndex);\n const avgSize = this.layoutCache.getAverageSize(itemType);\n if (avgSize !== undefined) {\n return avgSize;\n }\n\n // Use default estimates based on item type\n if (item.type === 'section-header') {\n return this.estimatedHeaderSize;\n }\n if (item.type === 'section-footer') {\n return this.estimatedFooterSize;\n }\n return this.estimatedItemSize;\n }\n\n /**\n * Get the actual or estimated size for an item.\n */\n private getItemSize(flatIndex: number): number {\n const item = this.flattenedData[flatIndex];\n if (!item) {\n return this.estimatedItemSize;\n }\n\n // Check cache for measured size\n const cached = this.layoutCache.get(item.key);\n if (cached) {\n return this.horizontal ? cached.width : cached.height;\n }\n\n // Fall back to estimated\n return this.getEstimatedSize(flatIndex);\n }\n\n /**\n * Compute layouts for all items if not already computed.\n */\n private ensureLayoutsComputed(): void {\n if (this.layoutsValid) {\n return;\n }\n\n this.computedLayouts.clear();\n let offset = 0;\n const crossAxisSize = this.horizontal ? this.containerHeight : this.containerWidth;\n\n for (let i = 0; i < this.flattenedData.length; i++) {\n const size = this.getItemSize(i);\n\n const layout: LayoutRect = this.horizontal\n ? {\n x: offset,\n y: 0,\n width: size,\n height: crossAxisSize,\n }\n : {\n x: 0,\n y: offset,\n width: crossAxisSize,\n height: size,\n };\n\n this.computedLayouts.set(i, layout);\n offset += size;\n }\n\n this.totalContentSize = this.horizontal\n ? { width: offset, height: crossAxisSize }\n : { width: crossAxisSize, height: offset };\n\n this.layoutsValid = true;\n }\n\n /**\n * Get the layout for a specific index.\n */\n getLayoutForIndex(index: number): LayoutRect {\n this.ensureLayoutsComputed();\n return (\n this.computedLayouts.get(index) ?? {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n }\n );\n }\n\n /**\n * Get the total content size.\n */\n getContentSize(): { width: number; height: number } {\n this.ensureLayoutsComputed();\n return this.totalContentSize;\n }\n\n /**\n * Get the range of visible indices for the given scroll position.\n * Uses binary search for efficiency with large lists.\n */\n getVisibleRange(\n scrollOffset: number,\n viewportSize: number,\n overscan: number\n ): { startIndex: number; endIndex: number } {\n this.ensureLayoutsComputed();\n\n if (this.flattenedData.length === 0) {\n return { startIndex: 0, endIndex: -1 };\n }\n\n const startOffset = Math.max(0, scrollOffset - overscan);\n const endOffset = scrollOffset + viewportSize + overscan;\n\n // Binary search for start index\n const startIndex = this.binarySearchStart(startOffset);\n // Binary search for end index\n const endIndex = this.binarySearchEnd(endOffset);\n\n return {\n startIndex: Math.max(0, startIndex),\n endIndex: Math.min(this.flattenedData.length - 1, endIndex),\n };\n }\n\n /**\n * Binary search to find first item that ends after the given offset.\n */\n private binarySearchStart(offset: number): number {\n let low = 0;\n let high = this.flattenedData.length - 1;\n\n while (low < high) {\n const mid = Math.floor((low + high) / 2);\n const layout = this.computedLayouts.get(mid);\n if (!layout) {\n low = mid + 1;\n continue;\n }\n\n const itemEnd = this.horizontal ? layout.x + layout.width : layout.y + layout.height;\n\n if (itemEnd <= offset) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * Binary search to find last item that starts before the given offset.\n */\n private binarySearchEnd(offset: number): number {\n let low = 0;\n let high = this.flattenedData.length - 1;\n\n while (low < high) {\n const mid = Math.ceil((low + high) / 2);\n const layout = this.computedLayouts.get(mid);\n if (!layout) {\n high = mid - 1;\n continue;\n }\n\n const itemStart = this.horizontal ? layout.x : layout.y;\n\n if (itemStart >= offset) {\n high = mid - 1;\n } else {\n low = mid;\n }\n }\n\n return high;\n }\n\n /**\n * Update the layout for a specific index after measurement.\n */\n updateItemLayout(index: number, layout: LayoutRect): void {\n const item = this.flattenedData[index];\n if (!item) return;\n\n const itemType = this.getItemType(index);\n const size = this.horizontal ? layout.width : layout.height;\n\n // Record measurement for type averages\n this.layoutCache.recordMeasurement(itemType, size);\n\n // Store in cache\n this.layoutCache.set(item.key, layout);\n\n // Invalidate layouts from this index onwards\n this.invalidateFrom(index);\n }\n\n /**\n * Invalidate layouts from a given index.\n */\n invalidateFrom(index: number): void {\n // Remove computed layouts from index onwards\n for (let i = index; i < this.flattenedData.length; i++) {\n this.computedLayouts.delete(i);\n }\n this.layoutsValid = false;\n }\n\n /**\n * Invalidate all layouts.\n */\n invalidateAll(): void {\n this.computedLayouts.clear();\n this.layoutsValid = false;\n }\n\n /**\n * Get the index of the item at or just before the given offset.\n */\n getIndexForOffset(offset: number): number {\n this.ensureLayoutsComputed();\n\n if (this.flattenedData.length === 0) {\n return 0;\n }\n\n return this.binarySearchStart(offset);\n }\n\n /**\n * Get the total number of items.\n */\n getTotalItemCount(): number {\n return this.flattenedData.length;\n }\n}\n\n/**\n * Factory function to create a LinearLayoutPositioner.\n */\nexport function createLayoutPositioner(\n layoutCache: LayoutCache,\n getItemType: (flatIndex: number) => string,\n options?: LinearLayoutPositionerOptions\n): LinearLayoutPositioner {\n return new LinearLayoutPositioner(layoutCache, getItemType, options);\n}\n","import type { Section, SectionLayoutInfo, FlattenedItem, LayoutRect } from '../types';\nimport type { LayoutCache } from './LayoutCache';\nimport { LinearLayoutPositioner } from './LinearLayoutPositioner';\n\n/**\n * SectionLayoutManager provides section-aware layout operations on top of\n * the LinearLayoutPositioner. It handles:\n * - Mapping between section/item coordinates and flat indices\n * - Tracking section boundaries and layouts\n * - Managing collapsed section state\n */\nexport interface SectionLayoutManager {\n // Coordinate mapping\n getFlatIndex(sectionIndex: number, itemIndex: number): number;\n getSectionItemIndex(flatIndex: number): { sectionIndex: number; itemIndex: number; isHeader: boolean; isFooter: boolean };\n\n // Section layout info\n getSectionLayout(sectionKey: string): SectionLayoutInfo | null;\n getSectionAtOffset(offset: number): SectionLayoutInfo | null;\n getAllSectionLayouts(): SectionLayoutInfo[];\n\n // Collapse management\n setSectionCollapsed(sectionKey: string, collapsed: boolean): void;\n isSectionCollapsed(sectionKey: string): boolean;\n getCollapsedSections(): Set<string>;\n\n // Data updates\n updateData(sections: Section<unknown>[], collapsedSections: Set<string>): FlattenedItem<unknown>[];\n\n // Layout positioner access\n getLayoutPositioner(): LinearLayoutPositioner;\n}\n\ninterface SectionBoundary {\n sectionIndex: number;\n sectionKey: string;\n headerFlatIndex: number;\n firstItemFlatIndex: number;\n lastItemFlatIndex: number;\n footerFlatIndex: number | null;\n itemCount: number;\n}\n\nclass SectionLayoutManagerImpl implements SectionLayoutManager {\n private sections: Section<unknown>[] = [];\n private flattenedData: FlattenedItem<unknown>[] = [];\n private collapsedSections: Set<string> = new Set();\n private sectionBoundaries: Map<string, SectionBoundary> = new Map();\n private flatIndexToSection: Map<number, SectionBoundary> = new Map();\n\n private layoutPositioner: LinearLayoutPositioner;\n private layoutCache: LayoutCache;\n private horizontal: boolean;\n private hasSectionFooters: boolean;\n\n constructor(\n layoutCache: LayoutCache,\n options: {\n horizontal?: boolean;\n estimatedItemSize?: number;\n estimatedHeaderSize?: number;\n estimatedFooterSize?: number;\n hasSectionFooters?: boolean;\n } = {}\n ) {\n this.layoutCache = layoutCache;\n this.horizontal = options.horizontal ?? false;\n this.hasSectionFooters = options.hasSectionFooters ?? false;\n\n this.layoutPositioner = new LinearLayoutPositioner(\n layoutCache,\n (flatIndex) => this.getItemTypeForIndex(flatIndex),\n {\n horizontal: this.horizontal,\n estimatedItemSize: options.estimatedItemSize,\n estimatedHeaderSize: options.estimatedHeaderSize,\n estimatedFooterSize: options.estimatedFooterSize,\n }\n );\n }\n\n /**\n * Get the item type for a flat index (used by layout positioner).\n */\n private getItemTypeForIndex(flatIndex: number): string {\n const item = this.flattenedData[flatIndex];\n if (!item) return 'default';\n\n if (item.type === 'section-header') return '__section_header__';\n if (item.type === 'section-footer') return '__section_footer__';\n return 'default';\n }\n\n /**\n * Update sections and compute flattened data.\n */\n updateData(\n sections: Section<unknown>[],\n collapsedSections: Set<string>\n ): FlattenedItem<unknown>[] {\n this.sections = sections;\n this.collapsedSections = collapsedSections;\n\n this.flattenedData = [];\n this.sectionBoundaries.clear();\n this.flatIndexToSection.clear();\n\n let flatIndex = 0;\n\n for (let sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) {\n const section = sections[sectionIndex];\n const isCollapsed = collapsedSections.has(section.key);\n\n const boundary: SectionBoundary = {\n sectionIndex,\n sectionKey: section.key,\n headerFlatIndex: flatIndex,\n firstItemFlatIndex: -1,\n lastItemFlatIndex: -1,\n footerFlatIndex: null,\n itemCount: 0,\n };\n\n // Section header\n this.flattenedData.push({\n type: 'section-header',\n key: `header-${section.key}`,\n sectionKey: section.key,\n sectionIndex,\n itemIndex: -1,\n item: null,\n section,\n });\n this.flatIndexToSection.set(flatIndex, boundary);\n flatIndex++;\n\n // Section items (only if not collapsed)\n if (!isCollapsed) {\n boundary.firstItemFlatIndex = flatIndex;\n\n for (let itemIndex = 0; itemIndex < section.data.length; itemIndex++) {\n this.flattenedData.push({\n type: 'item',\n key: `item-${section.key}-${itemIndex}`,\n sectionKey: section.key,\n sectionIndex,\n itemIndex,\n item: section.data[itemIndex],\n section,\n });\n this.flatIndexToSection.set(flatIndex, boundary);\n flatIndex++;\n }\n\n boundary.lastItemFlatIndex = flatIndex - 1;\n boundary.itemCount = section.data.length;\n\n // Section footer (optional)\n if (this.hasSectionFooters) {\n boundary.footerFlatIndex = flatIndex;\n this.flattenedData.push({\n type: 'section-footer',\n key: `footer-${section.key}`,\n sectionKey: section.key,\n sectionIndex,\n itemIndex: -1,\n item: null,\n section,\n });\n this.flatIndexToSection.set(flatIndex, boundary);\n flatIndex++;\n }\n }\n\n this.sectionBoundaries.set(section.key, boundary);\n }\n\n // Update layout positioner with new data\n this.layoutPositioner.setData(this.flattenedData);\n\n return this.flattenedData;\n }\n\n /**\n * Get the flat index for a section/item coordinate.\n */\n getFlatIndex(sectionIndex: number, itemIndex: number): number {\n const section = this.sections[sectionIndex];\n if (!section) return -1;\n\n const boundary = this.sectionBoundaries.get(section.key);\n if (!boundary) return -1;\n\n if (itemIndex === -1) {\n // Return header index\n return boundary.headerFlatIndex;\n }\n\n if (this.collapsedSections.has(section.key)) {\n // Section is collapsed, items not in flattened data\n return -1;\n }\n\n if (itemIndex < 0 || itemIndex >= section.data.length) {\n return -1;\n }\n\n return boundary.firstItemFlatIndex + itemIndex;\n }\n\n /**\n * Get section/item coordinates from a flat index.\n */\n getSectionItemIndex(flatIndex: number): {\n sectionIndex: number;\n itemIndex: number;\n isHeader: boolean;\n isFooter: boolean;\n } {\n const item = this.flattenedData[flatIndex];\n if (!item) {\n return { sectionIndex: -1, itemIndex: -1, isHeader: false, isFooter: false };\n }\n\n return {\n sectionIndex: item.sectionIndex,\n itemIndex: item.itemIndex,\n isHeader: item.type === 'section-header',\n isFooter: item.type === 'section-footer',\n };\n }\n\n /**\n * Get layout info for a section.\n */\n getSectionLayout(sectionKey: string): SectionLayoutInfo | null {\n const boundary = this.sectionBoundaries.get(sectionKey);\n if (!boundary) return null;\n\n const headerLayout = this.layoutPositioner.getLayoutForIndex(boundary.headerFlatIndex);\n\n let footerLayout: LayoutRect | null = null;\n if (boundary.footerFlatIndex !== null) {\n footerLayout = this.layoutPositioner.getLayoutForIndex(boundary.footerFlatIndex);\n }\n\n // Calculate items offset range\n const isCollapsed = this.collapsedSections.has(sectionKey);\n let itemsStartOffset = this.horizontal ? headerLayout.x + headerLayout.width : headerLayout.y + headerLayout.height;\n let itemsEndOffset = itemsStartOffset;\n\n if (!isCollapsed && boundary.lastItemFlatIndex >= boundary.firstItemFlatIndex) {\n const lastItemLayout = this.layoutPositioner.getLayoutForIndex(boundary.lastItemFlatIndex);\n itemsEndOffset = this.horizontal\n ? lastItemLayout.x + lastItemLayout.width\n : lastItemLayout.y + lastItemLayout.height;\n }\n\n return {\n sectionKey,\n sectionIndex: boundary.sectionIndex,\n headerLayout,\n footerLayout,\n itemsStartOffset,\n itemsEndOffset,\n itemCount: boundary.itemCount,\n isCollapsed,\n };\n }\n\n /**\n * Get the section containing a given scroll offset.\n */\n getSectionAtOffset(offset: number): SectionLayoutInfo | null {\n for (const [sectionKey] of this.sectionBoundaries) {\n const layout = this.getSectionLayout(sectionKey);\n if (!layout) continue;\n\n const sectionStart = this.horizontal ? layout.headerLayout.x : layout.headerLayout.y;\n const sectionEnd = layout.itemsEndOffset;\n\n if (offset >= sectionStart && offset < sectionEnd) {\n return layout;\n }\n }\n\n return null;\n }\n\n /**\n * Get layout info for all sections.\n */\n getAllSectionLayouts(): SectionLayoutInfo[] {\n const layouts: SectionLayoutInfo[] = [];\n\n for (const [sectionKey] of this.sectionBoundaries) {\n const layout = this.getSectionLayout(sectionKey);\n if (layout) {\n layouts.push(layout);\n }\n }\n\n return layouts;\n }\n\n /**\n * Set a section's collapsed state.\n */\n setSectionCollapsed(sectionKey: string, collapsed: boolean): void {\n if (collapsed) {\n this.collapsedSections.add(sectionKey);\n } else {\n this.collapsedSections.delete(sectionKey);\n }\n\n // Re-flatten data with new collapsed state\n this.updateData(this.sections, this.collapsedSections);\n }\n\n /**\n * Check if a section is collapsed.\n */\n isSectionCollapsed(sectionKey: string): boolean {\n return this.collapsedSections.has(sectionKey);\n }\n\n /**\n * Get all collapsed sections.\n */\n getCollapsedSections(): Set<string> {\n return new Set(this.collapsedSections);\n }\n\n /**\n * Get the layout positioner for direct layout operations.\n */\n getLayoutPositioner(): LinearLayoutPositioner {\n return this.layoutPositioner;\n }\n}\n\n/**\n * Factory function to create a SectionLayoutManager.\n */\nexport function createSectionLayoutManager(\n layoutCache: LayoutCache,\n options?: {\n horizontal?: boolean;\n estimatedItemSize?: number;\n estimatedHeaderSize?: number;\n estimatedFooterSize?: number;\n hasSectionFooters?: boolean;\n }\n): SectionLayoutManager {\n return new SectionLayoutManagerImpl(layoutCache, options);\n}\n","import { useCallback, useRef, useMemo } from 'react';\nimport type { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';\nimport { SCROLL_VELOCITY_THRESHOLD } from '../constants';\n\ninterface ScrollState {\n offset: number;\n velocity: number;\n direction: 'forward' | 'backward' | 'idle';\n isScrolling: boolean;\n contentSize: number;\n viewportSize: number;\n}\n\ninterface UseScrollHandlerOptions {\n horizontal?: boolean;\n onScrollStateChange?: (state: ScrollState) => void;\n onEndReached?: (distanceFromEnd: number) => void;\n onEndReachedThreshold?: number;\n}\n\ninterface ScrollHandlerResult {\n scrollState: React.RefObject<ScrollState>;\n onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;\n onScrollBeginDrag: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;\n onScrollEndDrag: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;\n onMomentumScrollBegin: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;\n onMomentumScrollEnd: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;\n onContentSizeChange: (width: number, height: number) => void;\n}\n\n/**\n * Hook for tracking scroll state with velocity and direction detection.\n * Used for adaptive buffering and scroll optimization.\n */\nexport function useScrollHandler(options: UseScrollHandlerOptions = {}): ScrollHandlerResult {\n const {\n horizontal = false,\n onScrollStateChange,\n onEndReached,\n onEndReachedThreshold = 0.5,\n } = options;\n\n const scrollState = useRef<ScrollState>({\n offset: 0,\n velocity: 0,\n direction: 'idle',\n isScrolling: false,\n contentSize: 0,\n viewportSize: 0,\n });\n\n const lastOffset = useRef(0);\n const lastTimestamp = useRef(Date.now());\n const endReachedCalled = useRef(false);\n\n /**\n * Calculate velocity from consecutive scroll events.\n */\n const calculateVelocity = useCallback(\n (newOffset: number): number => {\n const now = Date.now();\n const timeDelta = now - lastTimestamp.current;\n\n if (timeDelta === 0) return scrollState.current.velocity;\n\n const offsetDelta = newOffset - lastOffset.current;\n const velocity = offsetDelta / timeDelta; // pixels per ms\n\n lastOffset.current = newOffset;\n lastTimestamp.current = now;\n\n return velocity;\n },\n []\n );\n\n /**\n * Determine scroll direction from velocity.\n */\n const getDirection = useCallback(\n (velocity: number): 'forward' | 'backward' | 'idle' => {\n if (Math.abs(velocity) < 0.1) return 'idle';\n return velocity > 0 ? 'forward' : 'backward';\n },\n []\n );\n\n /**\n * Check if we've reached the end and should trigger callback.\n */\n const checkEndReached = useCallback(() => {\n if (!onEndReached) return;\n\n const { offset, contentSize, viewportSize } = scrollState.current;\n const distanceFromEnd = contentSize - offset - viewportSize;\n const threshold = viewportSize * onEndReachedThreshold;\n\n if (distanceFromEnd <= threshold && !endReachedCalled.current) {\n endReachedCalled.current = true;\n onEndReached(distanceFromEnd);\n } else if (distanceFromEnd > threshold) {\n // Reset when scrolled away from end\n endReachedCalled.current = false;\n }\n }, [onEndReached, onEndReachedThreshold]);\n\n /**\n * Update scroll state and notify listeners.\n */\n const updateScrollState = useCallback(\n (event: NativeScrollEvent, isScrolling: boolean) => {\n const { contentOffset, contentSize, layoutMeasurement } = event;\n\n const offset = horizontal ? contentOffset.x : contentOffset.y;\n const size = horizontal ? contentSize.width : contentSize.height;\n const viewport = horizontal ? layoutMeasurement.width : layoutMeasurement.height;\n\n const velocity = calculateVelocity(offset);\n const direction = getDirection(velocity);\n\n scrollState.current = {\n offset,\n velocity,\n direction,\n isScrolling,\n contentSize: size,\n viewportSize: viewport,\n };\n\n onScrollStateChange?.(scrollState.current);\n checkEndReached();\n },\n [horizontal, calculateVelocity, getDirection, onScrollStateChange, checkEndReached]\n );\n\n const onScroll = useCallback(\n (event: NativeSyntheticEvent<NativeScrollEvent>) => {\n updateScrollState(event.nativeEvent, scrollState.current.isScrolling);\n },\n [updateScrollState]\n );\n\n const onScrollBeginDrag = useCallback(\n (event: NativeSyntheticEvent<NativeScrollEvent>) => {\n scrollState.current.isScrolling = true;\n updateScrollState(event.nativeEvent, true);\n },\n [updateScrollState]\n );\n\n const onScrollEndDrag = useCallback(\n (event: NativeSyntheticEvent<NativeScrollEvent>) => {\n // Scrolling might continue with momentum\n updateScrollState(event.nativeEvent, scrollState.current.isScrolling);\n },\n [updateScrollState]\n );\n\n const onMomentumScrollBegin = useCallback(\n (event: NativeSyntheticEvent<NativeScrollEvent>) => {\n scrollState.current.isScrolling = true;\n updateScrollState(event.nativeEvent, true);\n },\n [updateScrollState]\n );\n\n const onMomentumScrollEnd = useCallback(\n (event: NativeSyntheticEvent<NativeScrollEvent>) => {\n scrollState.current.isScrolling = false;\n scrollState.current.direction = 'idle';\n scrollState.current.velocity = 0;\n updateScrollState(event.nativeEvent, false);\n },\n [updateScrollState]\n );\n\n const onContentSizeChange = useCallback((width: number, height: number) => {\n scrollState.current.contentSize = horizontal ? width : height;\n }, [horizontal]);\n\n return {\n scrollState,\n onScroll,\n onScrollBeginDrag,\n onScrollEndDrag,\n onMomentumScrollBegin,\n onMomentumScrollEnd,\n onContentSizeChange,\n };\n}\n\n/**\n * Hook to calculate adaptive draw distance based on scroll velocity.\n * Increases buffer for fast scrolling to reduce blank areas.\n */\nexport function useAdaptiveDrawDistance(\n baseDistance: number,\n scrollVelocity: number\n): number {\n return useMemo(() => {\n const absVelocity = Math.abs(scrollVelocity);\n\n if (absVelocity < SCROLL_VELOCITY_THRESHOLD) {\n return baseDistance;\n }\n\n // Scale draw distance with velocity (max 3x for very fast scrolling)\n const velocityMultiplier = Math.min(3, 1 + absVelocity / SCROLL_VELOCITY_THRESHOLD);\n return Math.round(baseDistance * velocityMultiplier);\n }, [baseDistance, scrollVelocity]);\n}\n","import type { CellRecyclerInterface, RecycledCell, RecyclePool } from '../types';\nimport { DEFAULT_MAX_POOL_SIZE } from '../constants';\n\n/**\n * CellRecycler manages pools of recycled cell instances per item type.\n * This is the core of FlashList-style performance - reusing view components\n * instead of destroying and recreating them.\n */\nclass CellRecyclerImpl implements CellRecyclerInterface {\n private pools: Map<string, RecyclePool> = new Map();\n private inUse: Map<string, Set<string>> = new Map(); // type -> set of cell keys in use\n private defaultMaxPoolSize: number;\n private cellCounter = 0;\n\n constructor(defaultMaxPoolSize: number = DEFAULT_MAX_POOL_SIZE) {\n this.defaultMaxPoolSize = defaultMaxPoolSize;\n }\n\n /**\n * Acquire a cell from the pool for the given type.\n * Returns null if no recycled cells are available (caller should create new).\n */\n acquireCell(type: string, flatIndex: number): RecycledCell | null {\n const pool = this.pools.get(type);\n\n if (!pool || pool.cells.length === 0) {\n // No recycled cells available\n return null;\n }\n\n // Pop a cell from the pool\n const cell = pool.cells.pop()!;\n cell.flatIndex = flatIndex;\n\n // Track as in use\n let inUseSet = this.inUse.get(type);\n if (!inUseSet) {\n inUseSet = new Set();\n this.inUse.set(type, inUseSet);\n }\n inUseSet.add(cell.key);\n\n return cell;\n }\n\n /**\n * Release a cell back to its pool for recycling.\n */\n releaseCell(cell: RecycledCell): void {\n const { itemType: type, key } = cell;\n\n // Remove from in-use tracking\n const inUseSet = this.inUse.get(type);\n if (inUseSet) {\n inUseSet.delete(key);\n }\n\n // Get or create pool for this type\n let pool = this.pools.get(type);\n if (!pool) {\n pool = {\n type,\n cells: [],\n maxSize: this.defaultMaxPoolSize,\n };\n this.pools.set(type, pool);\n }\n\n // Only add to pool if under max size\n if (pool.cells.length < pool.maxSize) {\n pool.cells.push(cell);\n }\n // If at max size, the cell is discarded (GC'd)\n }\n\n /**\n * Clear all recycled cells from all pools.\n * Useful when data changes significantly.\n */\n clearPools(): void {\n this.pools.clear();\n this.inUse.clear();\n }\n\n /**\n * Set the maximum pool size for a specific item type.\n */\n setMaxPoolSize(type: string, size: number): void {\n let pool = this.pools.get(type);\n if (!pool) {\n pool = {\n type,\n cells: [],\n maxSize: size,\n };\n this.pools.set(type, pool);\n } else {\n pool.maxSize = size;\n // Trim pool if necessary\n while (pool.cells.length > size) {\n pool.cells.pop();\n }\n }\n }\n\n /**\n * Get statistics about pool usage for debugging.\n */\n getPoolStats(): Map<string, { available: number; inUse: number }> {\n const stats = new Map<string, { available: number; inUse: number }>();\n\n // Collect all known types\n const allTypes = new Set([...this.pools.keys(), ...this.inUse.keys()]);\n\n for (const type of allTypes) {\n const pool = this.pools.get(type);\n const inUseSet = this.inUse.get(type);\n\n stats.set(type, {\n available: pool?.cells.length ?? 0,\n inUse: inUseSet?.size ?? 0,\n });\n }\n\n return stats;\n }\n\n /**\n * Generate a unique key for a new cell.\n */\n generateCellKey(type: string): string {\n return `${type}-${++this.cellCounter}`;\n }\n\n /**\n * Create a new cell (when pool is empty).\n */\n createCell(type: string, flatIndex: number): RecycledCell {\n const key = this.generateCellKey(type);\n const cell: RecycledCell = {\n key,\n itemType: type,\n flatIndex,\n };\n\n // Track as in use\n let inUseSet = this.inUse.get(type);\n if (!inUseSet) {\n inUseSet = new Set();\n this.inUse.set(type, inUseSet);\n }\n inUseSet.add(key);\n\n return cell;\n }\n\n /**\n * Get or create a cell - the main method used during rendering.\n * First tries to acquire from pool, then creates new if needed.\n */\n getCell(type: string, flatIndex: number): RecycledCell {\n const recycled = this.acquireCell(type, flatIndex);\n if (recycled) {\n return recycled;\n }\n return this.createCell(type, flatIndex);\n }\n}\n\n/**\n * Factory function to create a CellRecycler instance.\n */\nexport function createCellRecycler(\n defaultMaxPoolSize: number = DEFAULT_MAX_POOL_SIZE\n): CellRecyclerImpl {\n return new CellRecyclerImpl(defaultMaxPoolSize);\n}\n\nexport type { CellRecyclerImpl };\n","import { useCallback, useRef, useMemo, useEffect } from 'react';\nimport { createCellRecycler, type CellRecyclerImpl } from '../core/CellRecycler';\nimport type { RecycledCell, FlattenedItem } from '../types';\nimport { DEFAULT_ITEM_TYPE, SECTION_HEADER_TYPE, SECTION_FOOTER_TYPE } from '../constants';\n\ninterface UseRecyclerOptions<TItem> {\n flattenedData: FlattenedItem<TItem>[];\n getItemType?: (item: TItem, index: number) => string;\n maxPoolSize?: number;\n}\n\ninterface RecyclerResult {\n getCell: (flatIndex: number) => RecycledCell;\n releaseCell: (cell: RecycledCell) => void;\n updateVisibleRange: (startIndex: number, endIndex: number) => void;\n clearPools: () => void;\n getPoolStats: () => Map<string, { available: number; inUse: number }>;\n}\n\n/**\n * Hook for managing cell recycling state.\n * Provides methods to acquire and release cells based on visibility.\n */\nexport function useRecycler<TItem>(options: UseRecyclerOptions<TItem>): RecyclerResult {\n const { flattenedData, getItemType, maxPoolSize } = options;\n\n // Create recycler instance (stable across renders)\n const recycler = useRef<CellRecyclerImpl | null>(null);\n if (!recycler.current) {\n recycler.current = createCellRecycler(maxPoolSize);\n }\n\n // Track currently rendered cells\n const activeCells = useRef<Map<number, RecycledCell>>(new Map());\n const visibleRange = useRef<{ start: number; end: number }>({ start: 0, end: -1 });\n\n /**\n * Get the item type for a flat index.\n */\n const getTypeForIndex = useCallback(\n (flatIndex: number): string => {\n const item = flattenedData[flatIndex];\n if (!item) return DEFAULT_ITEM_TYPE;\n\n if (item.type === 'section-header') return SECTION_HEADER_TYPE;\n if (item.type === 'section-footer') return SECTION_FOOTER_TYPE;\n\n if (getItemType && item.item !== null) {\n return getItemType(item.item, item.itemIndex);\n }\n\n return DEFAULT_ITEM_TYPE;\n },\n [flattenedData, getItemType]\n );\n\n /**\n * Get or create a cell for a flat index.\n */\n const getCell = useCallback(\n (flatIndex: number): RecycledCell => {\n // Check if already have an active cell for this index\n const existing = activeCells.current.get(flatIndex);\n if (existing) {\n return existing;\n }\n\n // Get type for this index\n const type = getTypeForIndex(flatIndex);\n\n // Get cell from recycler (may be recycled or new)\n const cell = recycler.current!.getCell(type, flatIndex);\n\n // Track as active\n activeCells.current.set(flatIndex, cell);\n\n return cell;\n },\n [getTypeForIndex]\n );\n\n /**\n * Release a cell back to the pool.\n */\n const releaseCell = useCallback((cell: RecycledCell) => {\n activeCells.current.delete(cell.flatIndex);\n recycler.current!.releaseCell(cell);\n }, []);\n\n /**\n * Update the visible range and recycle cells outside it.\n */\n const updateVisibleRange = useCallback(\n (startIndex: number, endIndex: number) => {\n const prevStart = visibleRange.current.start;\n const prevEnd = visibleRange.current.end;\n\n visibleRange.current = { start: startIndex, end: endIndex };\n\n // Release cells that are now outside visible range\n for (const [flatIndex, cell] of activeCells.current) {\n if (flatIndex < startIndex || flatIndex > endIndex) {\n releaseCell(cell);\n }\n }\n },\n [releaseCell]\n );\n\n /**\n * Clear all pools (e.g., on data change).\n */\n const clearPools = useCallback(() => {\n activeCells.current.clear();\n recycler.current!.clearPools();\n }, []);\n\n /**\n * Get pool statistics for debugging.\n */\n const getPoolStats = useCallback(() => {\n return recycler.current!.getPoolStats();\n }, []);\n\n // Clear pools when data changes significantly\n const dataLength = flattenedData.length;\n useEffect(() => {\n // If data length changes dramatically, clear pools\n if (activeCells.current.size > dataLength * 2) {\n clearPools();\n }\n }, [dataLength, clearPools]);\n\n return {\n getCell,\n releaseCell,\n updateVisibleRange,\n clearPools,\n getPoolStats,\n };\n}\n\n/**\n * Hook to determine which item type to use for rendering.\n * Returns a stable function that maps flat indices to type strings.\n */\nexport function useItemTypeResolver<TItem>(\n flattenedData: FlattenedItem<TItem>[],\n getItemType?: (item: TItem, index: number) => string\n): (flatIndex: number) => string {\n return useCallback(\n (flatIndex: number): string => {\n const item = flattenedData[flatIndex];\n if (!item) return DEFAULT_ITEM_TYPE;\n\n if (item.type === 'section-header') return SECTION_HEADER_TYPE;\n if (item.type === 'section-footer') return SECTION_FOOTER_TYPE;\n\n if (getItemType && item.item !== null) {\n return getItemType(item.item, item.itemIndex);\n }\n\n return DEFAULT_ITEM_TYPE;\n },\n [flattenedData, getItemType]\n );\n}\n","import { useMemo, useRef, useCallback } from 'react';\nimport type { SectionLayoutInfo, LayoutRect } from '../types';\n\ninterface StickyHeaderState {\n sectionKey: string | null;\n sectionIndex: number;\n translateY: number;\n isSticky: boolean;\n headerLayout: LayoutRect | null;\n}\n\ninterface UseStickyHeaderOptions {\n sectionLayouts: SectionLayoutInfo[];\n scrollOffset: number;\n viewportHeight: number;\n horizontal?: boolean;\n enabled?: boolean;\n}\n\n/**\n * Hook for computing sticky header positioning.\n * Handles the \"pushing\" effect when the next section header approaches.\n */\nexport function useStickyHeader(options: UseStickyHeaderOptions): StickyHeaderState {\n const { sectionLayouts, scrollOffset, viewportHeight, horizontal = false, enabled = true } = options;\n\n return useMemo(() => {\n if (!enabled || sectionLayouts.length === 0) {\n return {\n sectionKey: null,\n sectionIndex: -1,\n translateY: 0,\n isSticky: false,\n headerLayout: null,\n };\n }\n\n // Find the section whose header should be sticky\n // This is the last section whose header has scrolled past the top\n let currentSection: SectionLayoutInfo | null = null;\n let nextSection: SectionLayoutInfo | null = null;\n\n for (let i = 0; i < sectionLayouts.length; i++) {\n const section = sectionLayouts[i];\n const headerStart = horizontal ? section.headerLayout.x : section.headerLayout.y;\n\n if (headerStart <= scrollOffset) {\n currentSection = section;\n nextSection = sectionLayouts[i + 1] ?? null;\n } else {\n break;\n }\n }\n\n if (!currentSection) {\n return {\n sectionKey: null,\n sectionIndex: -1,\n translateY: 0,\n isSticky: false,\n headerLayout: null,\n };\n }\n\n const headerSize = horizontal\n ? currentSection.headerLayout.width\n : currentSection.headerLayout.height;\n\n // Calculate push offset if next section is approaching\n let translateY = 0;\n\n if (nextSection) {\n const nextHeaderStart = horizontal\n ? nextSection.headerLayout.x\n : nextSection.headerLayout.y;\n\n const pushPoint = nextHeaderStart - headerSize;\n\n if (scrollOffset > pushPoint) {\n // Push the current header up as next section approaches\n translateY = pushPoint - scrollOffset;\n }\n }\n\n return {\n sectionKey: currentSection.sectionKey,\n sectionIndex: currentSection.sectionIndex,\n translateY,\n isSticky: true,\n headerLayout: currentSection.headerLayout,\n };\n }, [sectionLayouts, scrollOffset, viewportHeight, horizontal, enabled]);\n}\n\n/**\n * Hook for tracking multiple sticky headers (e.g., for multi-level sections).\n */\nexport function useMultipleStickyHeaders(\n sectionLayouts: SectionLayoutInfo[],\n scrollOffset: number,\n levels: number = 1\n): StickyHeaderState[] {\n return useMemo(() => {\n // For now, just return single sticky header in array\n // Future: support nested section levels\n const states: StickyHeaderState[] = [];\n\n if (sectionLayouts.length === 0) {\n return states;\n }\n\n let currentSection: SectionLayoutInfo | null = null;\n let nextSection: SectionLayoutInfo | null = null;\n\n for (let i = 0; i < sectionLayouts.length; i++) {\n const section = sectionLayouts[i];\n const headerStart = section.headerLayout.y;\n\n if (headerStart <= scrollOffset) {\n currentSection = section;\n nextSection = sectionLayouts[i + 1] ?? null;\n } else {\n break;\n }\n }\n\n if (currentSection) {\n const headerSize = currentSection.headerLayout.height;\n let translateY = 0;\n\n if (nextSection) {\n const nextHeaderStart = nextSection.headerLayout.y;\n const pushPoint = nextHeaderStart - headerSize;\n\n if (scrollOffset > pushPoint) {\n translateY = pushPoint - scrollOffset;\n }\n }\n\n states.push({\n sectionKey: currentSection.sectionKey,\n sectionIndex: currentSection.sectionIndex,\n translateY,\n isSticky: true,\n headerLayout: currentSection.headerLayout,\n });\n }\n\n return states;\n }, [sectionLayouts, scrollOffset, levels]);\n}\n\n/**\n * Hook for determining sticky header opacity during transitions.\n */\nexport function useStickyHeaderOpacity(\n stickyState: StickyHeaderState,\n fadeDistance: number = 20\n): number {\n return useMemo(() => {\n if (!stickyState.isSticky) return 0;\n if (stickyState.translateY >= 0) return 1;\n\n // Fade out as header is pushed up\n const fadeProgress = Math.abs(stickyState.translateY) / fadeDistance;\n return Math.max(0, 1 - fadeProgress);\n }, [stickyState.isSticky, stickyState.translateY, fadeDistance]);\n}\n","import type {\n ViewToken,\n ViewabilityConfig,\n FlattenedItem,\n LayoutPositioner,\n} from '../types';\nimport { DEFAULT_VIEWABILITY_CONFIG } from '../constants';\n\n/**\n * ViewabilityTracker monitors which items are currently visible in the viewport\n * and triggers callbacks when viewability changes.\n */\nexport interface ViewabilityTracker<TItem> {\n updateScrollOffset(offset: number): void;\n setViewportSize(size: number): void;\n setData(flattenedData: FlattenedItem<TItem>[]): void;\n getVisibleIndices(): number[];\n isIndexVisible(index: number): boolean;\n getFirstVisibleIndex(): number;\n getLastVisibleIndex(): number;\n onViewableItemsChanged(\n callback: (info: { viewableItems: ViewToken<TItem>[]; changed: ViewToken<TItem>[] }) => void\n ): () => void;\n recordInteraction(): void;\n dispose(): void;\n}\n\ninterface TrackedItem {\n flatIndex: number;\n isViewable: boolean;\n lastVisibleTime: number;\n becameVisibleAt: number | null;\n}\n\nclass ViewabilityTrackerImpl<TItem> implements ViewabilityTracker<TItem> {\n private config: Required<ViewabilityConfig>;\n private layoutPositioner: LayoutPositioner;\n private flattenedData: FlattenedItem<TItem>[] = [];\n private horizontal: boolean;\n\n private scrollOffset = 0;\n private viewportSize = 0;\n\n private trackedItems: Map<number, TrackedItem> = new Map();\n private currentlyViewable: Set<number> = new Set();\n private callbacks: Set<(info: { viewableItems: ViewToken<TItem>[]; changed: ViewToken<TItem>[] }) => void> = new Set();\n\n private hasInteracted = false;\n private pendingUpdate: ReturnType<typeof setTimeout> | null = null;\n\n constructor(\n layoutPositioner: LayoutPositioner,\n flattenedData: FlattenedItem<TItem>[],\n config: ViewabilityConfig = {},\n horizontal = false\n ) {\n this.layoutPositioner = layoutPositioner;\n this.flattenedData = flattenedData;\n this.horizontal = horizontal;\n\n this.config = {\n minimumViewTime: config.minimumViewTime ?? DEFAULT_VIEWABILITY_CONFIG.minimumViewTime,\n viewAreaCoveragePercentThreshold:\n config.viewAreaCoveragePercentThreshold ?? DEFAULT_VIEWABILITY_CONFIG.viewAreaCoveragePercentThreshold,\n itemVisiblePercentThreshold:\n config.itemVisiblePercentThreshold ?? DEFAULT_VIEWABILITY_CONFIG.itemVisiblePercentThreshold,\n waitForInteraction: config.waitForInteraction ?? DEFAULT_VIEWABILITY_CONFIG.waitForInteraction,\n };\n }\n\n /**\n * Update flattened data when it changes.\n */\n setData(flattenedData: FlattenedItem<TItem>[]): void {\n this.flattenedData = flattenedData;\n // Reset tracking for new data\n this.trackedItems.clear();\n this.currentlyViewable.clear();\n this.scheduleUpdate();\n }\n\n /**\n * Update the current scroll offset.\n */\n updateScrollOffset(offset: number): void {\n this.scrollOffset = offset;\n this.scheduleUpdate();\n }\n\n /**\n * Update the viewport size.\n */\n setViewportSize(size: number): void {\n if (this.viewportSize !== size) {\n this.viewportSize = size;\n this.scheduleUpdate();\n }\n }\n\n /**\n * Record that user has interacted with the list.\n */\n recordInteraction(): void {\n if (!this.hasInteracted) {\n this.hasInteracted = true;\n this.scheduleUpdate();\n }\n }\n\n /**\n * Schedule a viewability update (debounced).\n */\n private scheduleUpdate(): void {\n if (this.pendingUpdate) {\n return; // Already scheduled\n }\n\n this.pendingUpdate = setTimeout(() => {\n this.pendingUpdate = null;\n this.computeViewability();\n }, 0);\n }\n\n /**\n * Compute which items are viewable based on current scroll position.\n */\n private computeViewability(): void {\n if (this.config.waitForInteraction && !this.hasInteracted) {\n return;\n }\n\n const now = Date.now();\n const newViewable = new Set<number>();\n const changed: ViewToken<TItem>[] = [];\n\n // Get visible range from layout positioner\n const { startIndex, endIndex } = this.layoutPositioner.getVisibleRange(\n this.scrollOffset,\n this.viewportSize,\n 0 // No overscan for viewability calculation\n );\n\n // Check each item in visible range\n for (let i = startIndex; i <= endIndex; i++) {\n const layout = this.layoutPositioner.getLayoutForIndex(i);\n const isViewable = this.isItemViewable(i, layout);\n\n if (isViewable) {\n newViewable.add(i);\n\n // Track when item became visible\n let tracked = this.trackedItems.get(i);\n if (!tracked) {\n tracked = {\n flatIndex: i,\n isViewable: false,\n lastVisibleTime: now,\n becameVisibleAt: now,\n };\n this.trackedItems.set(i, tracked);\n }\n\n // Check if item meets minimum view time\n if (!tracked.isViewable && tracked.becameVisibleAt !== null) {\n const visibleDuration = now - tracked.becameVisibleAt;\n if (visibleDuration >= this.config.minimumViewTime) {\n tracked.isViewable = true;\n changed.push(this.createViewToken(i, true));\n }\n }\n\n tracked.lastVisibleTime = now;\n }\n }\n\n // Check for items that are no longer viewable\n for (const flatIndex of this.currentlyViewable) {\n if (!newViewable.has(flatIndex)) {\n const tracked = this.trackedItems.get(flatIndex);\n if (tracked && tracked.isViewable) {\n tracked.isViewable = false;\n tracked.becameVisibleAt = null;\n changed.push(this.createViewToken(flatIndex, false));\n }\n }\n }\n\n this.currentlyViewable = newViewable;\n\n // Notify callbacks if there are changes\n if (changed.length > 0) {\n const viewableItems = Array.from(this.currentlyViewable)\n .filter(i => this.trackedItems.get(i)?.isViewable)\n .map(i => this.createViewToken(i, true));\n\n for (const callback of this.callbacks) {\n callback({ viewableItems, changed });\n }\n }\n }\n\n /**\n * Check if an item meets viewability thresholds.\n */\n private isItemViewable(\n flatIndex: number,\n layout: { x: number; y: number; width: number; height: number }\n ): boolean {\n const itemStart = this.horizontal ? layout.x : layout.y;\n const itemSize = this.horizontal ? layout.width : layout.height;\n const itemEnd = itemStart + itemSize;\n\n const viewportStart = this.scrollOffset;\n const viewportEnd = this.scrollOffset + this.viewportSize;\n\n // Calculate visible portion\n const visibleStart = Math.max(itemStart, viewportStart);\n const visibleEnd = Math.min(itemEnd, viewportEnd);\n const visibleSize = Math.max(0, visibleEnd - visibleStart);\n\n // Check item visible percent threshold\n if (this.config.itemVisiblePercentThreshold > 0) {\n const visiblePercent = itemSize > 0 ? (visibleSize / itemSize) * 100 : 0;\n if (visiblePercent < this.config.itemVisiblePercentThreshold) {\n return false;\n }\n }\n\n // Check view area coverage threshold\n if (this.config.viewAreaCoveragePercentThreshold > 0) {\n const coveragePercent = this.viewportSize > 0 ? (visibleSize / this.viewportSize) * 100 : 0;\n if (coveragePercent < this.config.viewAreaCoveragePercentThreshold) {\n return false;\n }\n }\n\n return visibleSize > 0;\n }\n\n /**\n * Create a ViewToken for an item.\n */\n private createViewToken(flatIndex: number, isViewable: boolean): ViewToken<TItem> {\n const item = this.flattenedData[flatIndex];\n return {\n item: item?.item ?? null,\n key: item?.key ?? `item-${flatIndex}`,\n index: flatIndex,\n isViewable,\n section: item?.section as any,\n };\n }\n\n /**\n * Get all currently visible indices.\n */\n getVisibleIndices(): number[] {\n return Array.from(this.currentlyViewable);\n }\n\n /**\n * Check if a specific index is visible.\n */\n isIndexVisible(index: number): boolean {\n return this.currentlyViewable.has(index);\n }\n\n /**\n * Get the first visible index.\n */\n getFirstVisibleIndex(): number {\n if (this.currentlyViewable.size === 0) {\n return -1;\n }\n return Math.min(...this.currentlyViewable);\n }\n\n /**\n * Get the last visible index.\n */\n getLastVisibleIndex(): number {\n if (this.currentlyViewable.size === 0) {\n return -1;\n }\n return Math.max(...this.currentlyViewable);\n }\n\n /**\n * Register a callback for viewability changes.\n */\n onViewableItemsChanged(\n callback: (info: { viewableItems: ViewToken<TItem>[]; changed: ViewToken<TItem>[] }) => void\n ): () => void {\n this.callbacks.add(callback);\n return () => {\n this.callbacks.delete(callback);\n };\n }\n\n /**\n * Clean up resources.\n */\n dispose(): void {\n if (this.pendingUpdate) {\n clearTimeout(this.pendingUpdate);\n this.pendingUpdate = null;\n }\n this.callbacks.clear();\n this.trackedItems.clear();\n this.currentlyViewable.clear();\n }\n}\n\n/**\n * Factory function to create a ViewabilityTracker.\n */\nexport function createViewabilityTracker<TItem>(\n layoutPositioner: LayoutPositioner,\n flattenedData: FlattenedItem<TItem>[],\n config?: ViewabilityConfig,\n horizontal?: boolean\n): ViewabilityTracker<TItem> {\n return new ViewabilityTrackerImpl(layoutPositioner, flattenedData, config, horizontal);\n}\n","import { useEffect, useRef, useCallback, useMemo } from 'react';\nimport type { ViewToken, ViewabilityConfig, FlattenedItem, LayoutPositioner } from '../types';\nimport { createViewabilityTracker, type ViewabilityTracker } from '../core/ViewabilityTracker';\nimport { DEFAULT_VIEWABILITY_CONFIG } from '../constants';\n\ninterface UseViewabilityOptions<TItem> {\n flattenedData: FlattenedItem<TItem>[];\n layoutPositioner: LayoutPositioner;\n scrollOffset: number;\n viewportSize: number;\n horizontal?: boolean;\n viewabilityConfig?: ViewabilityConfig;\n onViewableItemsChanged?: (info: {\n viewableItems: ViewToken<TItem>[];\n changed: ViewToken<TItem>[];\n }) => void;\n}\n\ninterface ViewabilityResult<TItem> {\n visibleIndices: number[];\n firstVisibleIndex: number;\n lastVisibleIndex: number;\n getVisibleItems: () => ViewToken<TItem>[];\n recordInteraction: () => void;\n}\n\n/**\n * Hook for tracking item viewability and triggering callbacks.\n */\nexport function useViewability<TItem>(\n options: UseViewabilityOptions<TItem>\n): ViewabilityResult<TItem> {\n const {\n flattenedData,\n layoutPositioner,\n scrollOffset,\n viewportSize,\n horizontal = false,\n viewabilityConfig = DEFAULT_VIEWABILITY_CONFIG,\n onViewableItemsChanged,\n } = options;\n\n // Create tracker instance\n const trackerRef = useRef<ViewabilityTracker<TItem> | null>(null);\n\n // Initialize tracker\n if (!trackerRef.current) {\n trackerRef.current = createViewabilityTracker(\n layoutPositioner,\n flattenedData,\n viewabilityConfig,\n horizontal\n );\n }\n\n const tracker = trackerRef.current;\n\n // Update tracker when data changes\n useEffect(() => {\n tracker.setData(flattenedData);\n }, [tracker, flattenedData]);\n\n // Update viewport size\n useEffect(() => {\n tracker.setViewportSize(viewportSize);\n }, [tracker, viewportSize]);\n\n // Update scroll offset\n useEffect(() => {\n tracker.updateScrollOffset(scrollOffset);\n }, [tracker, scrollOffset]);\n\n // Register callback\n useEffect(() => {\n if (!onViewableItemsChanged) return;\n\n const unsubscribe = tracker.onViewableItemsChanged(onViewableItemsChanged);\n return unsubscribe;\n }, [tracker, onViewableItemsChanged]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n tracker.dispose();\n };\n }, [tracker]);\n\n const recordInteraction = useCallback(() => {\n tracker.recordInteraction();\n }, [tracker]);\n\n const getVisibleItems = useCallback((): ViewToken<TItem>[] => {\n return tracker.getVisibleIndices().map((flatIndex) => {\n const item = flattenedData[flatIndex];\n return {\n item: item?.item ?? null,\n key: item?.key ?? `item-${flatIndex}`,\n index: flatIndex,\n isViewable: true,\n section: item?.section as any,\n };\n });\n }, [tracker, flattenedData]);\n\n // Compute visible indices\n const visibleState = useMemo(() => {\n const indices = tracker.getVisibleIndices();\n return {\n visibleIndices: indices,\n firstVisibleIndex: tracker.getFirstVisibleIndex(),\n lastVisibleIndex: tracker.getLastVisibleIndex(),\n };\n }, [tracker, scrollOffset, viewportSize]);\n\n return {\n ...visibleState,\n getVisibleItems,\n recordInteraction,\n };\n}\n\n/**\n * Hook for handling multiple viewability configs with different callbacks.\n */\nexport function useMultipleViewabilityConfigs<TItem>(\n flattenedData: FlattenedItem<TItem>[],\n layoutPositioner: LayoutPositioner,\n scrollOffset: number,\n viewportSize: number,\n configs: Array<{\n viewabilityConfig: ViewabilityConfig;\n onViewableItemsChanged: (info: {\n viewableItems: ViewToken<TItem>[];\n changed: ViewToken<TItem>[];\n }) => void;\n }>,\n horizontal = false\n): void {\n const trackersRef = useRef<ViewabilityTracker<TItem>[]>([]);\n\n // Initialize trackers for each config\n useEffect(() => {\n trackersRef.current = configs.map((config) =>\n createViewabilityTracker(\n layoutPositioner,\n flattenedData,\n config.viewabilityConfig,\n horizontal\n )\n );\n\n // Register callbacks\n const unsubscribes = trackersRef.current.map((tracker, index) =>\n tracker.onViewableItemsChanged(configs[index].onViewableItemsChanged)\n );\n\n return () => {\n unsubscribes.forEach((unsub) => unsub());\n trackersRef.current.forEach((tracker) => tracker.dispose());\n trackersRef.current = [];\n };\n }, [configs, flattenedData, layoutPositioner, horizontal]);\n\n // Update data\n useEffect(() => {\n trackersRef.current.forEach((tracker) => tracker.setData(flattenedData));\n }, [flattenedData]);\n\n // Update viewport\n useEffect(() => {\n trackersRef.current.forEach((tracker) => tracker.setViewportSize(viewportSize));\n }, [viewportSize]);\n\n // Update scroll\n useEffect(() => {\n trackersRef.current.forEach((tracker) => tracker.updateScrollOffset(scrollOffset));\n }, [scrollOffset]);\n}\n","import React, { createContext, useContext, useMemo, useRef, useCallback } from 'react';\nimport type {\n Section,\n FlattenedItem,\n LayoutRect,\n SectionFlowProps,\n RenderItemInfo,\n RenderSectionHeaderInfo,\n RenderSectionFooterInfo,\n} from '../types';\nimport type { SectionLayoutManager } from '../core/SectionLayoutManager';\nimport type { LayoutCache } from '../core/LayoutCache';\n\n/**\n * Internal context value for SectionFlow components.\n */\ninterface SectionFlowContextValue<TItem> {\n // Data\n sections: Section<TItem>[];\n flattenedData: FlattenedItem<TItem>[];\n\n // Layout\n layoutManager: SectionLayoutManager;\n layoutCache: LayoutCache;\n horizontal: boolean;\n\n // State\n collapsedSections: Set<string>;\n scrollOffset: number;\n viewportWidth: number;\n viewportHeight: number;\n\n // Config\n stickySectionHeadersEnabled: boolean;\n estimatedItemSize: number;\n drawDistance: number;\n debug: boolean;\n\n // Render functions\n renderItem: (info: RenderItemInfo<TItem>) => React.ReactElement | null;\n renderSectionHeader?: (info: RenderSectionHeaderInfo<TItem>) => React.ReactElement | null;\n renderSectionFooter?: (info: RenderSectionFooterInfo<TItem>) => React.ReactElement | null;\n\n // Callbacks\n onCellMeasured: (key: string, flatIndex: number, layout: LayoutRect) => void;\n onSectionToggle?: (sectionKey: string, collapsed: boolean) => void;\n\n // Item type resolution\n getItemType: (flatIndex: number) => string;\n}\n\n// Create context with undefined default (will always be provided by SectionFlowProvider)\nconst SectionFlowContext = createContext<SectionFlowContextValue<unknown> | undefined>(undefined);\n\n/**\n * Hook to access SectionFlow context.\n * Must be used within a SectionFlowProvider.\n */\nexport function useSectionFlowContext<TItem>(): SectionFlowContextValue<TItem> {\n const context = useContext(SectionFlowContext);\n if (!context) {\n throw new Error('useSectionFlowContext must be used within a SectionFlowProvider');\n }\n return context as SectionFlowContextValue<TItem>;\n}\n\ninterface SectionFlowProviderProps<TItem> {\n children: React.ReactNode;\n sections: Section<TItem>[];\n flattenedData: FlattenedItem<TItem>[];\n layoutManager: SectionLayoutManager;\n layoutCache: LayoutCache;\n horizontal: boolean;\n collapsedSections: Set<string>;\n scrollOffset: number;\n viewportWidth: number;\n viewportHeight: number;\n stickySectionHeadersEnabled: boolean;\n estimatedItemSize: number;\n drawDistance: number;\n debug: boolean;\n renderItem: (info: RenderItemInfo<TItem>) => React.ReactElement | null;\n renderSectionHeader?: (info: RenderSectionHeaderInfo<TItem>) => React.ReactElement | null;\n renderSectionFooter?: (info: RenderSectionFooterInfo<TItem>) => React.ReactElement | null;\n onCellMeasured: (key: string, flatIndex: number, layout: LayoutRect) => void;\n onSectionToggle?: (sectionKey: string, collapsed: boolean) => void;\n getItemType: (flatIndex: number) => string;\n}\n\n/**\n * Provider component for SectionFlow context.\n */\nexport function SectionFlowProvider<TItem>({\n children,\n sections,\n flattenedData,\n layoutManager,\n layoutCache,\n horizontal,\n collapsedSections,\n scrollOffset,\n viewportWidth,\n viewportHeight,\n stickySectionHeadersEnabled,\n estimatedItemSize,\n drawDistance,\n debug,\n renderItem,\n renderSectionHeader,\n renderSectionFooter,\n onCellMeasured,\n onSectionToggle,\n getItemType,\n}: SectionFlowProviderProps<TItem>): React.ReactElement {\n const value = useMemo(\n (): SectionFlowContextValue<TItem> => ({\n sections,\n flattenedData,\n layoutManager,\n layoutCache,\n horizontal,\n collapsedSections,\n scrollOffset,\n viewportWidth,\n viewportHeight,\n stickySectionHeadersEnabled,\n estimatedItemSize,\n drawDistance,\n debug,\n renderItem,\n renderSectionHeader,\n renderSectionFooter,\n onCellMeasured,\n onSectionToggle,\n getItemType,\n }),\n [\n sections,\n flattenedData,\n layoutManager,\n layoutCache,\n horizontal,\n collapsedSections,\n scrollOffset,\n viewportWidth,\n viewportHeight,\n stickySectionHeadersEnabled,\n estimatedItemSize,\n drawDistance,\n debug,\n renderItem,\n renderSectionHeader,\n renderSectionFooter,\n onCellMeasured,\n onSectionToggle,\n getItemType,\n ]\n );\n\n return (\n <SectionFlowContext.Provider value={value as SectionFlowContextValue<unknown>}>\n {children}\n </SectionFlowContext.Provider>\n );\n}\n","import React, { memo, useCallback } from 'react';\nimport { View, StyleSheet } from 'react-native';\nimport type { ViewStyle, LayoutChangeEvent } from 'react-native';\nimport type { LayoutRect, RecycledCell } from '../types';\n\ninterface RecyclerCellProps {\n cell: RecycledCell;\n layout: LayoutRect;\n children: React.ReactNode;\n onLayout: (key: string, flatIndex: number, layout: LayoutRect) => void;\n debug?: boolean;\n}\n\n/**\n * RecyclerCell wraps each item with absolute positioning.\n * This is the fundamental unit of the recycling system.\n *\n * Key responsibilities:\n * 1. Position the item at the correct x/y coordinates\n * 2. Report layout measurements back to the system\n * 3. Maintain stable identity for recycling (via key)\n */\nfunction RecyclerCellComponent({\n cell,\n layout,\n children,\n onLayout,\n debug = false,\n}: RecyclerCellProps): React.ReactElement {\n const handleLayout = useCallback(\n (event: LayoutChangeEvent) => {\n const { x, y, width, height } = event.nativeEvent.layout;\n onLayout(cell.key, cell.flatIndex, { x, y, width, height });\n },\n [cell.key, cell.flatIndex, onLayout]\n );\n\n const positionStyle: ViewStyle = {\n position: 'absolute',\n left: layout.x,\n top: layout.y,\n width: layout.width,\n // Height is determined by content - don't constrain it\n // This allows for dynamic sizing\n };\n\n return (\n <View\n style={[positionStyle, debug && styles.debug]}\n onLayout={handleLayout}\n // Key prop for React reconciliation (handled by parent)\n >\n {children}\n </View>\n );\n}\n\nconst styles: { debug: ViewStyle } = StyleSheet.create({\n debug: {\n borderWidth: 1,\n borderColor: 'rgba(255, 0, 0, 0.3)',\n },\n});\n\n/**\n * Memoized cell component to prevent unnecessary re-renders.\n * Only re-renders when:\n * - Cell key changes (different item)\n * - Layout position changes\n * - Children change (new render)\n */\nexport const RecyclerCell: React.MemoExoticComponent<typeof RecyclerCellComponent> = memo(\n RecyclerCellComponent,\n (prevProps, nextProps) => {\n // Custom comparison for performance\n return (\n prevProps.cell.key === nextProps.cell.key &&\n prevProps.cell.flatIndex === nextProps.cell.flatIndex &&\n prevProps.layout.x === nextProps.layout.x &&\n prevProps.layout.y === nextProps.layout.y &&\n prevProps.layout.width === nextProps.layout.width &&\n prevProps.layout.height === nextProps.layout.height &&\n prevProps.children === nextProps.children &&\n prevProps.debug === nextProps.debug\n );\n }\n);\n\nRecyclerCell.displayName = 'RecyclerCell';\n","import React, { memo, useMemo, useCallback } from 'react';\nimport { View, StyleSheet } from 'react-native';\nimport type { ViewStyle, LayoutChangeEvent } from 'react-native';\nimport { RecyclerCell } from './RecyclerCell';\nimport type {\n FlattenedItem,\n LayoutRect,\n RecycledCell,\n RenderItemInfo,\n RenderSectionHeaderInfo,\n RenderSectionFooterInfo,\n} from '../types';\n\ninterface RecyclerContainerProps<TItem> {\n flattenedData: FlattenedItem<TItem>[];\n visibleRange: { startIndex: number; endIndex: number };\n getLayoutForIndex: (index: number) => LayoutRect;\n getCell: (flatIndex: number) => RecycledCell;\n contentSize: { width: number; height: number };\n renderItem: (info: RenderItemInfo<TItem>) => React.ReactElement | null;\n renderSectionHeader?: (info: RenderSectionHeaderInfo<TItem>) => React.ReactElement | null;\n renderSectionFooter?: (info: RenderSectionFooterInfo<TItem>) => React.ReactElement | null;\n onCellLayout: (key: string, flatIndex: number, layout: LayoutRect) => void;\n horizontal?: boolean;\n debug?: boolean;\n}\n\n/**\n * RecyclerContainer manages the absolute-positioned content area.\n * It renders only the visible items within the current scroll window.\n *\n * Key responsibilities:\n * 1. Set content size for scroll container\n * 2. Render visible items at correct positions\n * 3. Coordinate cell recycling\n */\nfunction RecyclerContainerComponent<TItem>({\n flattenedData,\n visibleRange,\n getLayoutForIndex,\n getCell,\n contentSize,\n renderItem,\n renderSectionHeader,\n renderSectionFooter,\n onCellLayout,\n horizontal = false,\n debug = false,\n}: RecyclerContainerProps<TItem>): React.ReactElement {\n const { startIndex, endIndex } = visibleRange;\n\n // Render visible cells\n const cells = useMemo(() => {\n const result: React.ReactElement[] = [];\n\n for (let i = startIndex; i <= endIndex; i++) {\n const item = flattenedData[i];\n if (!item) continue;\n\n const cell = getCell(i);\n const layout = getLayoutForIndex(i);\n\n let content: React.ReactElement | null = null;\n\n switch (item.type) {\n case 'section-header':\n if (renderSectionHeader) {\n content = renderSectionHeader({\n section: item.section,\n sectionIndex: item.sectionIndex,\n });\n }\n break;\n\n case 'section-footer':\n if (renderSectionFooter) {\n content = renderSectionFooter({\n section: item.section,\n sectionIndex: item.sectionIndex,\n });\n }\n break;\n\n case 'item':\n if (item.item !== null) {\n content = renderItem({\n item: item.item,\n index: item.itemIndex,\n section: item.section,\n sectionIndex: item.sectionIndex,\n });\n }\n break;\n }\n\n if (content) {\n result.push(\n <RecyclerCell\n key={cell.key}\n cell={cell}\n layout={layout}\n onLayout={onCellLayout}\n debug={debug}\n >\n {content}\n </RecyclerCell>\n );\n }\n }\n\n return result;\n }, [\n startIndex,\n endIndex,\n flattenedData,\n getCell,\n getLayoutForIndex,\n renderItem,\n renderSectionHeader,\n renderSectionFooter,\n onCellLayout,\n debug,\n ]);\n\n const containerStyle: ViewStyle = useMemo(\n () => ({\n width: contentSize.width || '100%',\n height: contentSize.height,\n position: 'relative',\n }),\n [contentSize.width, contentSize.height]\n );\n\n return (\n <View style={[containerStyle, debug && styles.debug]}>\n {cells}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n debug: {\n backgroundColor: 'rgba(0, 255, 0, 0.05)',\n },\n});\n\nexport const RecyclerContainer = memo(RecyclerContainerComponent) as typeof RecyclerContainerComponent;\n","import React, { memo, useMemo } from 'react';\nimport { View, StyleSheet, Animated } from 'react-native';\nimport type { ViewStyle } from 'react-native';\nimport type { Section, SectionLayoutInfo, RenderSectionHeaderInfo } from '../types';\n\ninterface StickyHeaderContainerProps<TItem> {\n stickySection: SectionLayoutInfo | null;\n translateY: number;\n sections: Section<TItem>[];\n renderSectionHeader: (info: RenderSectionHeaderInfo<TItem>) => React.ReactElement | null;\n horizontal?: boolean;\n style?: ViewStyle;\n}\n\n/**\n * Container for the sticky section header.\n * Positioned at the top (or left for horizontal) of the viewport.\n * Handles the \"push\" effect when the next section approaches.\n */\nfunction StickyHeaderContainerComponent<TItem>({\n stickySection,\n translateY,\n sections,\n renderSectionHeader,\n horizontal = false,\n style,\n}: StickyHeaderContainerProps<TItem>): React.ReactElement | null {\n if (!stickySection) {\n return null;\n }\n\n const section = sections.find((s) => s.key === stickySection.sectionKey);\n if (!section) {\n return null;\n }\n\n const headerContent = renderSectionHeader({\n section,\n sectionIndex: stickySection.sectionIndex,\n });\n\n if (!headerContent) {\n return null;\n }\n\n const containerStyle: ViewStyle = useMemo(\n () => ({\n position: 'absolute',\n top: horizontal ? undefined : 0,\n left: horizontal ? 0 : 0,\n right: horizontal ? undefined : 0,\n transform: horizontal\n ? [{ translateX: translateY }]\n : [{ translateY }],\n zIndex: 1000,\n elevation: 4, // Android shadow\n }),\n [horizontal, translateY]\n );\n\n return (\n <View style={[containerStyle, styles.shadow, style]} pointerEvents=\"box-none\">\n {headerContent}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n shadow: {\n shadowColor: '#000',\n shadowOffset: { width: 0, height: 2 },\n shadowOpacity: 0.1,\n shadowRadius: 4,\n // Note: backgroundColor is needed for shadow to be visible on iOS\n // Users should set backgroundColor via stickyHeaderStyle prop or in their renderSectionHeader\n },\n});\n\nexport const StickyHeaderContainer = memo(\n StickyHeaderContainerComponent\n) as typeof StickyHeaderContainerComponent;\n\n/**\n * Animated version of sticky header for smoother transitions.\n * Uses Animated API for better performance on the native thread.\n */\ninterface AnimatedStickyHeaderProps<TItem> extends StickyHeaderContainerProps<TItem> {\n animatedTranslateY: Animated.Value;\n}\n\nfunction AnimatedStickyHeaderContainerComponent<TItem>({\n stickySection,\n animatedTranslateY,\n sections,\n renderSectionHeader,\n horizontal = false,\n style,\n}: AnimatedStickyHeaderProps<TItem>): React.ReactElement | null {\n if (!stickySection) {\n return null;\n }\n\n const section = sections.find((s) => s.key === stickySection.sectionKey);\n if (!section) {\n return null;\n }\n\n const headerContent = renderSectionHeader({\n section,\n sectionIndex: stickySection.sectionIndex,\n });\n\n if (!headerContent) {\n return null;\n }\n\n const animatedStyle = useMemo(\n () => ({\n position: 'absolute' as const,\n top: horizontal ? undefined : 0,\n left: 0,\n right: horizontal ? undefined : 0,\n transform: horizontal\n ? [{ translateX: animatedTranslateY }]\n : [{ translateY: animatedTranslateY }],\n zIndex: 1000,\n elevation: 4,\n }),\n [horizontal, animatedTranslateY]\n );\n\n return (\n <Animated.View style={[animatedStyle, styles.shadow, style]} pointerEvents=\"box-none\">\n {headerContent}\n </Animated.View>\n );\n}\n\nexport const AnimatedStickyHeaderContainer = memo(\n AnimatedStickyHeaderContainerComponent\n) as typeof AnimatedStickyHeaderContainerComponent;\n","import React, {\n forwardRef,\n useImperativeHandle,\n useRef,\n useState,\n useCallback,\n useMemo,\n useEffect,\n} from 'react';\nimport { ScrollView, View, StyleSheet, RefreshControl } from 'react-native';\nimport type { LayoutChangeEvent, NativeSyntheticEvent, NativeScrollEvent } from 'react-native';\nimport type {\n SectionFlowProps,\n SectionFlowRef,\n Section,\n FlattenedItem,\n LayoutRect,\n SectionLayoutInfo,\n ScrollToSectionOptions,\n ScrollToItemOptions,\n ViewToken,\n} from '../types';\nimport {\n DEFAULT_ESTIMATED_ITEM_SIZE,\n DEFAULT_ESTIMATED_HEADER_SIZE,\n DEFAULT_DRAW_DISTANCE,\n DEFAULT_ITEM_TYPE,\n SECTION_HEADER_TYPE,\n SECTION_FOOTER_TYPE,\n} from '../constants';\nimport { createLayoutCache } from '../core/LayoutCache';\nimport { createSectionLayoutManager } from '../core/SectionLayoutManager';\nimport { useScrollHandler } from '../hooks/useScrollHandler';\nimport { useRecycler } from '../hooks/useRecycler';\nimport { useStickyHeader } from '../hooks/useStickyHeader';\nimport { useViewability } from '../hooks/useViewability';\nimport { SectionFlowProvider } from '../state/SectionFlowContext';\nimport { RecyclerContainer } from './RecyclerContainer';\nimport { StickyHeaderContainer } from './StickyHeaderContainer';\n\n/**\n * SectionFlow - High-performance section list for React Native\n *\n * A drop-in replacement for SectionList with FlashList-style cell recycling.\n * Provides smooth 60fps scrolling through:\n * - Cell recycling (reuses views instead of creating new ones)\n * - Synchronous measurements (New Architecture)\n * - Type-based recycle pools\n * - Absolute positioning with computed layouts\n */\nfunction SectionFlowInner<TItem>(\n props: SectionFlowProps<TItem>,\n ref: React.ForwardedRef<SectionFlowRef<TItem>>\n): React.ReactElement {\n const {\n sections,\n renderItem,\n renderSectionHeader,\n renderSectionFooter,\n keyExtractor,\n getItemType,\n estimatedItemSize = DEFAULT_ESTIMATED_ITEM_SIZE,\n estimatedSectionHeaderSize = DEFAULT_ESTIMATED_HEADER_SIZE,\n estimatedSectionFooterSize = 0,\n horizontal = false,\n stickySectionHeadersEnabled = true,\n stickyHeaderStyle,\n collapsible = false,\n defaultCollapsed = [],\n onSectionToggle,\n maxItemsInRecyclePool,\n drawDistance = DEFAULT_DRAW_DISTANCE,\n viewabilityConfig,\n onViewableItemsChanged,\n onEndReached,\n onEndReachedThreshold,\n style,\n contentContainerStyle,\n ListHeaderComponent,\n ListFooterComponent,\n ListEmptyComponent,\n refreshing,\n onRefresh,\n extraData,\n debug = false,\n ...scrollViewProps\n } = props;\n\n // Refs\n const scrollViewRef = useRef<ScrollView>(null);\n\n // Layout state\n const [viewportSize, setViewportSize] = useState({ width: 0, height: 0 });\n const [scrollOffset, setScrollOffset] = useState(0);\n\n // Collapsed sections state\n const [collapsedSections, setCollapsedSections] = useState<Set<string>>(\n () => new Set(defaultCollapsed)\n );\n\n // Create layout cache (stable)\n const layoutCache = useMemo(() => createLayoutCache(), []);\n\n // Create section layout manager\n const layoutManager = useMemo(\n () =>\n createSectionLayoutManager(layoutCache, {\n horizontal,\n estimatedItemSize,\n estimatedHeaderSize: estimatedSectionHeaderSize,\n estimatedFooterSize: estimatedSectionFooterSize,\n hasSectionFooters: !!renderSectionFooter,\n }),\n [\n layoutCache,\n horizontal,\n estimatedItemSize,\n estimatedSectionHeaderSize,\n estimatedSectionFooterSize,\n renderSectionFooter,\n ]\n );\n\n // Flatten sections into renderable data\n const flattenedData = useMemo(\n () => layoutManager.updateData(sections as Section<unknown>[], collapsedSections) as FlattenedItem<TItem>[],\n [layoutManager, sections, collapsedSections, extraData]\n );\n\n // Update layout positioner container size\n useEffect(() => {\n layoutManager.getLayoutPositioner().setContainerSize(viewportSize.width, viewportSize.height);\n }, [layoutManager, viewportSize]);\n\n // Get item type for a flat index\n const getItemTypeForIndex = useCallback(\n (flatIndex: number): string => {\n const item = flattenedData[flatIndex];\n if (!item) return DEFAULT_ITEM_TYPE;\n\n if (item.type === 'section-header') return SECTION_HEADER_TYPE;\n if (item.type === 'section-footer') return SECTION_FOOTER_TYPE;\n\n if (getItemType && item.item !== null) {\n return getItemType(item.item as TItem, item.itemIndex, item.section);\n }\n\n return DEFAULT_ITEM_TYPE;\n },\n [flattenedData, getItemType]\n );\n\n // Scroll handler\n const { scrollState, onScroll, onScrollBeginDrag, onScrollEndDrag, onMomentumScrollBegin, onMomentumScrollEnd } =\n useScrollHandler({\n horizontal,\n onScrollStateChange: (state) => {\n setScrollOffset(state.offset);\n },\n onEndReached: onEndReached ? (distance) => onEndReached({ distanceFromEnd: distance }) : undefined,\n onEndReachedThreshold,\n });\n\n // Cell recycler\n const { getCell, releaseCell, updateVisibleRange, clearPools, getPoolStats } = useRecycler({\n flattenedData,\n getItemType: getItemType as ((item: unknown, index: number) => string) | undefined,\n maxPoolSize: maxItemsInRecyclePool,\n });\n\n // Calculate visible range\n const layoutPositioner = layoutManager.getLayoutPositioner();\n const viewportDimension = horizontal ? viewportSize.width : viewportSize.height;\n const visibleRange = useMemo(\n () => layoutPositioner.getVisibleRange(scrollOffset, viewportDimension, drawDistance),\n [layoutPositioner, scrollOffset, viewportDimension, drawDistance]\n );\n\n // Update recycler with visible range\n useEffect(() => {\n updateVisibleRange(visibleRange.startIndex, visibleRange.endIndex);\n }, [updateVisibleRange, visibleRange.startIndex, visibleRange.endIndex]);\n\n // Section layouts for sticky headers\n const sectionLayouts = useMemo(\n () => layoutManager.getAllSectionLayouts(),\n [layoutManager, flattenedData, scrollOffset]\n );\n\n // Sticky header state\n const stickyHeaderState = useStickyHeader({\n sectionLayouts,\n scrollOffset,\n viewportHeight: viewportDimension,\n horizontal,\n enabled: stickySectionHeadersEnabled,\n });\n\n // Viewability tracking\n const viewabilityResult = useViewability({\n flattenedData,\n layoutPositioner,\n scrollOffset,\n viewportSize: viewportDimension,\n horizontal,\n viewabilityConfig,\n onViewableItemsChanged,\n });\n\n // Handle cell layout measurement\n const handleCellLayout = useCallback(\n (key: string, flatIndex: number, layout: LayoutRect) => {\n layoutPositioner.updateItemLayout(flatIndex, layout);\n },\n [layoutPositioner]\n );\n\n // Handle viewport layout\n const handleViewportLayout = useCallback((event: LayoutChangeEvent) => {\n const { width, height } = event.nativeEvent.layout;\n setViewportSize({ width, height });\n }, []);\n\n // Handle section toggle\n const handleSectionToggle = useCallback(\n (sectionKey: string) => {\n setCollapsedSections((prev) => {\n const next = new Set(prev);\n const isCollapsed = next.has(sectionKey);\n\n if (isCollapsed) {\n next.delete(sectionKey);\n } else {\n next.add(sectionKey);\n }\n\n onSectionToggle?.(sectionKey, !isCollapsed);\n return next;\n });\n },\n [onSectionToggle]\n );\n\n // Content size\n const contentSize = useMemo(() => layoutPositioner.getContentSize(), [layoutPositioner, flattenedData]);\n\n // Scroll methods\n const scrollToOffset = useCallback(\n (options: { offset: number; animated?: boolean }) => {\n scrollViewRef.current?.scrollTo({\n x: horizontal ? options.offset : 0,\n y: horizontal ? 0 : options.offset,\n animated: options.animated ?? true,\n });\n },\n [horizontal]\n );\n\n const scrollToSection = useCallback(\n (options: ScrollToSectionOptions) => {\n const { sectionKey, sectionIndex, animated = true, viewPosition = 0 } = options;\n\n let targetSection: SectionLayoutInfo | null = null;\n\n if (sectionKey) {\n targetSection = layoutManager.getSectionLayout(sectionKey);\n } else if (sectionIndex !== undefined) {\n const section = sections[sectionIndex];\n if (section) {\n targetSection = layoutManager.getSectionLayout(section.key);\n }\n }\n\n if (targetSection) {\n const headerOffset = horizontal\n ? targetSection.headerLayout.x\n : targetSection.headerLayout.y;\n\n scrollToOffset({ offset: headerOffset, animated });\n }\n },\n [layoutManager, sections, horizontal, scrollToOffset]\n );\n\n const scrollToItem = useCallback(\n (options: ScrollToItemOptions) => {\n const { sectionKey, sectionIndex, itemIndex, animated = true } = options;\n\n let targetSectionIndex = sectionIndex;\n if (sectionKey) {\n targetSectionIndex = sections.findIndex((s) => s.key === sectionKey);\n }\n\n if (targetSectionIndex === undefined || targetSectionIndex < 0) return;\n\n const flatIndex = layoutManager.getFlatIndex(targetSectionIndex, itemIndex);\n if (flatIndex < 0) return;\n\n const layout = layoutPositioner.getLayoutForIndex(flatIndex);\n const offset = horizontal ? layout.x : layout.y;\n\n scrollToOffset({ offset, animated });\n },\n [layoutManager, layoutPositioner, sections, horizontal, scrollToOffset]\n );\n\n const scrollToEnd = useCallback(\n (options?: { animated?: boolean }) => {\n const totalSize = horizontal ? contentSize.width : contentSize.height;\n const offset = Math.max(0, totalSize - viewportDimension);\n scrollToOffset({ offset, animated: options?.animated ?? true });\n },\n [contentSize, viewportDimension, horizontal, scrollToOffset]\n );\n\n // Imperative handle\n useImperativeHandle(\n ref,\n () => ({\n scrollToSection,\n scrollToItem,\n scrollToOffset,\n scrollToEnd,\n toggleSection: handleSectionToggle,\n getSectionLayouts: () => sectionLayouts,\n getVisibleItems: viewabilityResult.getVisibleItems,\n recordInteraction: viewabilityResult.recordInteraction,\n flashScrollIndicators: () => scrollViewRef.current?.flashScrollIndicators(),\n }),\n [\n scrollToSection,\n scrollToItem,\n scrollToOffset,\n scrollToEnd,\n handleSectionToggle,\n sectionLayouts,\n viewabilityResult,\n ]\n );\n\n // Empty state\n if (sections.length === 0 && ListEmptyComponent) {\n const EmptyComponent =\n typeof ListEmptyComponent === 'function' ? (\n <ListEmptyComponent />\n ) : (\n ListEmptyComponent\n );\n\n return (\n <View style={[styles.container, style]}>\n {EmptyComponent}\n </View>\n );\n }\n\n // Render header/footer components\n const HeaderComponent = ListHeaderComponent ? (\n typeof ListHeaderComponent === 'function' ? (\n <ListHeaderComponent />\n ) : (\n ListHeaderComponent\n )\n ) : null;\n\n const FooterComponent = ListFooterComponent ? (\n typeof ListFooterComponent === 'function' ? (\n <ListFooterComponent />\n ) : (\n ListFooterComponent\n )\n ) : null;\n\n return (\n <View style={[styles.container, style]} onLayout={handleViewportLayout}>\n <ScrollView\n ref={scrollViewRef}\n horizontal={horizontal}\n scrollEventThrottle={16}\n onScroll={onScroll}\n onScrollBeginDrag={onScrollBeginDrag}\n onScrollEndDrag={onScrollEndDrag}\n onMomentumScrollBegin={onMomentumScrollBegin}\n onMomentumScrollEnd={onMomentumScrollEnd}\n contentContainerStyle={contentContainerStyle}\n refreshControl={\n onRefresh ? (\n <RefreshControl refreshing={refreshing ?? false} onRefresh={onRefresh} />\n ) : undefined\n }\n {...scrollViewProps}\n >\n {HeaderComponent}\n\n <SectionFlowProvider\n sections={sections}\n flattenedData={flattenedData}\n layoutManager={layoutManager}\n layoutCache={layoutCache}\n horizontal={horizontal}\n collapsedSections={collapsedSections}\n scrollOffset={scrollOffset}\n viewportWidth={viewportSize.width}\n viewportHeight={viewportSize.height}\n stickySectionHeadersEnabled={stickySectionHeadersEnabled}\n estimatedItemSize={estimatedItemSize}\n drawDistance={drawDistance}\n debug={debug}\n renderItem={renderItem}\n renderSectionHeader={renderSectionHeader}\n renderSectionFooter={renderSectionFooter}\n onCellMeasured={handleCellLayout}\n onSectionToggle={collapsible ? handleSectionToggle : undefined}\n getItemType={getItemTypeForIndex}\n >\n <RecyclerContainer\n flattenedData={flattenedData}\n visibleRange={visibleRange}\n getLayoutForIndex={(index) => layoutPositioner.getLayoutForIndex(index)}\n getCell={getCell}\n contentSize={contentSize}\n renderItem={renderItem}\n renderSectionHeader={renderSectionHeader}\n renderSectionFooter={renderSectionFooter}\n onCellLayout={handleCellLayout}\n horizontal={horizontal}\n debug={debug}\n />\n </SectionFlowProvider>\n\n {FooterComponent}\n </ScrollView>\n\n {/* Sticky header overlay */}\n {stickySectionHeadersEnabled && renderSectionHeader && stickyHeaderState.sectionKey && (\n <StickyHeaderContainer\n stickySection={sectionLayouts.find((s) => s.sectionKey === stickyHeaderState.sectionKey) ?? null}\n translateY={stickyHeaderState.translateY}\n sections={sections}\n renderSectionHeader={renderSectionHeader}\n horizontal={horizontal}\n style={stickyHeaderStyle}\n />\n )}\n\n {/* Debug overlay */}\n {debug && (\n <View style={styles.debugOverlay} pointerEvents=\"none\">\n {/* Debug info would go here */}\n </View>\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n },\n debugOverlay: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n },\n});\n\n/**\n * Export with proper generic typing.\n * Usage: <SectionFlow<MyItemType> sections={...} renderItem={...} />\n */\nexport const SectionFlow = forwardRef(SectionFlowInner) as <TItem>(\n props: SectionFlowProps<TItem> & { ref?: React.ForwardedRef<SectionFlowRef<TItem>> }\n) => React.ReactElement;\n\n// Add display name for debugging\n(SectionFlow as React.FC).displayName = 'SectionFlow';\n","import React, { memo, useCallback } from 'react';\nimport { View, Text, TouchableOpacity, StyleSheet } from 'react-native';\nimport type { ViewStyle, TextStyle } from 'react-native';\nimport type { Section } from '../types';\n\ninterface SectionHeaderProps<TItem> {\n section: Section<TItem>;\n sectionIndex: number;\n isCollapsed?: boolean;\n collapsible?: boolean;\n onToggle?: (sectionKey: string) => void;\n renderContent?: (info: {\n section: Section<TItem>;\n sectionIndex: number;\n isCollapsed: boolean;\n }) => React.ReactElement | null;\n style?: ViewStyle;\n}\n\n/**\n * Default section header component.\n * Can be overridden by providing renderSectionHeader prop to SectionFlow.\n */\nfunction SectionHeaderComponent<TItem>({\n section,\n sectionIndex,\n isCollapsed = false,\n collapsible = false,\n onToggle,\n renderContent,\n style,\n}: SectionHeaderProps<TItem>): React.ReactElement {\n const handlePress = useCallback(() => {\n if (collapsible && onToggle) {\n onToggle(section.key);\n }\n }, [collapsible, onToggle, section.key]);\n\n // If custom render function provided, use it\n if (renderContent) {\n const content = renderContent({ section, sectionIndex, isCollapsed });\n if (content) {\n if (collapsible) {\n return (\n <TouchableOpacity onPress={handlePress} activeOpacity={0.7}>\n {content}\n </TouchableOpacity>\n );\n }\n return <View>{content}</View>;\n }\n }\n\n // Default header UI\n const Wrapper = collapsible ? TouchableOpacity : View;\n const wrapperProps = collapsible\n ? { onPress: handlePress, activeOpacity: 0.7 }\n : {};\n\n return (\n <Wrapper {...wrapperProps} style={[styles.container, style]}>\n <Text style={styles.title}>{section.title ?? section.key}</Text>\n {collapsible && (\n <Text style={styles.indicator}>{isCollapsed ? '▸' : '▾'}</Text>\n )}\n </Wrapper>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingHorizontal: 16,\n paddingVertical: 12,\n backgroundColor: '#f5f5f5',\n borderBottomWidth: StyleSheet.hairlineWidth,\n borderBottomColor: '#e0e0e0',\n },\n title: {\n fontSize: 14,\n fontWeight: '600',\n color: '#333',\n textTransform: 'uppercase',\n letterSpacing: 0.5,\n },\n indicator: {\n fontSize: 14,\n color: '#666',\n },\n});\n\nexport const SectionHeader = memo(SectionHeaderComponent) as typeof SectionHeaderComponent;\n","import { useCallback, useRef, useLayoutEffect } from 'react';\nimport type { View, LayoutChangeEvent } from 'react-native';\nimport type { LayoutRect } from '../types';\n\ninterface UseMeasurementOptions {\n onMeasure: (layout: LayoutRect) => void;\n enabled?: boolean;\n}\n\ninterface MeasurementResult {\n ref: React.RefObject<View | null>;\n onLayout: (event: LayoutChangeEvent) => void;\n measure: () => void;\n}\n\n/**\n * Hook for synchronous layout measurement using New Architecture features.\n *\n * In React Native's New Architecture with Fabric, useLayoutEffect runs synchronously\n * before paint, allowing us to measure and correct layouts without visible glitches.\n *\n * This hook provides:\n * 1. A ref to attach to the View\n * 2. An onLayout callback for initial/resize measurements\n * 3. A measure function for on-demand measurement\n */\nexport function useLayoutMeasurement(options: UseMeasurementOptions): MeasurementResult {\n const { onMeasure, enabled = true } = options;\n const ref = useRef<View>(null);\n const lastMeasurement = useRef<LayoutRect | null>(null);\n\n /**\n * Measure the view using measureInWindow for absolute positioning.\n * In New Architecture, this is synchronous when called in useLayoutEffect.\n */\n const measure = useCallback(() => {\n if (!enabled || !ref.current) return;\n\n ref.current.measureInWindow((x, y, width, height) => {\n // measureInWindow returns window coordinates\n // We primarily care about width/height for layout calculations\n const layout: LayoutRect = { x, y, width, height };\n\n // Only report if changed to avoid unnecessary updates\n if (\n !lastMeasurement.current ||\n lastMeasurement.current.width !== width ||\n lastMeasurement.current.height !== height\n ) {\n lastMeasurement.current = layout;\n onMeasure(layout);\n }\n });\n }, [enabled, onMeasure]);\n\n /**\n * Handle layout events from React Native's onLayout prop.\n * This fires on mount and whenever the layout changes.\n */\n const onLayout = useCallback(\n (event: LayoutChangeEvent) => {\n if (!enabled) return;\n\n const { x, y, width, height } = event.nativeEvent.layout;\n const layout: LayoutRect = { x, y, width, height };\n\n // Only report if changed\n if (\n !lastMeasurement.current ||\n lastMeasurement.current.width !== width ||\n lastMeasurement.current.height !== height\n ) {\n lastMeasurement.current = layout;\n onMeasure(layout);\n }\n },\n [enabled, onMeasure]\n );\n\n return { ref, onLayout, measure };\n}\n\n/**\n * Hook for measuring a cell's layout and reporting to the layout system.\n * Uses synchronous measurement in New Architecture for smooth corrections.\n */\nexport function useCellMeasurement(\n cellKey: string,\n onCellMeasured: (key: string, layout: LayoutRect) => void,\n enabled = true\n): MeasurementResult {\n const handleMeasure = useCallback(\n (layout: LayoutRect) => {\n onCellMeasured(cellKey, layout);\n },\n [cellKey, onCellMeasured]\n );\n\n return useLayoutMeasurement({\n onMeasure: handleMeasure,\n enabled,\n });\n}\n\n/**\n * Hook for progressive rendering - measures initial items and expands.\n * Implements FlashList v2's progressive rendering strategy.\n */\nexport function useProgressiveRender(\n totalItems: number,\n initialCount: number,\n batchSize: number,\n onRenderCountChange: (count: number) => void\n): {\n renderCount: number;\n onItemMeasured: (index: number) => void;\n} {\n const renderCount = useRef(Math.min(initialCount, totalItems));\n const measuredCount = useRef(0);\n\n const onItemMeasured = useCallback(\n (index: number) => {\n measuredCount.current++;\n\n // If all current items are measured, expand render window\n if (measuredCount.current >= renderCount.current && renderCount.current < totalItems) {\n const newCount = Math.min(renderCount.current + batchSize, totalItems);\n renderCount.current = newCount;\n onRenderCountChange(newCount);\n }\n },\n [totalItems, batchSize, onRenderCountChange]\n );\n\n return {\n renderCount: renderCount.current,\n onItemMeasured,\n };\n}\n","import type { Section, FlattenedItem } from '../types';\n\ninterface FlattenOptions {\n collapsedSections?: Set<string>;\n includeSectionFooters?: boolean;\n}\n\n/**\n * Flatten sections into a single array of items for virtualization.\n * Each item includes metadata about its section and position.\n */\nexport function flattenSections<TItem>(\n sections: Section<TItem>[],\n options: FlattenOptions = {}\n): FlattenedItem<TItem>[] {\n const { collapsedSections = new Set(), includeSectionFooters = false } = options;\n const result: FlattenedItem<TItem>[] = [];\n\n for (let sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) {\n const section = sections[sectionIndex];\n const isCollapsed = collapsedSections.has(section.key);\n\n // Always add section header\n result.push({\n type: 'section-header',\n key: `header-${section.key}`,\n sectionKey: section.key,\n sectionIndex,\n itemIndex: -1,\n item: null,\n section,\n });\n\n // Add items only if not collapsed\n if (!isCollapsed) {\n for (let itemIndex = 0; itemIndex < section.data.length; itemIndex++) {\n result.push({\n type: 'item',\n key: `item-${section.key}-${itemIndex}`,\n sectionKey: section.key,\n sectionIndex,\n itemIndex,\n item: section.data[itemIndex],\n section,\n });\n }\n\n // Optionally add section footer\n if (includeSectionFooters) {\n result.push({\n type: 'section-footer',\n key: `footer-${section.key}`,\n sectionKey: section.key,\n sectionIndex,\n itemIndex: -1,\n item: null,\n section,\n });\n }\n }\n }\n\n return result;\n}\n\n/**\n * Get the flat index for a specific section and item index.\n */\nexport function getFlatIndex<TItem>(\n sections: Section<TItem>[],\n sectionIndex: number,\n itemIndex: number,\n collapsedSections: Set<string> = new Set(),\n includeSectionFooters = false\n): number {\n let flatIndex = 0;\n\n for (let i = 0; i < sectionIndex; i++) {\n const section = sections[i];\n flatIndex++; // Header\n\n if (!collapsedSections.has(section.key)) {\n flatIndex += section.data.length; // Items\n if (includeSectionFooters) {\n flatIndex++; // Footer\n }\n }\n }\n\n // Add header of target section\n flatIndex++;\n\n // Add items up to target index\n if (itemIndex >= 0 && !collapsedSections.has(sections[sectionIndex].key)) {\n flatIndex += itemIndex;\n }\n\n return flatIndex;\n}\n\n/**\n * Get section and item index from a flat index.\n */\nexport function getSectionItemFromFlatIndex<TItem>(\n sections: Section<TItem>[],\n flatIndex: number,\n collapsedSections: Set<string> = new Set(),\n includeSectionFooters = false\n): { sectionIndex: number; itemIndex: number; type: 'header' | 'item' | 'footer' } | null {\n let currentFlatIndex = 0;\n\n for (let sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) {\n const section = sections[sectionIndex];\n const isCollapsed = collapsedSections.has(section.key);\n\n // Check if this is the header\n if (currentFlatIndex === flatIndex) {\n return { sectionIndex, itemIndex: -1, type: 'header' };\n }\n currentFlatIndex++;\n\n if (!isCollapsed) {\n // Check items\n for (let itemIndex = 0; itemIndex < section.data.length; itemIndex++) {\n if (currentFlatIndex === flatIndex) {\n return { sectionIndex, itemIndex, type: 'item' };\n }\n currentFlatIndex++;\n }\n\n // Check footer\n if (includeSectionFooters) {\n if (currentFlatIndex === flatIndex) {\n return { sectionIndex, itemIndex: -1, type: 'footer' };\n }\n currentFlatIndex++;\n }\n }\n }\n\n return null;\n}\n","/**\n * Key extraction utilities for list items.\n */\n\n/**\n * Default key extractor that uses index as string.\n * Note: Using indices as keys is not recommended for dynamic lists.\n */\nexport function defaultKeyExtractor<TItem>(item: TItem, index: number): string {\n // Try to use common id field names\n const anyItem = item as Record<string, unknown>;\n\n if (typeof anyItem?.id === 'string' || typeof anyItem?.id === 'number') {\n return String(anyItem.id);\n }\n\n if (typeof anyItem?.key === 'string' || typeof anyItem?.key === 'number') {\n return String(anyItem.key);\n }\n\n if (typeof anyItem?._id === 'string' || typeof anyItem?._id === 'number') {\n return String(anyItem._id);\n }\n\n if (typeof anyItem?.uuid === 'string') {\n return anyItem.uuid;\n }\n\n // Fallback to index\n return String(index);\n}\n\n/**\n * Create a key extractor function with a custom field name.\n */\nexport function createKeyExtractor<TItem>(\n field: keyof TItem\n): (item: TItem, index: number) => string {\n return (item: TItem) => {\n const value = item[field];\n if (value !== undefined && value !== null) {\n return String(value);\n }\n throw new Error(`Key field \"${String(field)}\" not found on item`);\n };\n}\n\n/**\n * Create a composite key from multiple fields.\n */\nexport function createCompositeKeyExtractor<TItem>(\n fields: (keyof TItem)[]\n): (item: TItem, index: number) => string {\n return (item: TItem) => {\n return fields\n .map((field) => {\n const value = item[field];\n return value !== undefined && value !== null ? String(value) : '';\n })\n .join('-');\n };\n}\n\n/**\n * Validate that keys are unique within a list.\n * Throws an error if duplicates are found.\n */\nexport function validateUniqueKeys<TItem>(\n items: TItem[],\n keyExtractor: (item: TItem, index: number) => string\n): void {\n const seen = new Set<string>();\n\n for (let i = 0; i < items.length; i++) {\n const key = keyExtractor(items[i], i);\n\n if (seen.has(key)) {\n throw new Error(\n `Duplicate key \"${key}\" found at index ${i}. Keys must be unique within a list.`\n );\n }\n\n seen.add(key);\n }\n}\n","/**\n * Binary search utilities for efficient offset-to-index lookups.\n */\n\n/**\n * Binary search to find the index of an item with a specific value.\n * Returns -1 if not found.\n */\nexport function binarySearch<T>(\n array: T[],\n target: number,\n getValue: (item: T) => number\n): number {\n let low = 0;\n let high = array.length - 1;\n\n while (low <= high) {\n const mid = Math.floor((low + high) / 2);\n const value = getValue(array[mid]);\n\n if (value === target) {\n return mid;\n } else if (value < target) {\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n return -1;\n}\n\n/**\n * Binary search to find the insertion position for a value.\n * Returns the index where the value should be inserted to maintain sorted order.\n */\nexport function binarySearchInsertPosition<T>(\n array: T[],\n target: number,\n getValue: (item: T) => number\n): number {\n let low = 0;\n let high = array.length;\n\n while (low < high) {\n const mid = Math.floor((low + high) / 2);\n const value = getValue(array[mid]);\n\n if (value < target) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n\n return low;\n}\n\n/**\n * Binary search to find the first item whose end position is after the target.\n * Useful for finding the first visible item.\n */\nexport function binarySearchFirstAfter(\n offsets: number[],\n sizes: number[],\n target: number\n): number {\n let low = 0;\n let high = offsets.length - 1;\n\n while (low < high) {\n const mid = Math.floor((low + high) / 2);\n const itemEnd = offsets[mid] + sizes[mid];\n\n if (itemEnd <= target) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n\n return low;\n}\n\n/**\n * Binary search to find the last item whose start position is before the target.\n * Useful for finding the last visible item.\n */\nexport function binarySearchLastBefore(\n offsets: number[],\n target: number\n): number {\n let low = 0;\n let high = offsets.length - 1;\n\n while (low < high) {\n const mid = Math.ceil((low + high) / 2);\n\n if (offsets[mid] >= target) {\n high = mid - 1;\n } else {\n low = mid;\n }\n }\n\n return high;\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dreamstack-us/section-flow",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"workspaces": ["packages/*"],
|
|
6
|
+
"description": "High-performance, section-first list library for React Native",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": {
|
|
13
|
+
"@dreamstack-us/source": "./src/index.ts",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"require": {
|
|
18
|
+
"@dreamstack-us/source": "./src/index.ts",
|
|
19
|
+
"types": "./dist/index.d.cts",
|
|
20
|
+
"default": "./dist/index.cjs"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"./package.json": "./package.json"
|
|
24
|
+
},
|
|
25
|
+
"files": ["dist", "README.md", "LICENSE"],
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"registry": "https://registry.npmjs.org/"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsdown && bun run --filter './packages/*' build",
|
|
32
|
+
"build:root": "tsdown",
|
|
33
|
+
"dev": "tsdown --watch",
|
|
34
|
+
"typecheck": "tsc --noEmit",
|
|
35
|
+
"release": "changeset publish",
|
|
36
|
+
"prepublishOnly": "bun run build:root"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"react": ">=18.0.0",
|
|
40
|
+
"react-native": ">=0.76.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependenciesMeta": {
|
|
43
|
+
"react-native-reanimated": {
|
|
44
|
+
"optional": true
|
|
45
|
+
},
|
|
46
|
+
"react-native-gesture-handler": {
|
|
47
|
+
"optional": true
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@changesets/changelog-github": "^0.5.0",
|
|
52
|
+
"@changesets/cli": "^2.27.0",
|
|
53
|
+
"@types/react": "^19.0.0",
|
|
54
|
+
"react": "^19.0.0",
|
|
55
|
+
"react-native": "^0.76.0",
|
|
56
|
+
"tsdown": "^0.6.0",
|
|
57
|
+
"typescript": "^5.7.0"
|
|
58
|
+
},
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "git+https://github.com/DreamStack-us/section-flow.git"
|
|
62
|
+
},
|
|
63
|
+
"author": "DreamStack <hello@dreamstack.us>",
|
|
64
|
+
"license": "MIT",
|
|
65
|
+
"keywords": ["react-native", "list", "sectionlist", "performance", "cell-recycling", "virtualization", "flashlist", "new-architecture"]
|
|
66
|
+
}
|