diff --git a/examples/ReactNativeListPlayground/app/(tabs)/List.tsx b/examples/ReactNativeListPlayground/app/(tabs)/List.tsx index eeabc92b..086864c3 100644 --- a/examples/ReactNativeListPlayground/app/(tabs)/List.tsx +++ b/examples/ReactNativeListPlayground/app/(tabs)/List.tsx @@ -1,8 +1,10 @@ import { useCallback, useMemo, useRef } from 'react'; -import { List, ScrollView } from '@infinite-list/react-native'; +import { List } from '@infinite-list/list'; +import { ScrollView } from '@infinite-list/scroller'; import { // NativeScrollEvent, // NativeSyntheticEvent, + ScrollView as NativeScrollView, Text, View, } from 'react-native'; @@ -15,7 +17,7 @@ const buildData = (count: number, startIndex = 0) => export default () => { const data = useMemo(() => buildData(10000), []); - const scrollViewRef = useRef(null); + const scrollViewRef = useRef(null); const renderItem = useCallback((props: { item }) => { const { item } = props; diff --git a/examples/ReactNativeListPlayground/app/(tabs)/index.tsx b/examples/ReactNativeListPlayground/app/(tabs)/index.tsx index a281ceb6..3b25502b 100644 --- a/examples/ReactNativeListPlayground/app/(tabs)/index.tsx +++ b/examples/ReactNativeListPlayground/app/(tabs)/index.tsx @@ -169,5 +169,6 @@ import MasonryList from './MasonryList'; import { Text } from 'react-native'; export default () => { - return ; + // return ; + return ; }; diff --git a/examples/ReactNativeListPlayground/metro.config.js b/examples/ReactNativeListPlayground/metro.config.js index 858c94e8..afca4e5e 100644 --- a/examples/ReactNativeListPlayground/metro.config.js +++ b/examples/ReactNativeListPlayground/metro.config.js @@ -84,9 +84,28 @@ const scrollerPkg = JSON.parse( const scrollerModules = Object.keys({ ...scrollerPkg.dependencies, }); +const listPkg = JSON.parse( + fs.readFileSync(path.join(root, 'ui', 'list', 'package.json'), 'utf8') +); +const listModules = Object.keys({ + ...listPkg.dependencies, +}); +const groupPkg = JSON.parse( + fs.readFileSync(path.join(root, 'ui', 'group', 'package.json'), 'utf8') +); +const groupModules = Object.keys({ + ...groupPkg.dependencies, +}); const extraModules = [] - .concat(reactNativeModules, dataModelModules, masonryModules, scrollerModules) + .concat( + reactNativeModules, + dataModelModules, + masonryModules, + scrollerModules, + listModules, + groupModules + ) .reduce((acc, name) => { acc[name] = path.join(root, 'packages', 'data-model', 'node_modules', name); return acc; @@ -104,13 +123,27 @@ config.resolver.extraNodeModules = { 'src' ), '@infinite-list/data-model': path.join(root, 'packages', 'data-model', 'src'), + '@infinite-list/list': path.join(root, 'ui', 'list', 'src'), + '@infinite-list/group': path.join(root, 'ui', 'group', 'src'), '@infinite-list/masonry': path.join(root, 'ui', 'masonry', 'src'), + '@infinite-list/group-dimensions': path.join( + root, + 'model', + 'group-dimensions', + 'src' + ), '@infinite-list/masonry-dimensions': path.join( root, 'model', 'masonry-dimensions', 'src' ), + '@infinite-list/list-dimensions': path.join( + root, + 'model', + 'list-dimensions', + 'src' + ), '@infinite-list/scroller': path.join(root, 'ui', 'scroller', 'src'), '@infinite-list/viewable': path.join(root, 'core', 'viewable', 'src'), '@infinite-list/base-dimensions': path.join( @@ -137,12 +170,20 @@ config.watchFolders = [ path.join(root, 'packages', 'react-native', 'node_modules'), path.join(root, 'packages', 'data-model', 'src'), path.join(root, 'packages', 'data-model', 'node_modules'), + path.join(root, 'ui', 'group', 'src'), + path.join(root, 'ui', 'group', 'node_modules'), + path.join(root, 'ui', 'list', 'src'), + path.join(root, 'ui', 'list', 'node_modules'), path.join(root, 'ui', 'masonry', 'src'), path.join(root, 'ui', 'masonry', 'node_modules'), path.join(root, 'ui', 'scroller', 'src'), path.join(root, 'ui', 'scroller', 'node_modules'), path.join(root, 'model', 'masonry-dimensions', 'src'), path.join(root, 'model', 'masonry-dimensions', 'node_modules'), + path.join(root, 'model', 'group-dimensions', 'src'), + path.join(root, 'model', 'group-dimensions', 'node_modules'), + path.join(root, 'model', 'list-dimensions', 'src'), + path.join(root, 'model', 'list-dimensions', 'node_modules'), path.join(root, 'core', 'viewable', 'src'), path.join(root, 'core', 'viewable', 'node_modules'), path.join(root, 'core', 'base-dimensions', 'src'), diff --git a/examples/ReactNativeListPlayground/tsconfig.json b/examples/ReactNativeListPlayground/tsconfig.json index a3d7b50c..f2b970a0 100644 --- a/examples/ReactNativeListPlayground/tsconfig.json +++ b/examples/ReactNativeListPlayground/tsconfig.json @@ -9,6 +9,8 @@ "@infinite-list/react-native": ["../../packages/react-native/src"], "@infinite-list/masonry": ["../../ui/masonry/src/react-native"], "@infinite-list/scroller": ["../../ui/scroller/src/react-native"], + "@infinite-list/group": ["../../ui/group/src/react-native"], + "@infinite-list/list": ["../../ui/list/src/react-native"], } }, "include": [ diff --git a/ui/list/src/react-native/List.tsx b/ui/list/src/react-native/List.tsx index 35067421..d315ec7d 100644 --- a/ui/list/src/react-native/List.tsx +++ b/ui/list/src/react-native/List.tsx @@ -1,4 +1,11 @@ -import { useEffect, useMemo, useState, useRef, useContext } from 'react'; +import { + useEffect, + useMemo, + useState, + useRef, + useContext, + useCallback, +} from 'react'; import { View, ViewStyle, @@ -51,6 +58,31 @@ const List = (props: ListProps) => { const offsetRef = useRef(0); const tsRef = useRef(Date.now()); + /** + * Trigger list render after initialization or content will be blank + */ + const onLayoutHandler = useCallback(() => { + const scrollMetrics = contextValues + .getScrollHelper() + .getScrollEventMetrics(); + const timestamp = Date.now(); + const offset = scrollMetrics.contentOffset.y; + + const dOffset = offset - offsetRef.current; + const dt = timestamp - tsRef.current; + const velocity = dOffset / dt; + + offsetRef.current = offset; + tsRef.current = timestamp; + + listModel.updateScrollMetrics({ + offset, + visibleLength: scrollMetrics.layoutMeasurement.height, + contentLength: scrollMetrics.contentSize.height, + velocity, + }); + }, []); + useEffect( () => contextValues @@ -83,7 +115,12 @@ const List = (props: ListProps) => { if (recycleEnabled) { const nextState = state as RecycleStateResult; return ( - + {nextState.recycleState.map((data) => (