react-native-list 1.0.1 → 2.0.0-alpha.2
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/README.md +186 -32
- package/ReactNativeList.podspec +39 -0
- package/android/CMakeLists.txt +48 -0
- package/android/build.gradle +151 -0
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/JHybridUiListModule.cpp +192 -0
- package/android/src/main/cpp/JHybridUiListModule.h +50 -0
- package/android/src/main/cpp/cpp-adapter.cpp +12 -0
- package/android/src/main/java/com/hannojg/reactnativelist/ReactNativeListPackage.kt +27 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridNativeListDataSource.kt +146 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridNativeListLayout.kt +86 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridUiListModule.kt +116 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridUiListView.kt +410 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridViewHolder.kt +9 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/NativeListAdapter.kt +217 -0
- package/ios/DataSource/HybridNativeListDataSource.swift +213 -0
- package/ios/HybridObjects/HybridUiListModule.swift +49 -0
- package/ios/HybridObjects/HybridViewHolder.swift +16 -0
- package/ios/Layout/HybridNativeListLayout.swift +128 -0
- package/ios/Utils/ErrorUtils.h +26 -0
- package/ios/Utils/HybridIOSWorkletsModuleProxyHolder.swift +10 -0
- package/ios/Utils/SurfaceHelper.h +20 -0
- package/ios/Utils/SurfaceHelper.mm +144 -0
- package/ios/Utils/SurfacePresenterRegistry.h +17 -0
- package/ios/Utils/SurfacePresenterRegistry.m +31 -0
- package/ios/Utils/TurboModuleInstaller.h +18 -0
- package/ios/Utils/TurboModuleInstaller.mm +267 -0
- package/ios/Views/HostCell.swift +216 -0
- package/ios/Views/HybridUiListView.swift +695 -0
- package/lib/ReactFabricMirror.d.ts +4 -0
- package/lib/ReactFabricMirror.js +515 -0
- package/lib/UiListModule.d.ts +2 -0
- package/lib/UiListModule.js +2 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +21 -0
- package/lib/privateGlobals.d.ts +14 -0
- package/lib/privateGlobals.js +2 -0
- package/lib/renderer/RenderHelper.d.ts +2 -0
- package/lib/renderer/RenderHelper.js +11 -0
- package/lib/renderer/UiManagerHelper.d.ts +2 -0
- package/lib/renderer/UiManagerHelper.js +2 -0
- package/lib/renderer/fabric/RenderHelper.d.ts +2 -0
- package/lib/renderer/fabric/RenderHelper.js +11 -0
- package/lib/renderer/fabric/UiManagerHelper.d.ts +2 -0
- package/lib/renderer/fabric/UiManagerHelper.js +2 -0
- package/lib/renderer/react/ReactFabricMirror.d.ts +4 -0
- package/lib/renderer/react/ReactFabricMirror.js +515 -0
- package/lib/renderer/react/ReactFabricRenderer.d.ts +3 -0
- package/lib/renderer/react/ReactFabricRenderer.js +9 -0
- package/lib/specs/IOSWorkletsModuleProxyHolder.nitro.d.ts +6 -0
- package/lib/specs/IOSWorkletsModuleProxyHolder.nitro.js +1 -0
- package/lib/specs/UIListModule.nitro.d.ts +9 -0
- package/lib/specs/UIListModule.nitro.js +1 -0
- package/lib/specs/UIManagerHelper.nitro.d.ts +13 -0
- package/lib/specs/UIManagerHelper.nitro.js +1 -0
- package/lib/specs/UiListView.nitro.d.ts +20 -0
- package/lib/specs/UiListView.nitro.js +1 -0
- package/lib/specs/ViewHolder.nitro.d.ts +6 -0
- package/lib/specs/ViewHolder.nitro.js +1 -0
- package/lib/views/List.d.ts +35 -0
- package/lib/views/List.js +225 -0
- package/lib/views/UiListHostComponent.d.ts +2 -0
- package/lib/views/UiListHostComponent.js +3 -0
- package/metro/RendererProxyThreadSwitch.js +66 -0
- package/metro-config.d.ts +1 -0
- package/metro-config.js +124 -0
- package/nitro.json +47 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/ReactNativeList+autolinking.cmake +99 -0
- package/nitrogen/generated/android/ReactNativeList+autolinking.gradle +27 -0
- package/nitrogen/generated/android/ReactNativeListOnLoad.cpp +156 -0
- package/nitrogen/generated/android/ReactNativeListOnLoad.hpp +34 -0
- package/nitrogen/generated/android/c++/JFunc_bool_NativeListItem_NativeListItem.hpp +83 -0
- package/nitrogen/generated/android/c++/JFunc_bool_double_NativeListItem_double.hpp +83 -0
- package/nitrogen/generated/android/c++/JFunc_double_std__string.hpp +78 -0
- package/nitrogen/generated/android/c++/JHybridIOSWorkletsModuleProxyHolderSpec.cpp +49 -0
- package/nitrogen/generated/android/c++/JHybridIOSWorkletsModuleProxyHolderSpec.hpp +63 -0
- package/nitrogen/generated/android/c++/JHybridNativeLinearListLayoutSpec.cpp +63 -0
- package/nitrogen/generated/android/c++/JHybridNativeLinearListLayoutSpec.hpp +65 -0
- package/nitrogen/generated/android/c++/JHybridNativeListDataSourceSpec.cpp +101 -0
- package/nitrogen/generated/android/c++/JHybridNativeListDataSourceSpec.hpp +70 -0
- package/nitrogen/generated/android/c++/JHybridNativeListLayoutSpec.cpp +49 -0
- package/nitrogen/generated/android/c++/JHybridNativeListLayoutSpec.hpp +63 -0
- package/nitrogen/generated/android/c++/JHybridUiListModuleSpec.cpp +65 -0
- package/nitrogen/generated/android/c++/JHybridUiListModuleSpec.hpp +64 -0
- package/nitrogen/generated/android/c++/JHybridUiListViewSpec.cpp +92 -0
- package/nitrogen/generated/android/c++/JHybridUiListViewSpec.hpp +67 -0
- package/nitrogen/generated/android/c++/JHybridViewHolderSpec.cpp +49 -0
- package/nitrogen/generated/android/c++/JHybridViewHolderSpec.hpp +63 -0
- package/nitrogen/generated/android/c++/JNativeItemSizeEstimate.hpp +61 -0
- package/nitrogen/generated/android/c++/JNativeLinearListLayoutConfig.hpp +81 -0
- package/nitrogen/generated/android/c++/JNativeLinearListLayoutIOSConfig.hpp +59 -0
- package/nitrogen/generated/android/c++/JNativeListItem.hpp +76 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_HybridIOSWorkletsModuleProxyHolderSpec.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_HybridIOSWorkletsModuleProxyHolderSpec.hpp +72 -0
- package/nitrogen/generated/android/c++/views/JHybridUiListViewStateUpdater.cpp +53 -0
- package/nitrogen/generated/android/c++/views/JHybridUiListViewStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/c++/views/JHybridViewHolderStateUpdater.cpp +53 -0
- package/nitrogen/generated/android/c++/views/JHybridViewHolderStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Func_bool_NativeListItem_NativeListItem.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Func_bool_double_NativeListItem_double.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Func_double_std__string.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridIOSWorkletsModuleProxyHolderSpec.kt +52 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridNativeLinearListLayoutSpec.kt +54 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridNativeListDataSourceSpec.kt +87 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridNativeListLayoutSpec.kt +52 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridUiListModuleSpec.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridUiListViewSpec.kt +76 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridViewHolderSpec.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeItemSizeEstimate.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeLinearListLayoutConfig.kt +76 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeLinearListLayoutIOSConfig.kt +51 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeListItem.kt +71 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/ReactNativeListOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Variant_NullType_HybridIOSWorkletsModuleProxyHolderSpec.kt +62 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridUiListViewManager.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridUiListViewStateUpdater.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridViewHolderManager.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridViewHolderStateUpdater.kt +23 -0
- package/nitrogen/generated/ios/ReactNativeList+autolinking.rb +62 -0
- package/nitrogen/generated/ios/ReactNativeList-Swift-Cxx-Bridge.cpp +162 -0
- package/nitrogen/generated/ios/ReactNativeList-Swift-Cxx-Bridge.hpp +368 -0
- package/nitrogen/generated/ios/ReactNativeList-Swift-Cxx-Umbrella.hpp +92 -0
- package/nitrogen/generated/ios/ReactNativeListAutolinking.mm +83 -0
- package/nitrogen/generated/ios/ReactNativeListAutolinking.swift +86 -0
- package/nitrogen/generated/ios/c++/HybridIOSWorkletsModuleProxyHolderSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridIOSWorkletsModuleProxyHolderSpecSwift.hpp +75 -0
- package/nitrogen/generated/ios/c++/HybridNativeLinearListLayoutSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNativeLinearListLayoutSpecSwift.hpp +92 -0
- package/nitrogen/generated/ios/c++/HybridNativeListDataSourceSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNativeListDataSourceSpecSwift.hpp +132 -0
- package/nitrogen/generated/ios/c++/HybridNativeListLayoutSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNativeListLayoutSpecSwift.hpp +75 -0
- package/nitrogen/generated/ios/c++/HybridUiListModuleSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridUiListModuleSpecSwift.hpp +93 -0
- package/nitrogen/generated/ios/c++/HybridUiListViewSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridUiListViewSpecSwift.hpp +121 -0
- package/nitrogen/generated/ios/c++/HybridViewHolderSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridViewHolderSpecSwift.hpp +75 -0
- package/nitrogen/generated/ios/c++/views/HybridUiListViewComponent.mm +118 -0
- package/nitrogen/generated/ios/c++/views/HybridViewHolderComponent.mm +118 -0
- package/nitrogen/generated/ios/swift/Func_bool_NativeListItem_NativeListItem.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_bool_double_NativeListItem_double.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_double_std__string.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridIOSWorkletsModuleProxyHolderSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridIOSWorkletsModuleProxyHolderSpec_cxx.swift +128 -0
- package/nitrogen/generated/ios/swift/HybridNativeLinearListLayoutSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridNativeLinearListLayoutSpec_cxx.swift +140 -0
- package/nitrogen/generated/ios/swift/HybridNativeListDataSourceSpec.swift +62 -0
- package/nitrogen/generated/ios/swift/HybridNativeListDataSourceSpec_cxx.swift +222 -0
- package/nitrogen/generated/ios/swift/HybridNativeListLayoutSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridNativeListLayoutSpec_cxx.swift +128 -0
- package/nitrogen/generated/ios/swift/HybridUiListModuleSpec.swift +56 -0
- package/nitrogen/generated/ios/swift/HybridUiListModuleSpec_cxx.swift +175 -0
- package/nitrogen/generated/ios/swift/HybridUiListViewSpec.swift +59 -0
- package/nitrogen/generated/ios/swift/HybridUiListViewSpec_cxx.swift +227 -0
- package/nitrogen/generated/ios/swift/HybridViewHolderSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridViewHolderSpec_cxx.swift +147 -0
- package/nitrogen/generated/ios/swift/NativeItemSizeEstimate.swift +60 -0
- package/nitrogen/generated/ios/swift/NativeLinearListLayoutConfig.swift +60 -0
- package/nitrogen/generated/ios/swift/NativeLinearListLayoutIOSConfig.swift +35 -0
- package/nitrogen/generated/ios/swift/NativeListItem.swift +75 -0
- package/nitrogen/generated/ios/swift/Variant_NullType__any_HybridIOSWorkletsModuleProxyHolderSpec_.swift +30 -0
- package/nitrogen/generated/shared/c++/HybridIOSWorkletsModuleProxyHolderSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridIOSWorkletsModuleProxyHolderSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridNativeLinearListLayoutSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridNativeLinearListLayoutSpec.hpp +67 -0
- package/nitrogen/generated/shared/c++/HybridNativeListDataSourceSpec.cpp +28 -0
- package/nitrogen/generated/shared/c++/HybridNativeListDataSourceSpec.hpp +72 -0
- package/nitrogen/generated/shared/c++/HybridNativeListLayoutSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridNativeListLayoutSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridUiListModuleSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridUiListModuleSpec.hpp +68 -0
- package/nitrogen/generated/shared/c++/HybridUiListViewSpec.cpp +25 -0
- package/nitrogen/generated/shared/c++/HybridUiListViewSpec.hpp +79 -0
- package/nitrogen/generated/shared/c++/HybridUiManagerHelperSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridUiManagerHelperSpec.hpp +65 -0
- package/nitrogen/generated/shared/c++/HybridViewHolderSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridViewHolderSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/NativeItemSizeEstimate.hpp +87 -0
- package/nitrogen/generated/shared/c++/NativeLinearListLayoutConfig.hpp +105 -0
- package/nitrogen/generated/shared/c++/NativeLinearListLayoutIOSConfig.hpp +85 -0
- package/nitrogen/generated/shared/c++/NativeListItem.hpp +101 -0
- package/nitrogen/generated/shared/c++/views/HybridUiListViewComponent.cpp +72 -0
- package/nitrogen/generated/shared/c++/views/HybridUiListViewComponent.hpp +109 -0
- package/nitrogen/generated/shared/c++/views/HybridViewHolderComponent.cpp +72 -0
- package/nitrogen/generated/shared/c++/views/HybridViewHolderComponent.hpp +109 -0
- package/nitrogen/generated/shared/json/UiListViewConfig.json +9 -0
- package/nitrogen/generated/shared/json/ViewHolderConfig.json +9 -0
- package/package.json +152 -5
- package/react-native.config.js +16 -0
- package/src/ListDataSource.ts +232 -0
- package/src/ListLayout.ts +95 -0
- package/src/UiListModule.ts +5 -0
- package/src/hooks/useChangeEffect.ts +50 -0
- package/src/index.tsx +49 -0
- package/src/privateGlobals.ts +20 -0
- package/src/renderer/fabric/RenderHelper.ts +29 -0
- package/src/renderer/fabric/UiManagerHelper.ts +5 -0
- package/src/renderer/react/ReactFabricMirror.bundle.js +1984 -0
- package/src/renderer/react/ReactFabricMirror.ts +766 -0
- package/src/renderer/react/ReactFabricRenderer.ts +11 -0
- package/src/specs/IOSWorkletsModuleProxyHolder.nitro.ts +6 -0
- package/src/specs/NativeLinearListLayout.nitro.ts +23 -0
- package/src/specs/NativeListDataSource.nitro.ts +28 -0
- package/src/specs/NativeListLayout.nitro.ts +6 -0
- package/src/specs/UIListModule.nitro.ts +13 -0
- package/src/specs/UIManagerHelper.nitro.ts +34 -0
- package/src/specs/UiListView.nitro.ts +31 -0
- package/src/specs/ViewHolder.nitro.ts +11 -0
- package/src/views/List.tsx +525 -0
- package/src/views/UiListHostComponent.ts +8 -0
- package/FillRateHelper.js +0 -179
- package/FlatList.js +0 -494
- package/LICENSE.md +0 -31
- package/MetroListView.js +0 -166
- package/SectionList.js +0 -291
- package/ViewabilityHelper.js +0 -260
- package/VirtualizeUtils.js +0 -163
- package/VirtualizedList.js +0 -861
- package/VirtualizedSectionList.js +0 -397
- package/index.js +0 -5
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type ReactFabricMirrorModule = typeof import('./ReactFabricMirror')
|
|
2
|
+
|
|
3
|
+
// This has to be a function so that its a worklet which can be called on the UI runtime.
|
|
4
|
+
// Never import the ReactFabricMirrorModule directly from non-worklet code!
|
|
5
|
+
export function getReactFabricRenderer(): ReactFabricMirrorModule {
|
|
6
|
+
'worklet'
|
|
7
|
+
// This file is generated by `bun bundle:js`. It contains setting up the React instance on the UI runtime.
|
|
8
|
+
// This is what will do the "react render phase" of our react tree. Note that this is seperate from the
|
|
9
|
+
// fabric tree rendering + mounting. This is just react stuff.
|
|
10
|
+
return require('react-native-list/src/renderer/react/ReactFabricMirror.bundle')
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { NativeListLayout } from './NativeListLayout.nitro'
|
|
2
|
+
|
|
3
|
+
export interface NativeItemSizeEstimate {
|
|
4
|
+
width?: number
|
|
5
|
+
height?: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface NativeLinearListLayoutIOSConfig {
|
|
9
|
+
estimatedItemSize?: NativeItemSizeEstimate
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface NativeLinearListLayoutConfig {
|
|
13
|
+
topInset: number
|
|
14
|
+
bottomInset: number
|
|
15
|
+
itemSpacing: number
|
|
16
|
+
itemHorizontalInset: number
|
|
17
|
+
itemVerticalInset: number
|
|
18
|
+
iosConfig?: NativeLinearListLayoutIOSConfig
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface NativeLinearListLayout extends NativeListLayout {
|
|
22
|
+
setConfig(config: NativeLinearListLayoutConfig): void
|
|
23
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AnyMap, HybridObject, Sync } from 'react-native-nitro-modules'
|
|
2
|
+
|
|
3
|
+
export interface NativeListItem {
|
|
4
|
+
key: string
|
|
5
|
+
type: string
|
|
6
|
+
width?: number
|
|
7
|
+
height?: number
|
|
8
|
+
data: AnyMap
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface NativeListDataSource extends HybridObject<{
|
|
12
|
+
android: 'kotlin'
|
|
13
|
+
ios: 'swift'
|
|
14
|
+
}> {
|
|
15
|
+
setContentEqualCallback(
|
|
16
|
+
isContentEqual: Sync<
|
|
17
|
+
(oldItem: NativeListItem, newItem: NativeListItem) => boolean
|
|
18
|
+
>
|
|
19
|
+
): void
|
|
20
|
+
|
|
21
|
+
replaceData(items: NativeListItem[], animated: boolean): void
|
|
22
|
+
insertItem(index: number, item: NativeListItem): void
|
|
23
|
+
updateItem(index: number, item: NativeListItem): void
|
|
24
|
+
removeItem(index: number): void
|
|
25
|
+
moveItem(fromIndex: number, toIndex: number): void
|
|
26
|
+
getCount(): number
|
|
27
|
+
getItem(index: number): NativeListItem
|
|
28
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { HybridObject } from 'react-native-nitro-modules'
|
|
2
|
+
import type { IOSWorkletsModuleProxyHolder } from './IOSWorkletsModuleProxyHolder.nitro'
|
|
3
|
+
// import { ViewHolder } from './ViewHolder.nitro'
|
|
4
|
+
|
|
5
|
+
export interface UiListModule extends HybridObject<{
|
|
6
|
+
android: 'kotlin'
|
|
7
|
+
ios: 'swift'
|
|
8
|
+
}> {
|
|
9
|
+
// TODO: on iOS getting the worklets proxy has JS thread asserts, so we have to get it from JS and pass it to the UI thread. Maybe we can change that in nitro at some point?
|
|
10
|
+
iosGetWorkletsModule(): IOSWorkletsModuleProxyHolder
|
|
11
|
+
setupRuntime(workletsModuleHolder: IOSWorkletsModuleProxyHolder | null): void
|
|
12
|
+
// renderAndGetView(tag: number): ViewHolder
|
|
13
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { CustomType, HybridObject } from 'react-native-nitro-modules'
|
|
2
|
+
|
|
3
|
+
type UiManagerBidningType = {
|
|
4
|
+
_stubToMakeNitroHappy_doesNotExist_doNotUse: void
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type UiManagerBinding = CustomType<
|
|
8
|
+
UiManagerBidningType,
|
|
9
|
+
'std::shared_ptr<facebook::react::UIManagerBinding>',
|
|
10
|
+
{ include: 'JSIConverter+UIManagerBinding.hpp' }
|
|
11
|
+
>
|
|
12
|
+
|
|
13
|
+
type ShadowNodeListType = {
|
|
14
|
+
_stubToMakeNitroHappy_doesNotExist_doNotUse: void
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type ShadowNodeList = CustomType<
|
|
18
|
+
ShadowNodeListType,
|
|
19
|
+
'facebook::react::ShadowNode::UnsharedListOfShared',
|
|
20
|
+
{ include: 'JSIConverter+ShadowNodeList.hpp' }
|
|
21
|
+
>
|
|
22
|
+
|
|
23
|
+
export interface UiManagerHelper extends HybridObject<{
|
|
24
|
+
android: 'c++'
|
|
25
|
+
ios: 'c++'
|
|
26
|
+
}> {
|
|
27
|
+
completeRootSync(
|
|
28
|
+
nativeFabricUIManager: UiManagerBinding,
|
|
29
|
+
surfaceId: number,
|
|
30
|
+
childSet: ShadowNodeList
|
|
31
|
+
): void
|
|
32
|
+
registerManagedSurface(surfaceId: number): void
|
|
33
|
+
unregisterManagedSurface(surfaceId: number): void
|
|
34
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HybridView,
|
|
3
|
+
HybridViewMethods,
|
|
4
|
+
HybridViewProps,
|
|
5
|
+
Sync,
|
|
6
|
+
} from 'react-native-nitro-modules'
|
|
7
|
+
import {
|
|
8
|
+
NativeListDataSource,
|
|
9
|
+
NativeListItem,
|
|
10
|
+
} from './NativeListDataSource.nitro'
|
|
11
|
+
import { NativeListLayout } from './NativeListLayout.nitro'
|
|
12
|
+
import { UiListModule } from './UIListModule.nitro'
|
|
13
|
+
|
|
14
|
+
export interface UiListViewProps extends HybridViewProps {}
|
|
15
|
+
|
|
16
|
+
export interface UiListViewMethods extends HybridViewMethods {
|
|
17
|
+
setListCallbacks(
|
|
18
|
+
uiListModule: UiListModule,
|
|
19
|
+
createView: Sync<(type: string) => number>,
|
|
20
|
+
updateView: Sync<
|
|
21
|
+
(reactTag: number, item: NativeListItem, index: number) => boolean
|
|
22
|
+
>
|
|
23
|
+
): void
|
|
24
|
+
|
|
25
|
+
setDataSource(dataSource: NativeListDataSource): void
|
|
26
|
+
setLayout(layout: NativeListLayout): void
|
|
27
|
+
getSurfaceId(): number
|
|
28
|
+
disposeRendererSurface(): void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type UiListView = HybridView<UiListViewProps, UiListViewMethods>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// import type { ColorValue } from "react-native";
|
|
2
|
+
import type {
|
|
3
|
+
HybridView,
|
|
4
|
+
HybridViewMethods,
|
|
5
|
+
HybridViewProps,
|
|
6
|
+
} from 'react-native-nitro-modules'
|
|
7
|
+
|
|
8
|
+
export interface ViewHolderProps extends HybridViewProps {}
|
|
9
|
+
|
|
10
|
+
export interface ViewHolderMethods extends HybridViewMethods {}
|
|
11
|
+
export type ViewHolder = HybridView<ViewHolderProps, ViewHolderMethods>
|
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
|
|
2
|
+
import { View, ViewStyle } from 'react-native'
|
|
3
|
+
import { callback, NitroModules } from 'react-native-nitro-modules'
|
|
4
|
+
import {
|
|
5
|
+
createShareable,
|
|
6
|
+
scheduleOnUI,
|
|
7
|
+
UIRuntimeId,
|
|
8
|
+
} from 'react-native-worklets'
|
|
9
|
+
import type {
|
|
10
|
+
ListDataSource,
|
|
11
|
+
ListDataSourceMutation,
|
|
12
|
+
ListItem,
|
|
13
|
+
ListItemForType,
|
|
14
|
+
ListItemType,
|
|
15
|
+
} from '../ListDataSource'
|
|
16
|
+
import {
|
|
17
|
+
addListDataSourceMutationListener,
|
|
18
|
+
getNativeListDataSource,
|
|
19
|
+
} from '../ListDataSource'
|
|
20
|
+
import { createLinearListLayout, ListLayout } from '../ListLayout'
|
|
21
|
+
import { useChangeEffect } from '../hooks/useChangeEffect'
|
|
22
|
+
import {
|
|
23
|
+
completeRootSyncWorklet,
|
|
24
|
+
registerManagedSurfaceWorklet,
|
|
25
|
+
unregisterManagedSurfaceWorklet,
|
|
26
|
+
uiListModuleBoxed,
|
|
27
|
+
} from '../renderer/fabric/RenderHelper'
|
|
28
|
+
import { getReactFabricRenderer } from '../renderer/react/ReactFabricRenderer'
|
|
29
|
+
import type { NativeListItem } from '../specs/NativeListDataSource.nitro'
|
|
30
|
+
import type { UiListViewMethods } from '../specs/UiListView.nitro'
|
|
31
|
+
import { UiListHostComponent } from './UiListHostComponent'
|
|
32
|
+
|
|
33
|
+
type NativeTaggedRef = {
|
|
34
|
+
__nativeTag: number
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type RenderedElementRecord = {
|
|
38
|
+
element: React.ReactElement
|
|
39
|
+
/**
|
|
40
|
+
* Stable React element key for a rendered slot in our tree.
|
|
41
|
+
*/
|
|
42
|
+
reactKey: number
|
|
43
|
+
/**
|
|
44
|
+
* Datasource item identity.
|
|
45
|
+
* The user provided key for an item with data.
|
|
46
|
+
*/
|
|
47
|
+
dataKey: string | null
|
|
48
|
+
/**
|
|
49
|
+
* Native React tag binding this React instance to a React Native view.
|
|
50
|
+
* A React tag can exist without a dataKey while the view is not currently
|
|
51
|
+
* bound to a datasource item.
|
|
52
|
+
*/
|
|
53
|
+
reactTag: number
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
type ListState = {
|
|
57
|
+
elementRecords: RenderedElementRecord[]
|
|
58
|
+
reactTagToRecordIndex: Record<number, number>
|
|
59
|
+
reactTagToReactKey: Record<number, number>
|
|
60
|
+
reactTagToDataKey: Record<number, string>
|
|
61
|
+
dataKeyToReactTag: Record<string, number>
|
|
62
|
+
nextReactKey: number
|
|
63
|
+
isDisposed: boolean
|
|
64
|
+
surfaceId: number | null
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type ListRenderer<TItem extends ListItem> = {
|
|
68
|
+
renderItemWorklet: (info: {
|
|
69
|
+
item?: TItem
|
|
70
|
+
index?: number
|
|
71
|
+
key?: string
|
|
72
|
+
type: ListItemType<TItem>
|
|
73
|
+
}) => React.ReactElement<any>
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export type ListRenderers<TItem extends ListItem> = {
|
|
77
|
+
[TType in ListItemType<TItem>]: ListRenderer<ListItemForType<TItem, TType>>
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type ListProps<TItem extends ListItem> = {
|
|
81
|
+
dataSource: ListDataSource<TItem>
|
|
82
|
+
layout?: ListLayout
|
|
83
|
+
renderers: ListRenderers<TItem>
|
|
84
|
+
style?: ViewStyle
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function ListInner<TItem extends ListItem>(props: ListProps<TItem>) {
|
|
88
|
+
const { dataSource, layout, renderers, style } = props
|
|
89
|
+
const isSetup = useRef(false)
|
|
90
|
+
const nativeListRef = useRef<UiListViewMethods | null>(null)
|
|
91
|
+
|
|
92
|
+
const listState = useMemo(() => {
|
|
93
|
+
return createShareable<ListState>(UIRuntimeId, {
|
|
94
|
+
elementRecords: [],
|
|
95
|
+
nextReactKey: 0,
|
|
96
|
+
reactTagToRecordIndex: {},
|
|
97
|
+
reactTagToReactKey: {},
|
|
98
|
+
// Maintain two reverse lookups that are one-to-one
|
|
99
|
+
// Used for O(1) operations in element updates and removals,
|
|
100
|
+
// where we only get the reactTag from native, and need to find the record,
|
|
101
|
+
// or need to find the reactTag for a dataKey
|
|
102
|
+
reactTagToDataKey: {},
|
|
103
|
+
dataKeyToReactTag: {},
|
|
104
|
+
isDisposed: false,
|
|
105
|
+
surfaceId: null,
|
|
106
|
+
})
|
|
107
|
+
}, [])
|
|
108
|
+
|
|
109
|
+
const getListState = useCallback(() => {
|
|
110
|
+
'worklet'
|
|
111
|
+
if (listState.isHost === false) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
'Expected listState to be only accessed on the UI Runtime!'
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
return listState.value
|
|
117
|
+
}, [listState])
|
|
118
|
+
|
|
119
|
+
const resolvedLayout = useMemo(() => {
|
|
120
|
+
if (layout != null) {
|
|
121
|
+
return layout
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return createLinearListLayout()
|
|
125
|
+
}, [layout])
|
|
126
|
+
|
|
127
|
+
const ownsResolvedLayout = layout == null
|
|
128
|
+
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
if (!ownsResolvedLayout) {
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return () => {
|
|
135
|
+
resolvedLayout.release()
|
|
136
|
+
}
|
|
137
|
+
}, [ownsResolvedLayout, resolvedLayout])
|
|
138
|
+
|
|
139
|
+
const boxedDataSource = useMemo(() => {
|
|
140
|
+
const nativeDataSource = getNativeListDataSource(dataSource)
|
|
141
|
+
return NitroModules.box(nativeDataSource)
|
|
142
|
+
}, [dataSource])
|
|
143
|
+
|
|
144
|
+
const boxedLayout = useMemo(() => {
|
|
145
|
+
return NitroModules.box(resolvedLayout.__nativeLayout)
|
|
146
|
+
}, [resolvedLayout])
|
|
147
|
+
|
|
148
|
+
const clearListItemKeys = useMemo(() => {
|
|
149
|
+
return () => {
|
|
150
|
+
'worklet'
|
|
151
|
+
|
|
152
|
+
const state = getListState()
|
|
153
|
+
state.elementRecords.forEach((record) => {
|
|
154
|
+
record.dataKey = null
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
for (const tagKey of Object.keys(state.reactTagToDataKey)) {
|
|
158
|
+
delete state.reactTagToDataKey[Number(tagKey)]
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
for (const dataKey of Object.keys(state.dataKeyToReactTag)) {
|
|
162
|
+
delete state.dataKeyToReactTag[dataKey]
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}, [getListState])
|
|
166
|
+
|
|
167
|
+
const handleDataSourceMutation = useMemo(() => {
|
|
168
|
+
return (mutation: ListDataSourceMutation) => {
|
|
169
|
+
'worklet'
|
|
170
|
+
|
|
171
|
+
if (mutation.type === 'replaceData') {
|
|
172
|
+
clearListItemKeys()
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
let dataKey: string
|
|
177
|
+
if (mutation.type === 'removeItem') {
|
|
178
|
+
dataKey = mutation.itemKey
|
|
179
|
+
} else {
|
|
180
|
+
dataKey = mutation.previousItemKey
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const state = getListState()
|
|
184
|
+
const reactTag = state.dataKeyToReactTag[dataKey]
|
|
185
|
+
if (reactTag == null) {
|
|
186
|
+
return
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const position = state.reactTagToRecordIndex[reactTag]
|
|
190
|
+
if (position == null) {
|
|
191
|
+
delete state.dataKeyToReactTag[dataKey]
|
|
192
|
+
delete state.reactTagToDataKey[reactTag]
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const record = state.elementRecords[position]
|
|
197
|
+
if (record == null) {
|
|
198
|
+
delete state.dataKeyToReactTag[dataKey]
|
|
199
|
+
delete state.reactTagToDataKey[reactTag]
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (record.dataKey !== dataKey) {
|
|
204
|
+
delete state.dataKeyToReactTag[dataKey]
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
record.dataKey = null
|
|
209
|
+
delete state.dataKeyToReactTag[dataKey]
|
|
210
|
+
delete state.reactTagToDataKey[reactTag]
|
|
211
|
+
}
|
|
212
|
+
}, [clearListItemKeys, getListState])
|
|
213
|
+
|
|
214
|
+
useEffect(() => {
|
|
215
|
+
return addListDataSourceMutationListener(
|
|
216
|
+
dataSource,
|
|
217
|
+
handleDataSourceMutation
|
|
218
|
+
)
|
|
219
|
+
}, [dataSource, handleDataSourceMutation])
|
|
220
|
+
|
|
221
|
+
useEffect(() => {
|
|
222
|
+
return () => {
|
|
223
|
+
const ref = nativeListRef.current
|
|
224
|
+
const didSetup = isSetup.current
|
|
225
|
+
|
|
226
|
+
nativeListRef.current = null
|
|
227
|
+
isSetup.current = false
|
|
228
|
+
|
|
229
|
+
if (ref == null) {
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
scheduleOnUI(() => {
|
|
234
|
+
'worklet'
|
|
235
|
+
|
|
236
|
+
const state = getListState()
|
|
237
|
+
state.isDisposed = true
|
|
238
|
+
|
|
239
|
+
if (!didSetup) {
|
|
240
|
+
ref.disposeRendererSurface()
|
|
241
|
+
return
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const surfaceId = state.surfaceId
|
|
245
|
+
ref.disposeRendererSurface()
|
|
246
|
+
state.surfaceId = null
|
|
247
|
+
|
|
248
|
+
if (surfaceId == null) {
|
|
249
|
+
return
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const { disposeReactRoot } = getReactFabricRenderer()
|
|
253
|
+
unregisterManagedSurfaceWorklet(surfaceId)
|
|
254
|
+
disposeReactRoot(surfaceId, completeRootSyncWorklet)
|
|
255
|
+
state.elementRecords = []
|
|
256
|
+
|
|
257
|
+
for (const key of Object.keys(state.reactTagToRecordIndex)) {
|
|
258
|
+
delete state.reactTagToRecordIndex[Number(key)]
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
for (const key of Object.keys(state.reactTagToReactKey)) {
|
|
262
|
+
delete state.reactTagToReactKey[Number(key)]
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
for (const key of Object.keys(state.reactTagToDataKey)) {
|
|
266
|
+
delete state.reactTagToDataKey[Number(key)]
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
for (const key of Object.keys(state.dataKeyToReactTag)) {
|
|
270
|
+
delete state.dataKeyToReactTag[key]
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
}
|
|
274
|
+
}, [getListState])
|
|
275
|
+
|
|
276
|
+
useChangeEffect(() => {
|
|
277
|
+
const ref = nativeListRef.current
|
|
278
|
+
if (ref == null) return
|
|
279
|
+
|
|
280
|
+
scheduleOnUI(clearListItemKeys)
|
|
281
|
+
|
|
282
|
+
const nativeDataSource = getNativeListDataSource(dataSource)
|
|
283
|
+
ref.setDataSource(nativeDataSource)
|
|
284
|
+
ref.setLayout(resolvedLayout.__nativeLayout)
|
|
285
|
+
}, [clearListItemKeys, dataSource, resolvedLayout])
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
<UiListHostComponent
|
|
289
|
+
style={style}
|
|
290
|
+
hybridRef={callback((ref) => {
|
|
291
|
+
nativeListRef.current = ref
|
|
292
|
+
|
|
293
|
+
if (isSetup.current) return
|
|
294
|
+
isSetup.current = true
|
|
295
|
+
|
|
296
|
+
scheduleOnUI(() => {
|
|
297
|
+
'worklet'
|
|
298
|
+
|
|
299
|
+
const { reactRender } = getReactFabricRenderer()
|
|
300
|
+
const state = getListState()
|
|
301
|
+
const surfaceId = ref.getSurfaceId()
|
|
302
|
+
state.isDisposed = false
|
|
303
|
+
state.surfaceId = surfaceId
|
|
304
|
+
registerManagedSurfaceWorklet(surfaceId)
|
|
305
|
+
|
|
306
|
+
function renderListElements() {
|
|
307
|
+
'worklet'
|
|
308
|
+
|
|
309
|
+
return state.elementRecords.map((record) => {
|
|
310
|
+
const wrapperStyle = {
|
|
311
|
+
// Why are we rendering position absolute?
|
|
312
|
+
// This will layout all items at (0x0).This is important because the native lists will relayout the views.
|
|
313
|
+
// In one iteration I was rendering all items just regularly. When then the items position in the elements changed or items were added before,
|
|
314
|
+
// fabric was thinking it had to update the layout position of those items, breaking the layout in the list.
|
|
315
|
+
// If fabric thinks all items are always at (0x0) it won't get the idea to relocate them!
|
|
316
|
+
position: 'absolute' as const,
|
|
317
|
+
left: 0,
|
|
318
|
+
top: 0,
|
|
319
|
+
}
|
|
320
|
+
const wrapperKey = 'reactkey-wrapper-' + record.reactKey
|
|
321
|
+
return (
|
|
322
|
+
<View key={wrapperKey} style={wrapperStyle} collapsable={false}>
|
|
323
|
+
{record.element}
|
|
324
|
+
</View>
|
|
325
|
+
)
|
|
326
|
+
})
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function rebuildTagPositions() {
|
|
330
|
+
'worklet'
|
|
331
|
+
|
|
332
|
+
for (const key of Object.keys(state.reactTagToRecordIndex)) {
|
|
333
|
+
delete state.reactTagToRecordIndex[Number(key)]
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
state.elementRecords.forEach((record, index) => {
|
|
337
|
+
if (record.reactTag < 0) {
|
|
338
|
+
return
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
state.reactTagToRecordIndex[record.reactTag] = index
|
|
342
|
+
})
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function bindDataKeyToReactTag(dataKey: string, reactTag: number) {
|
|
346
|
+
'worklet'
|
|
347
|
+
|
|
348
|
+
const previousDataKey = state.reactTagToDataKey[reactTag]
|
|
349
|
+
if (previousDataKey != null && previousDataKey !== dataKey) {
|
|
350
|
+
// This same reactTag used to represent another dataKey.
|
|
351
|
+
// If it is now being assigned to dataKey, remove the old reverse lookup
|
|
352
|
+
delete state.dataKeyToReactTag[previousDataKey]
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const previousReactTag = state.dataKeyToReactTag[dataKey]
|
|
356
|
+
if (previousReactTag != null && previousReactTag !== reactTag) {
|
|
357
|
+
// This dataKey used to point at another reactTag.
|
|
358
|
+
// If it is now being assigned to this reactTag, clear the old tag's binding
|
|
359
|
+
const previousPosition =
|
|
360
|
+
state.reactTagToRecordIndex[previousReactTag]
|
|
361
|
+
if (previousPosition != null) {
|
|
362
|
+
const previousRecord = state.elementRecords[previousPosition]
|
|
363
|
+
if (previousRecord != null) {
|
|
364
|
+
previousRecord.dataKey = null
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
delete state.reactTagToDataKey[previousReactTag]
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
state.reactTagToDataKey[reactTag] = dataKey
|
|
371
|
+
state.dataKeyToReactTag[dataKey] = reactTag
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function renderContentInReact() {
|
|
375
|
+
'worklet'
|
|
376
|
+
|
|
377
|
+
if (state.isDisposed) {
|
|
378
|
+
return
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const elements = renderListElements()
|
|
382
|
+
const parentContainer = <View>{elements}</View>
|
|
383
|
+
reactRender(
|
|
384
|
+
surfaceId,
|
|
385
|
+
parentContainer,
|
|
386
|
+
() => {},
|
|
387
|
+
completeRootSyncWorklet
|
|
388
|
+
)
|
|
389
|
+
rebuildTagPositions()
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function setNativeListDataSource() {
|
|
393
|
+
'worklet'
|
|
394
|
+
|
|
395
|
+
const nativeDataSource = boxedDataSource.unbox()
|
|
396
|
+
const nativeLayout = boxedLayout.unbox()
|
|
397
|
+
ref.setDataSource(nativeDataSource)
|
|
398
|
+
ref.setLayout(nativeLayout)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function createViewCallback(type: string) {
|
|
402
|
+
if (state.isDisposed) {
|
|
403
|
+
throw new Error('Cannot create view after list was disposed')
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const nativeRef = globalThis.React.createRef<NativeTaggedRef>()
|
|
407
|
+
const reactKey = state.nextReactKey++
|
|
408
|
+
const typedType = type as ListItemType<TItem>
|
|
409
|
+
const renderer = renderers[typedType] as ListRenderer<TItem>
|
|
410
|
+
|
|
411
|
+
if (renderer == null) {
|
|
412
|
+
throw new Error('No renderer for list item type ' + type)
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const newElement = renderer.renderItemWorklet({
|
|
416
|
+
type: typedType,
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
const newProps = {
|
|
420
|
+
key: 'reactkey-' + reactKey,
|
|
421
|
+
ref: nativeRef,
|
|
422
|
+
collapsable: false,
|
|
423
|
+
}
|
|
424
|
+
const newElementWithKey = globalThis.React.cloneElement(
|
|
425
|
+
newElement,
|
|
426
|
+
newProps
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
const newRecord: RenderedElementRecord = {
|
|
430
|
+
element: newElementWithKey,
|
|
431
|
+
reactKey,
|
|
432
|
+
dataKey: null,
|
|
433
|
+
reactTag: -1,
|
|
434
|
+
}
|
|
435
|
+
const newLength = state.elementRecords.push(newRecord)
|
|
436
|
+
const currentIndex = newLength - 1
|
|
437
|
+
|
|
438
|
+
// Why for rendering one item we have to render the whole content?!
|
|
439
|
+
// Thats because react/react-native would issue remove transitions if we'd only render the item we need, and then swap it for another item.
|
|
440
|
+
// When rendering all content react-reconciler will only update the diff on the native side, which is just this one item, so performance wise this seems to be okay.
|
|
441
|
+
renderContentInReact()
|
|
442
|
+
|
|
443
|
+
if (nativeRef.current == null) {
|
|
444
|
+
throw new Error('Ref is null after render')
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const reactTag = nativeRef.current.__nativeTag
|
|
448
|
+
newRecord.reactTag = reactTag
|
|
449
|
+
state.reactTagToRecordIndex[reactTag] = currentIndex
|
|
450
|
+
state.reactTagToReactKey[reactTag] = reactKey
|
|
451
|
+
|
|
452
|
+
return reactTag
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function updateViewCallback(
|
|
456
|
+
reactTag: number,
|
|
457
|
+
item: NativeListItem,
|
|
458
|
+
index: number
|
|
459
|
+
) {
|
|
460
|
+
if (state.isDisposed) {
|
|
461
|
+
return false
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const typedType: ListItemType<TItem> = item.type
|
|
465
|
+
const renderer = renderers[typedType] as ListRenderer<TItem>
|
|
466
|
+
|
|
467
|
+
if (renderer == null) {
|
|
468
|
+
throw new Error('No renderer for list item type ' + item.type)
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const reactKey = state.reactTagToReactKey[reactTag]
|
|
472
|
+
if (reactKey == null) {
|
|
473
|
+
throw new Error('No reactKey for reactTag ' + reactTag)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const newElement = renderer.renderItemWorklet({
|
|
477
|
+
item: item as unknown as TItem,
|
|
478
|
+
index,
|
|
479
|
+
key: item.key,
|
|
480
|
+
type: typedType,
|
|
481
|
+
})
|
|
482
|
+
const newProps = {
|
|
483
|
+
key: 'reactkey-' + reactKey,
|
|
484
|
+
collapsable: false,
|
|
485
|
+
}
|
|
486
|
+
const newElementWithKey = globalThis.React.cloneElement(
|
|
487
|
+
newElement,
|
|
488
|
+
newProps
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
const position = state.reactTagToRecordIndex[reactTag]
|
|
492
|
+
if (position == null) {
|
|
493
|
+
throw new Error('No position for reactTag ' + reactTag)
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const record = state.elementRecords[position]
|
|
497
|
+
if (record == null) {
|
|
498
|
+
throw new Error('No record for reactTag ' + reactTag)
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
bindDataKeyToReactTag(item.key, reactTag)
|
|
502
|
+
record.element = newElementWithKey
|
|
503
|
+
record.dataKey = item.key
|
|
504
|
+
|
|
505
|
+
renderContentInReact()
|
|
506
|
+
|
|
507
|
+
return true
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const uiListModuleUnboxed = uiListModuleBoxed.unbox()
|
|
511
|
+
ref.setListCallbacks(
|
|
512
|
+
uiListModuleUnboxed,
|
|
513
|
+
createViewCallback,
|
|
514
|
+
updateViewCallback
|
|
515
|
+
)
|
|
516
|
+
setNativeListDataSource()
|
|
517
|
+
})
|
|
518
|
+
})}
|
|
519
|
+
/>
|
|
520
|
+
)
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
export const List = ListInner as <TItem extends ListItem>(
|
|
524
|
+
props: ListProps<TItem>
|
|
525
|
+
) => React.ReactElement | null
|