react-native-list 1.0.1 → 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.
Files changed (190) hide show
  1. package/README.md +188 -32
  2. package/ReactNativeList.podspec +39 -0
  3. package/android/CMakeLists.txt +48 -0
  4. package/android/build.gradle +151 -0
  5. package/android/fix-prefab.gradle +51 -0
  6. package/android/gradle.properties +5 -0
  7. package/android/src/main/AndroidManifest.xml +2 -0
  8. package/android/src/main/cpp/JHybridUiListModule.cpp +192 -0
  9. package/android/src/main/cpp/JHybridUiListModule.h +50 -0
  10. package/android/src/main/cpp/cpp-adapter.cpp +12 -0
  11. package/android/src/main/java/com/hannojg/reactnativelist/ReactNativeListPackage.kt +27 -0
  12. package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridNativeListDataSource.kt +146 -0
  13. package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridNativeListLayout.kt +86 -0
  14. package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridUiListModule.kt +116 -0
  15. package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridUiListView.kt +410 -0
  16. package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridViewHolder.kt +9 -0
  17. package/android/src/main/java/com/margelo/nitro/reactnativelist/NativeListAdapter.kt +217 -0
  18. package/ios/DataSource/HybridNativeListDataSource.swift +213 -0
  19. package/ios/HybridObjects/HybridUiListModule.swift +49 -0
  20. package/ios/HybridObjects/HybridViewHolder.swift +16 -0
  21. package/ios/Layout/HybridNativeListLayout.swift +128 -0
  22. package/ios/Utils/ErrorUtils.h +26 -0
  23. package/ios/Utils/HybridIOSWorkletsModuleProxyHolder.swift +10 -0
  24. package/ios/Utils/SurfaceHelper.h +20 -0
  25. package/ios/Utils/SurfaceHelper.mm +144 -0
  26. package/ios/Utils/SurfacePresenterRegistry.h +17 -0
  27. package/ios/Utils/SurfacePresenterRegistry.m +31 -0
  28. package/ios/Utils/TurboModuleInstaller.h +18 -0
  29. package/ios/Utils/TurboModuleInstaller.mm +267 -0
  30. package/ios/Views/HostCell.swift +216 -0
  31. package/ios/Views/HybridUiListView.swift +695 -0
  32. package/metro/RendererProxyThreadSwitch.js +66 -0
  33. package/metro-config.d.ts +1 -0
  34. package/metro-config.js +52 -0
  35. package/nitro.json +47 -0
  36. package/nitrogen/generated/.gitattributes +1 -0
  37. package/nitrogen/generated/android/ReactNativeList+autolinking.cmake +99 -0
  38. package/nitrogen/generated/android/ReactNativeList+autolinking.gradle +27 -0
  39. package/nitrogen/generated/android/ReactNativeListOnLoad.cpp +156 -0
  40. package/nitrogen/generated/android/ReactNativeListOnLoad.hpp +34 -0
  41. package/nitrogen/generated/android/c++/JFunc_bool_NativeListItem_NativeListItem.hpp +83 -0
  42. package/nitrogen/generated/android/c++/JFunc_bool_double_NativeListItem_double.hpp +83 -0
  43. package/nitrogen/generated/android/c++/JFunc_double_std__string.hpp +78 -0
  44. package/nitrogen/generated/android/c++/JHybridIOSWorkletsModuleProxyHolderSpec.cpp +49 -0
  45. package/nitrogen/generated/android/c++/JHybridIOSWorkletsModuleProxyHolderSpec.hpp +63 -0
  46. package/nitrogen/generated/android/c++/JHybridNativeLinearListLayoutSpec.cpp +63 -0
  47. package/nitrogen/generated/android/c++/JHybridNativeLinearListLayoutSpec.hpp +65 -0
  48. package/nitrogen/generated/android/c++/JHybridNativeListDataSourceSpec.cpp +101 -0
  49. package/nitrogen/generated/android/c++/JHybridNativeListDataSourceSpec.hpp +70 -0
  50. package/nitrogen/generated/android/c++/JHybridNativeListLayoutSpec.cpp +49 -0
  51. package/nitrogen/generated/android/c++/JHybridNativeListLayoutSpec.hpp +63 -0
  52. package/nitrogen/generated/android/c++/JHybridUiListModuleSpec.cpp +65 -0
  53. package/nitrogen/generated/android/c++/JHybridUiListModuleSpec.hpp +64 -0
  54. package/nitrogen/generated/android/c++/JHybridUiListViewSpec.cpp +92 -0
  55. package/nitrogen/generated/android/c++/JHybridUiListViewSpec.hpp +67 -0
  56. package/nitrogen/generated/android/c++/JHybridViewHolderSpec.cpp +49 -0
  57. package/nitrogen/generated/android/c++/JHybridViewHolderSpec.hpp +63 -0
  58. package/nitrogen/generated/android/c++/JNativeItemSizeEstimate.hpp +61 -0
  59. package/nitrogen/generated/android/c++/JNativeLinearListLayoutConfig.hpp +81 -0
  60. package/nitrogen/generated/android/c++/JNativeLinearListLayoutIOSConfig.hpp +59 -0
  61. package/nitrogen/generated/android/c++/JNativeListItem.hpp +76 -0
  62. package/nitrogen/generated/android/c++/JVariant_NullType_HybridIOSWorkletsModuleProxyHolderSpec.cpp +26 -0
  63. package/nitrogen/generated/android/c++/JVariant_NullType_HybridIOSWorkletsModuleProxyHolderSpec.hpp +72 -0
  64. package/nitrogen/generated/android/c++/views/JHybridUiListViewStateUpdater.cpp +53 -0
  65. package/nitrogen/generated/android/c++/views/JHybridUiListViewStateUpdater.hpp +49 -0
  66. package/nitrogen/generated/android/c++/views/JHybridViewHolderStateUpdater.cpp +53 -0
  67. package/nitrogen/generated/android/c++/views/JHybridViewHolderStateUpdater.hpp +49 -0
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Func_bool_NativeListItem_NativeListItem.kt +80 -0
  69. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Func_bool_double_NativeListItem_double.kt +80 -0
  70. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Func_double_std__string.kt +80 -0
  71. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridIOSWorkletsModuleProxyHolderSpec.kt +52 -0
  72. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridNativeLinearListLayoutSpec.kt +54 -0
  73. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridNativeListDataSourceSpec.kt +87 -0
  74. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridNativeListLayoutSpec.kt +52 -0
  75. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridUiListModuleSpec.kt +59 -0
  76. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridUiListViewSpec.kt +76 -0
  77. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridViewHolderSpec.kt +53 -0
  78. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeItemSizeEstimate.kt +56 -0
  79. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeLinearListLayoutConfig.kt +76 -0
  80. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeLinearListLayoutIOSConfig.kt +51 -0
  81. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeListItem.kt +71 -0
  82. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/ReactNativeListOnLoad.kt +35 -0
  83. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Variant_NullType_HybridIOSWorkletsModuleProxyHolderSpec.kt +62 -0
  84. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridUiListViewManager.kt +80 -0
  85. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridUiListViewStateUpdater.kt +23 -0
  86. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridViewHolderManager.kt +80 -0
  87. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridViewHolderStateUpdater.kt +23 -0
  88. package/nitrogen/generated/ios/ReactNativeList+autolinking.rb +62 -0
  89. package/nitrogen/generated/ios/ReactNativeList-Swift-Cxx-Bridge.cpp +162 -0
  90. package/nitrogen/generated/ios/ReactNativeList-Swift-Cxx-Bridge.hpp +368 -0
  91. package/nitrogen/generated/ios/ReactNativeList-Swift-Cxx-Umbrella.hpp +92 -0
  92. package/nitrogen/generated/ios/ReactNativeListAutolinking.mm +83 -0
  93. package/nitrogen/generated/ios/ReactNativeListAutolinking.swift +86 -0
  94. package/nitrogen/generated/ios/c++/HybridIOSWorkletsModuleProxyHolderSpecSwift.cpp +11 -0
  95. package/nitrogen/generated/ios/c++/HybridIOSWorkletsModuleProxyHolderSpecSwift.hpp +75 -0
  96. package/nitrogen/generated/ios/c++/HybridNativeLinearListLayoutSpecSwift.cpp +11 -0
  97. package/nitrogen/generated/ios/c++/HybridNativeLinearListLayoutSpecSwift.hpp +92 -0
  98. package/nitrogen/generated/ios/c++/HybridNativeListDataSourceSpecSwift.cpp +11 -0
  99. package/nitrogen/generated/ios/c++/HybridNativeListDataSourceSpecSwift.hpp +132 -0
  100. package/nitrogen/generated/ios/c++/HybridNativeListLayoutSpecSwift.cpp +11 -0
  101. package/nitrogen/generated/ios/c++/HybridNativeListLayoutSpecSwift.hpp +75 -0
  102. package/nitrogen/generated/ios/c++/HybridUiListModuleSpecSwift.cpp +11 -0
  103. package/nitrogen/generated/ios/c++/HybridUiListModuleSpecSwift.hpp +93 -0
  104. package/nitrogen/generated/ios/c++/HybridUiListViewSpecSwift.cpp +11 -0
  105. package/nitrogen/generated/ios/c++/HybridUiListViewSpecSwift.hpp +121 -0
  106. package/nitrogen/generated/ios/c++/HybridViewHolderSpecSwift.cpp +11 -0
  107. package/nitrogen/generated/ios/c++/HybridViewHolderSpecSwift.hpp +75 -0
  108. package/nitrogen/generated/ios/c++/views/HybridUiListViewComponent.mm +118 -0
  109. package/nitrogen/generated/ios/c++/views/HybridViewHolderComponent.mm +118 -0
  110. package/nitrogen/generated/ios/swift/Func_bool_NativeListItem_NativeListItem.swift +47 -0
  111. package/nitrogen/generated/ios/swift/Func_bool_double_NativeListItem_double.swift +47 -0
  112. package/nitrogen/generated/ios/swift/Func_double_std__string.swift +47 -0
  113. package/nitrogen/generated/ios/swift/HybridIOSWorkletsModuleProxyHolderSpec.swift +55 -0
  114. package/nitrogen/generated/ios/swift/HybridIOSWorkletsModuleProxyHolderSpec_cxx.swift +128 -0
  115. package/nitrogen/generated/ios/swift/HybridNativeLinearListLayoutSpec.swift +55 -0
  116. package/nitrogen/generated/ios/swift/HybridNativeLinearListLayoutSpec_cxx.swift +140 -0
  117. package/nitrogen/generated/ios/swift/HybridNativeListDataSourceSpec.swift +62 -0
  118. package/nitrogen/generated/ios/swift/HybridNativeListDataSourceSpec_cxx.swift +222 -0
  119. package/nitrogen/generated/ios/swift/HybridNativeListLayoutSpec.swift +55 -0
  120. package/nitrogen/generated/ios/swift/HybridNativeListLayoutSpec_cxx.swift +128 -0
  121. package/nitrogen/generated/ios/swift/HybridUiListModuleSpec.swift +56 -0
  122. package/nitrogen/generated/ios/swift/HybridUiListModuleSpec_cxx.swift +175 -0
  123. package/nitrogen/generated/ios/swift/HybridUiListViewSpec.swift +59 -0
  124. package/nitrogen/generated/ios/swift/HybridUiListViewSpec_cxx.swift +227 -0
  125. package/nitrogen/generated/ios/swift/HybridViewHolderSpec.swift +55 -0
  126. package/nitrogen/generated/ios/swift/HybridViewHolderSpec_cxx.swift +147 -0
  127. package/nitrogen/generated/ios/swift/NativeItemSizeEstimate.swift +60 -0
  128. package/nitrogen/generated/ios/swift/NativeLinearListLayoutConfig.swift +60 -0
  129. package/nitrogen/generated/ios/swift/NativeLinearListLayoutIOSConfig.swift +35 -0
  130. package/nitrogen/generated/ios/swift/NativeListItem.swift +75 -0
  131. package/nitrogen/generated/ios/swift/Variant_NullType__any_HybridIOSWorkletsModuleProxyHolderSpec_.swift +30 -0
  132. package/nitrogen/generated/shared/c++/HybridIOSWorkletsModuleProxyHolderSpec.cpp +21 -0
  133. package/nitrogen/generated/shared/c++/HybridIOSWorkletsModuleProxyHolderSpec.hpp +62 -0
  134. package/nitrogen/generated/shared/c++/HybridNativeLinearListLayoutSpec.cpp +22 -0
  135. package/nitrogen/generated/shared/c++/HybridNativeLinearListLayoutSpec.hpp +67 -0
  136. package/nitrogen/generated/shared/c++/HybridNativeListDataSourceSpec.cpp +28 -0
  137. package/nitrogen/generated/shared/c++/HybridNativeListDataSourceSpec.hpp +72 -0
  138. package/nitrogen/generated/shared/c++/HybridNativeListLayoutSpec.cpp +21 -0
  139. package/nitrogen/generated/shared/c++/HybridNativeListLayoutSpec.hpp +62 -0
  140. package/nitrogen/generated/shared/c++/HybridUiListModuleSpec.cpp +22 -0
  141. package/nitrogen/generated/shared/c++/HybridUiListModuleSpec.hpp +68 -0
  142. package/nitrogen/generated/shared/c++/HybridUiListViewSpec.cpp +25 -0
  143. package/nitrogen/generated/shared/c++/HybridUiListViewSpec.hpp +79 -0
  144. package/nitrogen/generated/shared/c++/HybridUiManagerHelperSpec.cpp +23 -0
  145. package/nitrogen/generated/shared/c++/HybridUiManagerHelperSpec.hpp +65 -0
  146. package/nitrogen/generated/shared/c++/HybridViewHolderSpec.cpp +21 -0
  147. package/nitrogen/generated/shared/c++/HybridViewHolderSpec.hpp +62 -0
  148. package/nitrogen/generated/shared/c++/NativeItemSizeEstimate.hpp +87 -0
  149. package/nitrogen/generated/shared/c++/NativeLinearListLayoutConfig.hpp +105 -0
  150. package/nitrogen/generated/shared/c++/NativeLinearListLayoutIOSConfig.hpp +85 -0
  151. package/nitrogen/generated/shared/c++/NativeListItem.hpp +101 -0
  152. package/nitrogen/generated/shared/c++/views/HybridUiListViewComponent.cpp +72 -0
  153. package/nitrogen/generated/shared/c++/views/HybridUiListViewComponent.hpp +109 -0
  154. package/nitrogen/generated/shared/c++/views/HybridViewHolderComponent.cpp +72 -0
  155. package/nitrogen/generated/shared/c++/views/HybridViewHolderComponent.hpp +109 -0
  156. package/nitrogen/generated/shared/json/UiListViewConfig.json +9 -0
  157. package/nitrogen/generated/shared/json/ViewHolderConfig.json +9 -0
  158. package/package.json +152 -5
  159. package/react-native.config.js +16 -0
  160. package/src/ListDataSource.ts +232 -0
  161. package/src/ListLayout.ts +95 -0
  162. package/src/UiListModule.ts +5 -0
  163. package/src/hooks/useChangeEffect.ts +50 -0
  164. package/src/index.tsx +49 -0
  165. package/src/privateGlobals.ts +20 -0
  166. package/src/renderer/fabric/RenderHelper.ts +29 -0
  167. package/src/renderer/fabric/UiManagerHelper.ts +5 -0
  168. package/src/renderer/react/ReactFabricMirror.bundle.js +1984 -0
  169. package/src/renderer/react/ReactFabricMirror.ts +766 -0
  170. package/src/renderer/react/ReactFabricRenderer.ts +11 -0
  171. package/src/specs/IOSWorkletsModuleProxyHolder.nitro.ts +6 -0
  172. package/src/specs/NativeLinearListLayout.nitro.ts +23 -0
  173. package/src/specs/NativeListDataSource.nitro.ts +28 -0
  174. package/src/specs/NativeListLayout.nitro.ts +6 -0
  175. package/src/specs/UIListModule.nitro.ts +13 -0
  176. package/src/specs/UIManagerHelper.nitro.ts +34 -0
  177. package/src/specs/UiListView.nitro.ts +31 -0
  178. package/src/specs/ViewHolder.nitro.ts +11 -0
  179. package/src/views/List.tsx +525 -0
  180. package/src/views/UiListHostComponent.ts +8 -0
  181. package/FillRateHelper.js +0 -179
  182. package/FlatList.js +0 -494
  183. package/LICENSE.md +0 -31
  184. package/MetroListView.js +0 -166
  185. package/SectionList.js +0 -291
  186. package/ViewabilityHelper.js +0 -260
  187. package/VirtualizeUtils.js +0 -163
  188. package/VirtualizedList.js +0 -861
  189. package/VirtualizedSectionList.js +0 -397
  190. 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,5 @@
1
+ import { NitroModules } from 'react-native-nitro-modules'
2
+ import { UiListModule } from './specs/UIListModule.nitro'
3
+
4
+ export const uiListModule =
5
+ NitroModules.createHybridObject<UiListModule>('UiListModule')
@@ -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
+ }
@@ -0,0 +1,5 @@
1
+ import { NitroModules } from 'react-native-nitro-modules'
2
+ import { UiManagerHelper } from '../../specs/UIManagerHelper.nitro'
3
+
4
+ export const uiManagerHelper =
5
+ NitroModules.createHybridObject<UiManagerHelper>('UiManagerHelper')