react-native-list 1.0.0 → 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +190 -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/metro/RendererProxyThreadSwitch.js +66 -0
- package/metro-config.d.ts +1 -0
- package/metro-config.js +52 -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/ListView/__mocks__/ListViewMock.js +0 -55
- 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/__flowtests__/FlatList-flowtest.js +0 -90
- package/__flowtests__/SectionList-flowtest.js +0 -89
- package/__tests__/FillRateHelper-test.js +0 -106
- package/__tests__/FlatList-test.js +0 -64
- package/__tests__/SectionList-test.js +0 -67
- package/__tests__/ViewabilityHelper-test.js +0 -359
- package/__tests__/VirtualizeUtils-test.js +0 -74
- package/__tests__/__snapshots__/FlatList-test.js.snap +0 -251
- package/__tests__/__snapshots__/SectionList-test.js.snap +0 -283
- package/index.js +0 -5
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { NitroModules } from 'react-native-nitro-modules'
|
|
2
|
+
import type { AnyMap } from 'react-native-nitro-modules'
|
|
3
|
+
import type { NativeListDataSource } from './specs/NativeListDataSource.nitro'
|
|
4
|
+
import { useEffect, useRef } from 'react'
|
|
5
|
+
import { scheduleOnUI } from 'react-native-worklets'
|
|
6
|
+
|
|
7
|
+
export type ListKey = string
|
|
8
|
+
|
|
9
|
+
export type ListItemSize = {
|
|
10
|
+
width?: number
|
|
11
|
+
height?: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type ListItem<
|
|
15
|
+
Type = string,
|
|
16
|
+
TData extends AnyMap = AnyMap,
|
|
17
|
+
> = ListItemSize & {
|
|
18
|
+
key: ListKey
|
|
19
|
+
type: Type
|
|
20
|
+
data: TData
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type ListItemType<TItem extends ListItem> = TItem['type']
|
|
24
|
+
|
|
25
|
+
export type ListItemForType<
|
|
26
|
+
TItem extends ListItem,
|
|
27
|
+
TType extends ListItemType<TItem>,
|
|
28
|
+
> =
|
|
29
|
+
Extract<TItem, { type: TType }> extends never
|
|
30
|
+
? TItem
|
|
31
|
+
: Extract<TItem, { type: TType }>
|
|
32
|
+
|
|
33
|
+
export type ListContentEqualByType<TItem extends ListItem> = {
|
|
34
|
+
[TType in ListItemType<TItem>]: (
|
|
35
|
+
oldItem: ListItemForType<TItem, TType>,
|
|
36
|
+
newItem: ListItemForType<TItem, TType>
|
|
37
|
+
) => boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type ListDataSourceConfig<TItem extends ListItem> = {
|
|
41
|
+
isContentEqualByType?: ListContentEqualByType<TItem>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type ListDataSource<TItem extends ListItem> = {
|
|
45
|
+
release(): void
|
|
46
|
+
replaceData(data: readonly TItem[], animated?: boolean): void
|
|
47
|
+
insertItem(index: number, item: TItem): void
|
|
48
|
+
updateItem(index: number, item: TItem): void
|
|
49
|
+
removeItem(index: number): void
|
|
50
|
+
moveItem(fromIndex: number, toIndex: number): void
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type ListDataSourceMutation =
|
|
54
|
+
| {
|
|
55
|
+
type: 'replaceData'
|
|
56
|
+
}
|
|
57
|
+
| {
|
|
58
|
+
type: 'removeItem'
|
|
59
|
+
itemKey: string
|
|
60
|
+
}
|
|
61
|
+
| {
|
|
62
|
+
type: 'updateItem'
|
|
63
|
+
previousItemKey: string
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type ListDataSourceMutationListener = (mutation: ListDataSourceMutation) => void
|
|
67
|
+
|
|
68
|
+
type NativeListDataSourceBacked<TItem extends ListItem> =
|
|
69
|
+
ListDataSource<TItem> & {
|
|
70
|
+
__nativeDataSource: NativeListDataSource
|
|
71
|
+
__setConfig(config: unknown): void
|
|
72
|
+
__addMutationListener(listener: ListDataSourceMutationListener): () => void
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function setContentEqualCallback<TItem extends ListItem>(
|
|
76
|
+
nativeDataSource: NativeListDataSource,
|
|
77
|
+
config: ListDataSourceConfig<TItem>
|
|
78
|
+
) {
|
|
79
|
+
nativeDataSource.setContentEqualCallback((oldItem, newItem) => {
|
|
80
|
+
if (oldItem.type !== newItem.type) {
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
if (oldItem.width !== newItem.width) {
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
if (oldItem.height !== newItem.height) {
|
|
87
|
+
return false
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const type = newItem.type as TItem['type']
|
|
91
|
+
const isContentEqual = config.isContentEqualByType?.[type]
|
|
92
|
+
if (isContentEqual == null) {
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return isContentEqual(
|
|
97
|
+
oldItem as unknown as ListItemForType<TItem, typeof type>,
|
|
98
|
+
newItem as unknown as ListItemForType<TItem, typeof type>
|
|
99
|
+
)
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function createListDataSource<TItem extends ListItem>(
|
|
104
|
+
config: ListDataSourceConfig<TItem> = {}
|
|
105
|
+
): ListDataSource<TItem> {
|
|
106
|
+
const nativeDataSource =
|
|
107
|
+
NitroModules.createHybridObject<NativeListDataSource>(
|
|
108
|
+
'NativeListDataSource'
|
|
109
|
+
)
|
|
110
|
+
let currentConfig = config
|
|
111
|
+
let currentItems: TItem[] = []
|
|
112
|
+
const mutationListeners = new Set<ListDataSourceMutationListener>()
|
|
113
|
+
|
|
114
|
+
setContentEqualCallback(nativeDataSource, currentConfig)
|
|
115
|
+
|
|
116
|
+
function notifyMutationListeners(mutation: ListDataSourceMutation) {
|
|
117
|
+
mutationListeners.forEach((listener) => {
|
|
118
|
+
scheduleOnUI(listener, mutation)
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const dataSource: NativeListDataSourceBacked<TItem> = {
|
|
123
|
+
__nativeDataSource: nativeDataSource,
|
|
124
|
+
__setConfig(nextConfig: unknown) {
|
|
125
|
+
currentConfig = nextConfig as unknown as ListDataSourceConfig<TItem>
|
|
126
|
+
setContentEqualCallback(nativeDataSource, currentConfig)
|
|
127
|
+
},
|
|
128
|
+
__addMutationListener(listener: ListDataSourceMutationListener) {
|
|
129
|
+
mutationListeners.add(listener)
|
|
130
|
+
return () => {
|
|
131
|
+
mutationListeners.delete(listener)
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
release() {
|
|
135
|
+
currentConfig = {}
|
|
136
|
+
currentItems = []
|
|
137
|
+
mutationListeners.clear()
|
|
138
|
+
nativeDataSource.dispose()
|
|
139
|
+
},
|
|
140
|
+
replaceData(data: readonly TItem[], animated: boolean = false) {
|
|
141
|
+
const nextItems = [...data]
|
|
142
|
+
currentItems = nextItems
|
|
143
|
+
notifyMutationListeners({
|
|
144
|
+
type: 'replaceData',
|
|
145
|
+
})
|
|
146
|
+
nativeDataSource.replaceData(nextItems, animated)
|
|
147
|
+
},
|
|
148
|
+
insertItem(index: number, item: TItem) {
|
|
149
|
+
currentItems.splice(index, 0, item)
|
|
150
|
+
nativeDataSource.insertItem(index, item)
|
|
151
|
+
},
|
|
152
|
+
updateItem(index: number, item: TItem) {
|
|
153
|
+
const previousItem = currentItems[index]
|
|
154
|
+
if (previousItem != null && previousItem.key !== item.key) {
|
|
155
|
+
currentItems[index] = item
|
|
156
|
+
notifyMutationListeners({
|
|
157
|
+
type: 'updateItem',
|
|
158
|
+
previousItemKey: previousItem.key,
|
|
159
|
+
})
|
|
160
|
+
nativeDataSource.updateItem(index, item)
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
currentItems[index] = item
|
|
165
|
+
nativeDataSource.updateItem(index, item)
|
|
166
|
+
},
|
|
167
|
+
removeItem(index: number) {
|
|
168
|
+
const removedItems = currentItems.slice(index, index + 1)
|
|
169
|
+
const removedItem = removedItems[0]
|
|
170
|
+
currentItems.splice(index, 1)
|
|
171
|
+
if (removedItem != null) {
|
|
172
|
+
notifyMutationListeners({
|
|
173
|
+
type: 'removeItem',
|
|
174
|
+
itemKey: removedItem.key,
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
nativeDataSource.removeItem(index)
|
|
178
|
+
},
|
|
179
|
+
moveItem(fromIndex: number, toIndex: number) {
|
|
180
|
+
const removedItems = currentItems.slice(fromIndex, fromIndex + 1)
|
|
181
|
+
const movedItem = removedItems[0]
|
|
182
|
+
if (movedItem != null) {
|
|
183
|
+
currentItems.splice(fromIndex, 1)
|
|
184
|
+
currentItems.splice(toIndex, 0, movedItem)
|
|
185
|
+
}
|
|
186
|
+
nativeDataSource.moveItem(fromIndex, toIndex)
|
|
187
|
+
},
|
|
188
|
+
}
|
|
189
|
+
return dataSource
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function getNativeListDataSource<TItem extends ListItem>(
|
|
193
|
+
dataSource: ListDataSource<TItem>
|
|
194
|
+
): NativeListDataSource {
|
|
195
|
+
const nativeBackedDataSource = dataSource as NativeListDataSourceBacked<TItem>
|
|
196
|
+
return nativeBackedDataSource.__nativeDataSource
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function addListDataSourceMutationListener<TItem extends ListItem>(
|
|
200
|
+
dataSource: ListDataSource<TItem>,
|
|
201
|
+
listener: ListDataSourceMutationListener
|
|
202
|
+
) {
|
|
203
|
+
const nativeBackedDataSource = dataSource as NativeListDataSourceBacked<TItem>
|
|
204
|
+
return nativeBackedDataSource.__addMutationListener(listener)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export function useListDataSource<TItem extends ListItem>(
|
|
208
|
+
config: ListDataSourceConfig<TItem> & {
|
|
209
|
+
data: readonly TItem[]
|
|
210
|
+
}
|
|
211
|
+
): ListDataSource<TItem> {
|
|
212
|
+
const dataSourceRef = useRef<ListDataSource<TItem> | null>(null)
|
|
213
|
+
if (dataSourceRef.current == null) {
|
|
214
|
+
dataSourceRef.current = createListDataSource(config)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const dataSource = dataSourceRef.current
|
|
218
|
+
const nativeBackedDataSource = dataSource as NativeListDataSourceBacked<TItem>
|
|
219
|
+
|
|
220
|
+
useEffect(() => {
|
|
221
|
+
nativeBackedDataSource.__setConfig(config)
|
|
222
|
+
dataSource.replaceData(config.data, true)
|
|
223
|
+
}, [config, dataSource, nativeBackedDataSource])
|
|
224
|
+
|
|
225
|
+
useEffect(() => {
|
|
226
|
+
return () => {
|
|
227
|
+
dataSource.release()
|
|
228
|
+
}
|
|
229
|
+
}, [dataSource])
|
|
230
|
+
|
|
231
|
+
return dataSource
|
|
232
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { NitroModules } from 'react-native-nitro-modules'
|
|
2
|
+
import { useEffect, useMemo } from 'react'
|
|
3
|
+
import type { NativeListLayout } from './specs/NativeListLayout.nitro'
|
|
4
|
+
import type {
|
|
5
|
+
NativeLinearListLayout,
|
|
6
|
+
NativeLinearListLayoutConfig,
|
|
7
|
+
} from './specs/NativeLinearListLayout.nitro'
|
|
8
|
+
|
|
9
|
+
type LinearListLayoutBaseConfig = Omit<
|
|
10
|
+
Partial<NativeLinearListLayoutConfig>,
|
|
11
|
+
'iosConfig'
|
|
12
|
+
>
|
|
13
|
+
|
|
14
|
+
export type ItemSizeEstimate =
|
|
15
|
+
| {
|
|
16
|
+
width: number
|
|
17
|
+
height?: number
|
|
18
|
+
}
|
|
19
|
+
| {
|
|
20
|
+
width?: number
|
|
21
|
+
height: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type LinearListLayoutIOSConfig = {
|
|
25
|
+
estimatedItemSize?: ItemSizeEstimate
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type LinearListLayoutConfig = LinearListLayoutBaseConfig & {
|
|
29
|
+
iosConfig?: LinearListLayoutIOSConfig
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type ListLayout = {
|
|
33
|
+
__nativeLayout: NativeListLayout
|
|
34
|
+
release(): void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const defaultLinearListLayoutConfig: NativeLinearListLayoutConfig = {
|
|
38
|
+
topInset: 16,
|
|
39
|
+
bottomInset: 16,
|
|
40
|
+
itemSpacing: 12,
|
|
41
|
+
itemHorizontalInset: 0,
|
|
42
|
+
itemVerticalInset: 0,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function normalizeLinearConfig(
|
|
46
|
+
config: LinearListLayoutConfig = {}
|
|
47
|
+
): NativeLinearListLayoutConfig {
|
|
48
|
+
return {
|
|
49
|
+
topInset: config.topInset ?? defaultLinearListLayoutConfig.topInset,
|
|
50
|
+
bottomInset:
|
|
51
|
+
config.bottomInset ?? defaultLinearListLayoutConfig.bottomInset,
|
|
52
|
+
itemSpacing:
|
|
53
|
+
config.itemSpacing ?? defaultLinearListLayoutConfig.itemSpacing,
|
|
54
|
+
itemHorizontalInset:
|
|
55
|
+
config.itemHorizontalInset ??
|
|
56
|
+
defaultLinearListLayoutConfig.itemHorizontalInset,
|
|
57
|
+
itemVerticalInset:
|
|
58
|
+
config.itemVerticalInset ??
|
|
59
|
+
defaultLinearListLayoutConfig.itemVerticalInset,
|
|
60
|
+
iosConfig: config.iosConfig,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function createLinearListLayout(
|
|
65
|
+
config?: LinearListLayoutConfig
|
|
66
|
+
): ListLayout {
|
|
67
|
+
const nativeLayout = NitroModules.createHybridObject<NativeLinearListLayout>(
|
|
68
|
+
'NativeLinearListLayout'
|
|
69
|
+
)
|
|
70
|
+
const normalizedConfig = normalizeLinearConfig(config)
|
|
71
|
+
nativeLayout.setConfig(normalizedConfig)
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
__nativeLayout: nativeLayout,
|
|
75
|
+
release() {
|
|
76
|
+
nativeLayout.dispose()
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function useLinearListLayout(
|
|
82
|
+
config?: LinearListLayoutConfig
|
|
83
|
+
): ListLayout {
|
|
84
|
+
const layout = useMemo(() => {
|
|
85
|
+
return createLinearListLayout(config)
|
|
86
|
+
}, [config])
|
|
87
|
+
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
return () => {
|
|
90
|
+
layout.release()
|
|
91
|
+
}
|
|
92
|
+
}, [layout])
|
|
93
|
+
|
|
94
|
+
return layout
|
|
95
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
import type React from 'react'
|
|
3
|
+
|
|
4
|
+
function areDependencyListsEqual(
|
|
5
|
+
currentDependencies: React.DependencyList,
|
|
6
|
+
previousDependencies: React.DependencyList
|
|
7
|
+
) {
|
|
8
|
+
if (currentDependencies.length !== previousDependencies.length) {
|
|
9
|
+
return false
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
for (let index = 0; index < currentDependencies.length; index += 1) {
|
|
13
|
+
const currentDependency = currentDependencies[index]
|
|
14
|
+
const previousDependency = previousDependencies[index]
|
|
15
|
+
if (!Object.is(currentDependency, previousDependency)) {
|
|
16
|
+
return false
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Only runs if one of the dependencies has changed, but not on the initial render!
|
|
25
|
+
*/
|
|
26
|
+
export function useChangeEffect(
|
|
27
|
+
effect: React.EffectCallback,
|
|
28
|
+
dependencies: React.DependencyList
|
|
29
|
+
) {
|
|
30
|
+
const previousDependencies = useRef<React.DependencyList | null>(null)
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
const lastDependencies = previousDependencies.current
|
|
34
|
+
previousDependencies.current = dependencies
|
|
35
|
+
if (lastDependencies == null) {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const dependenciesAreEqual = areDependencyListsEqual(
|
|
40
|
+
dependencies,
|
|
41
|
+
lastDependencies
|
|
42
|
+
)
|
|
43
|
+
if (dependenciesAreEqual) {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return effect()
|
|
48
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
49
|
+
}, dependencies)
|
|
50
|
+
}
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { scheduleOnUI } from 'react-native-worklets'
|
|
2
|
+
import { uiListModule } from './UiListModule'
|
|
3
|
+
import { uiManagerHelper } from './renderer/fabric/UiManagerHelper'
|
|
4
|
+
import { List } from './views/List'
|
|
5
|
+
import { Platform } from 'react-native'
|
|
6
|
+
import { getReactFabricRenderer } from './renderer/react/ReactFabricRenderer'
|
|
7
|
+
|
|
8
|
+
export { ViewHolder } from './specs/ViewHolder.nitro'
|
|
9
|
+
export { IOSWorkletsModuleProxyHolder } from './specs/IOSWorkletsModuleProxyHolder.nitro'
|
|
10
|
+
export type { NativeListItem } from './specs/NativeListDataSource.nitro'
|
|
11
|
+
export type { ListProps, ListRenderer, ListRenderers } from './views/List'
|
|
12
|
+
export { createListDataSource, useListDataSource } from './ListDataSource'
|
|
13
|
+
export type {
|
|
14
|
+
ListContentEqualByType,
|
|
15
|
+
ListDataSource,
|
|
16
|
+
ListDataSourceConfig,
|
|
17
|
+
ListItem,
|
|
18
|
+
ListItemForType,
|
|
19
|
+
ListItemSize,
|
|
20
|
+
ListItemType,
|
|
21
|
+
ListKey,
|
|
22
|
+
} from './ListDataSource'
|
|
23
|
+
export { createLinearListLayout, useLinearListLayout } from './ListLayout'
|
|
24
|
+
export type {
|
|
25
|
+
ItemSizeEstimate,
|
|
26
|
+
LinearListLayoutConfig,
|
|
27
|
+
LinearListLayoutIOSConfig,
|
|
28
|
+
ListLayout,
|
|
29
|
+
} from './ListLayout'
|
|
30
|
+
|
|
31
|
+
const boxed = uiListModule
|
|
32
|
+
const nativeFabricUIManager = globalThis.nativeFabricUIManager
|
|
33
|
+
|
|
34
|
+
function setup() {
|
|
35
|
+
// TODO: ask SWM if they can remove their JS thread checks, then we could just access this from the UI thread.
|
|
36
|
+
const iosWorkletsModuleHolder =
|
|
37
|
+
Platform.OS === 'ios' ? uiListModule.iosGetWorkletsModule() : null
|
|
38
|
+
scheduleOnUI(() => {
|
|
39
|
+
'worklet'
|
|
40
|
+
globalThis.nativeFabricUIManager = nativeFabricUIManager
|
|
41
|
+
boxed.setupRuntime(iosWorkletsModuleHolder)
|
|
42
|
+
|
|
43
|
+
// This will setup the react instance on the UI runtime:
|
|
44
|
+
getReactFabricRenderer()
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
setup()
|
|
48
|
+
|
|
49
|
+
export { List, uiListModule, uiManagerHelper }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
import type * as ReactModule from 'react'
|
|
4
|
+
import type { UiManagerBinding } from './specs/UIManagerHelper.nitro'
|
|
5
|
+
|
|
6
|
+
declare global {
|
|
7
|
+
var log: (...args: unknown[]) => void
|
|
8
|
+
var nativeFabricUIManager: UiManagerBinding
|
|
9
|
+
|
|
10
|
+
interface GlobalThis {
|
|
11
|
+
React: typeof ReactModule
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface Performance {
|
|
15
|
+
now(): number
|
|
16
|
+
}
|
|
17
|
+
var performance: Performance
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export {}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { NitroModules } from 'react-native-nitro-modules'
|
|
2
|
+
import { uiListModule } from '../../UiListModule'
|
|
3
|
+
import { uiManagerHelper } from './UiManagerHelper'
|
|
4
|
+
import type { ShadowNodeList } from '../../specs/UIManagerHelper.nitro'
|
|
5
|
+
|
|
6
|
+
export const uiListModuleBoxed = NitroModules.box(uiListModule)
|
|
7
|
+
const capturedOnJS = global.nativeFabricUIManager
|
|
8
|
+
const uiManagerHelperBoxed = NitroModules.box(uiManagerHelper)
|
|
9
|
+
|
|
10
|
+
export function completeRootSyncWorklet(
|
|
11
|
+
surfaceId: number,
|
|
12
|
+
childSet: ShadowNodeList
|
|
13
|
+
) {
|
|
14
|
+
'worklet'
|
|
15
|
+
const uiManagerHelperUnboxed = uiManagerHelperBoxed.unbox()
|
|
16
|
+
uiManagerHelperUnboxed.completeRootSync(capturedOnJS, surfaceId, childSet)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function registerManagedSurfaceWorklet(surfaceId: number) {
|
|
20
|
+
'worklet'
|
|
21
|
+
const uiManagerHelperUnboxed = uiManagerHelperBoxed.unbox()
|
|
22
|
+
uiManagerHelperUnboxed.registerManagedSurface(surfaceId)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function unregisterManagedSurfaceWorklet(surfaceId: number) {
|
|
26
|
+
'worklet'
|
|
27
|
+
const uiManagerHelperUnboxed = uiManagerHelperBoxed.unbox()
|
|
28
|
+
uiManagerHelperUnboxed.unregisterManagedSurface(surfaceId)
|
|
29
|
+
}
|