@onekeyfe/react-native-native-list 3.0.157-alpha.253 → 3.0.157-alpha.255

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 (88) hide show
  1. package/android/build.gradle +7 -0
  2. package/android/src/main/java/com/onekey/nativelist/HybridNativeList.kt +20 -0
  3. package/android/src/main/java/com/onekey/nativelist/NativeListActivityDetailsView.kt +179 -0
  4. package/android/src/main/java/com/onekey/nativelist/NativeListActivityRenderer.kt +23 -2
  5. package/android/src/main/java/com/onekey/nativelist/NativeListContainerSlotAdapter.kt +53 -0
  6. package/android/src/main/java/com/onekey/nativelist/NativeListEndAlignment.kt +5 -0
  7. package/android/src/main/java/com/onekey/nativelist/NativeListMediaPreviewSlot.kt +215 -0
  8. package/android/src/main/java/com/onekey/nativelist/NativeListMediaTileRenderer.kt +15 -6
  9. package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +3 -1
  10. package/android/src/main/java/com/onekey/nativelist/NativeListScrollPositionTracker.kt +29 -0
  11. package/android/src/main/java/com/onekey/nativelist/NativeListSectionHeaderRenderer.kt +16 -1
  12. package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +163 -26
  13. package/android/src/main/res/values/native_scroll_coordinator_ids.xml +4 -0
  14. package/android/src/test/java/com/margelo/nitro/nativelist/NativeListEndAlignmentTest.kt +34 -0
  15. package/android/src/test/java/com/margelo/nitro/nativelist/NativeListScrollPositionTrackerTest.kt +28 -0
  16. package/docs/DESIGN.md +4 -2
  17. package/docs/ROW_TEMPLATES.md +45 -0
  18. package/docs/SPEC.md +227 -1
  19. package/docs/STYLE_SPEC.md +8 -0
  20. package/ios/HybridNativeList.swift +30 -0
  21. package/ios/NativeListActivityDetailsView.swift +229 -0
  22. package/ios/NativeListActivityRenderer.swift +24 -2
  23. package/ios/NativeListMediaPreviewSlot.swift +199 -0
  24. package/ios/NativeListMediaTileRenderer.swift +10 -4
  25. package/ios/NativeListModels.swift +4 -1
  26. package/ios/NativeListScrollPositionTracker.swift +30 -0
  27. package/ios/NativeListSectionHeaderRenderer.swift +27 -1
  28. package/ios/RNCNativeListView.swift +159 -4
  29. package/ios/tests/NativeListActivityPresentationTests.swift +43 -0
  30. package/ios/tests/NativeListLifecycleTests.swift +213 -0
  31. package/ios/tests/NativeListMediaVisibilityTests.swift +42 -0
  32. package/ios/tests/NativeListScrollPositionTrackerTests.swift +25 -0
  33. package/lib/module/NativeList.js +56 -3
  34. package/lib/module/NativeList.web.js +5 -0
  35. package/lib/module/validation.js +64 -4
  36. package/lib/nitrogen/generated/android/c++/JFunc_void_bool.hpp +75 -0
  37. package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +39 -3
  38. package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +6 -0
  39. package/lib/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +15 -0
  40. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/Func_void_bool.kt +78 -0
  41. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +26 -0
  42. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/views/HybridNativeListManager.kt +24 -9
  43. package/lib/nitrogen/generated/android/nativelistOnLoad.cpp +2 -0
  44. package/lib/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Bridge.cpp +8 -0
  45. package/lib/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Bridge.hpp +37 -0
  46. package/lib/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +23 -2
  47. package/lib/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +32 -0
  48. package/lib/nitrogen/generated/ios/swift/Func_void_bool.swift +46 -0
  49. package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +3 -0
  50. package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +54 -0
  51. package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +6 -0
  52. package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +8 -2
  53. package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +6 -0
  54. package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +11 -2
  55. package/lib/nitrogen/generated/shared/json/NativeListConfig.json +3 -0
  56. package/lib/typescript/src/NativeList.nitro.d.ts +3 -0
  57. package/lib/typescript/src/NativeList.types.d.ts +14 -1
  58. package/lib/typescript/src/models.d.ts +33 -5
  59. package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +75 -0
  60. package/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +39 -3
  61. package/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +6 -0
  62. package/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +15 -0
  63. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/Func_void_bool.kt +78 -0
  64. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +26 -0
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/views/HybridNativeListManager.kt +24 -9
  66. package/nitrogen/generated/android/nativelistOnLoad.cpp +2 -0
  67. package/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Bridge.cpp +8 -0
  68. package/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Bridge.hpp +37 -0
  69. package/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +23 -2
  70. package/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +32 -0
  71. package/nitrogen/generated/ios/swift/Func_void_bool.swift +46 -0
  72. package/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +3 -0
  73. package/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +54 -0
  74. package/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +6 -0
  75. package/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +8 -2
  76. package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +6 -0
  77. package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +11 -2
  78. package/nitrogen/generated/shared/json/NativeListConfig.json +3 -0
  79. package/package.json +6 -5
  80. package/react-native-native-list.podspec +6 -0
  81. package/scripts/enable-container-slots.mjs +58 -0
  82. package/scripts/enable-container-slots.test.mjs +58 -0
  83. package/src/NativeList.nitro.ts +3 -0
  84. package/src/NativeList.tsx +84 -2
  85. package/src/NativeList.types.ts +14 -1
  86. package/src/NativeList.web.tsx +5 -0
  87. package/src/models.ts +38 -1
  88. package/src/validation.ts +146 -4
@@ -14,6 +14,14 @@
14
14
 
15
15
  namespace margelo::nitro::nativelist::bridge::swift {
16
16
 
17
+ // pragma MARK: std::function<void(bool /* isBeyondThreshold */)>
18
+ Func_void_bool create_Func_void_bool(void* NON_NULL swiftClosureWrapper) noexcept {
19
+ auto swiftClosure = NativeListModule::Func_void_bool::fromUnsafe(swiftClosureWrapper);
20
+ return [swiftClosure = std::move(swiftClosure)](bool isBeyondThreshold) mutable -> void {
21
+ swiftClosure.call(isBeyondThreshold);
22
+ };
23
+ }
24
+
17
25
  // pragma MARK: std::function<void(const std::string& /* payloadJson */)>
18
26
  Func_void_std__string create_Func_void_std__string(void* NON_NULL swiftClosureWrapper) noexcept {
19
27
  auto swiftClosure = NativeListModule::Func_void_std__string::fromUnsafe(swiftClosureWrapper);
@@ -30,6 +30,43 @@ namespace NativeListModule { class HybridNativeListSpec_cxx; }
30
30
  */
31
31
  namespace margelo::nitro::nativelist::bridge::swift {
32
32
 
33
+ // pragma MARK: std::function<void(bool /* isBeyondThreshold */)>
34
+ /**
35
+ * Specialized version of `std::function<void(bool)>`.
36
+ */
37
+ using Func_void_bool = std::function<void(bool /* isBeyondThreshold */)>;
38
+ /**
39
+ * Wrapper class for a `std::function<void(bool / * isBeyondThreshold * /)>`, this can be used from Swift.
40
+ */
41
+ class Func_void_bool_Wrapper final {
42
+ public:
43
+ explicit Func_void_bool_Wrapper(std::function<void(bool /* isBeyondThreshold */)>&& func): _function(std::make_unique<std::function<void(bool /* isBeyondThreshold */)>>(std::move(func))) {}
44
+ inline void call(bool isBeyondThreshold) const noexcept {
45
+ _function->operator()(isBeyondThreshold);
46
+ }
47
+ private:
48
+ std::unique_ptr<std::function<void(bool /* isBeyondThreshold */)>> _function;
49
+ } SWIFT_NONCOPYABLE;
50
+ Func_void_bool create_Func_void_bool(void* NON_NULL swiftClosureWrapper) noexcept;
51
+ inline Func_void_bool_Wrapper wrap_Func_void_bool(Func_void_bool value) noexcept {
52
+ return Func_void_bool_Wrapper(std::move(value));
53
+ }
54
+
55
+ // pragma MARK: std::optional<std::function<void(bool /* isBeyondThreshold */)>>
56
+ /**
57
+ * Specialized version of `std::optional<std::function<void(bool / * isBeyondThreshold * /)>>`.
58
+ */
59
+ using std__optional_std__function_void_bool____isBeyondThreshold______ = std::optional<std::function<void(bool /* isBeyondThreshold */)>>;
60
+ inline std::optional<std::function<void(bool /* isBeyondThreshold */)>> create_std__optional_std__function_void_bool____isBeyondThreshold______(const std::function<void(bool /* isBeyondThreshold */)>& value) noexcept {
61
+ return std::optional<std::function<void(bool /* isBeyondThreshold */)>>(value);
62
+ }
63
+ inline bool has_value_std__optional_std__function_void_bool____isBeyondThreshold______(const std::optional<std::function<void(bool /* isBeyondThreshold */)>>& optional) noexcept {
64
+ return optional.has_value();
65
+ }
66
+ inline std::function<void(bool /* isBeyondThreshold */)> get_std__optional_std__function_void_bool____isBeyondThreshold______(const std::optional<std::function<void(bool /* isBeyondThreshold */)>>& optional) noexcept {
67
+ return optional.value();
68
+ }
69
+
33
70
  // pragma MARK: std::function<void(const std::string& /* payloadJson */)>
34
71
  /**
35
72
  * Specialized version of `std::function<void(const std::string&)>`.
@@ -20,10 +20,10 @@ namespace margelo::nitro::nativelist { enum class NativeListKeyboardShouldPersis
20
20
  namespace margelo::nitro::nativelist { enum class NativeListScrollAlignment; }
21
21
 
22
22
  #include <string>
23
- #include "NativeListKeyboardDismissMode.hpp"
24
- #include "NativeListKeyboardShouldPersistTaps.hpp"
25
23
  #include <functional>
26
24
  #include <optional>
25
+ #include "NativeListKeyboardDismissMode.hpp"
26
+ #include "NativeListKeyboardShouldPersistTaps.hpp"
27
27
  #include "NativeListScrollAlignment.hpp"
28
28
 
29
29
  #include "NativeListModule-Swift-Cxx-Umbrella.hpp"
@@ -79,6 +79,27 @@ namespace margelo::nitro::nativelist {
79
79
  inline void setSnapshotJson(const std::string& snapshotJson) noexcept override {
80
80
  _swiftPart.setSnapshotJson(snapshotJson);
81
81
  }
82
+ inline std::string getContainerSlotHeightsJson() noexcept override {
83
+ auto __result = _swiftPart.getContainerSlotHeightsJson();
84
+ return __result;
85
+ }
86
+ inline void setContainerSlotHeightsJson(const std::string& containerSlotHeightsJson) noexcept override {
87
+ _swiftPart.setContainerSlotHeightsJson(containerSlotHeightsJson);
88
+ }
89
+ inline std::string getScrollPositionThresholdsJson() noexcept override {
90
+ auto __result = _swiftPart.getScrollPositionThresholdsJson();
91
+ return __result;
92
+ }
93
+ inline void setScrollPositionThresholdsJson(const std::string& scrollPositionThresholdsJson) noexcept override {
94
+ _swiftPart.setScrollPositionThresholdsJson(scrollPositionThresholdsJson);
95
+ }
96
+ inline std::optional<std::function<void(bool /* isBeyondThreshold */)>> getOnScrollPositionThresholdChange() noexcept override {
97
+ auto __result = _swiftPart.getOnScrollPositionThresholdChange();
98
+ return __result;
99
+ }
100
+ inline void setOnScrollPositionThresholdChange(const std::optional<std::function<void(bool /* isBeyondThreshold */)>>& onScrollPositionThresholdChange) noexcept override {
101
+ _swiftPart.setOnScrollPositionThresholdChange(onScrollPositionThresholdChange);
102
+ }
82
103
  inline NativeListKeyboardDismissMode getKeyboardDismissMode() noexcept override {
83
104
  auto __result = _swiftPart.getKeyboardDismissMode();
84
105
  return static_cast<NativeListKeyboardDismissMode>(__result);
@@ -35,6 +35,11 @@ using namespace margelo::nitro::nativelist::views;
35
35
  + (BOOL)shouldBeRecycled;
36
36
  @end
37
37
 
38
+ @interface UIView (NativeListContainerSlots)
39
+ - (void)mountContainerSlot:(UIView *)view atIndex:(NSInteger)index;
40
+ - (void)unmountContainerSlot:(UIView *)view;
41
+ @end
42
+
38
43
  @implementation HybridNativeListComponent {
39
44
  std::shared_ptr<HybridNativeListSpecSwift> _hybridView;
40
45
  BOOL _didDropView;
@@ -59,6 +64,15 @@ using namespace margelo::nitro::nativelist::views;
59
64
  return self;
60
65
  }
61
66
 
67
+ // NativeList container slot mounting
68
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)child index:(NSInteger)index {
69
+ [self.contentView mountContainerSlot:child atIndex:index];
70
+ }
71
+
72
+ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)child index:(NSInteger)index {
73
+ [self.contentView unmountContainerSlot:child];
74
+ }
75
+
62
76
  - (void) updateView {
63
77
  // 1. Get Swift part
64
78
  NativeListModule::HybridNativeListSpec_cxx& swiftPart = _hybridView->getSwiftPart();
@@ -104,6 +118,24 @@ using namespace margelo::nitro::nativelist::views;
104
118
  : !newViewProps.snapshotJson.hasSameValue(oldViewProps->snapshotJson)) {
105
119
  swiftPart.setSnapshotJson(newViewProps.snapshotJson.get());
106
120
  }
121
+ // containerSlotHeightsJson: string
122
+ if (oldViewProps == nullptr
123
+ ? newViewProps.containerSlotHeightsJson.isProvided()
124
+ : !newViewProps.containerSlotHeightsJson.hasSameValue(oldViewProps->containerSlotHeightsJson)) {
125
+ swiftPart.setContainerSlotHeightsJson(newViewProps.containerSlotHeightsJson.get());
126
+ }
127
+ // scrollPositionThresholdsJson: string
128
+ if (oldViewProps == nullptr
129
+ ? newViewProps.scrollPositionThresholdsJson.isProvided()
130
+ : !newViewProps.scrollPositionThresholdsJson.hasSameValue(oldViewProps->scrollPositionThresholdsJson)) {
131
+ swiftPart.setScrollPositionThresholdsJson(newViewProps.scrollPositionThresholdsJson.get());
132
+ }
133
+ // onScrollPositionThresholdChange: optional
134
+ if (oldViewProps == nullptr
135
+ ? newViewProps.onScrollPositionThresholdChange.isProvided()
136
+ : !newViewProps.onScrollPositionThresholdChange.hasSameValue(oldViewProps->onScrollPositionThresholdChange)) {
137
+ swiftPart.setOnScrollPositionThresholdChange(newViewProps.onScrollPositionThresholdChange.get());
138
+ }
107
139
  // keyboardDismissMode: enum
108
140
  if (oldViewProps == nullptr
109
141
  ? newViewProps.keyboardDismissMode.isProvided()
@@ -0,0 +1,46 @@
1
+ ///
2
+ /// Func_void_bool.swift
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ import NitroModules
9
+
10
+ /**
11
+ * Wraps a Swift `(_ isBeyondThreshold: Bool) -> Void` as a class.
12
+ * This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`.
13
+ */
14
+ public final class Func_void_bool {
15
+ public typealias bridge = margelo.nitro.nativelist.bridge.swift
16
+
17
+ private let closure: (_ isBeyondThreshold: Bool) -> Void
18
+
19
+ public init(_ closure: @escaping (_ isBeyondThreshold: Bool) -> Void) {
20
+ self.closure = closure
21
+ }
22
+
23
+ @inline(__always)
24
+ public func call(isBeyondThreshold: Bool) -> Void {
25
+ self.closure(isBeyondThreshold)
26
+ }
27
+
28
+ /**
29
+ * Casts this instance to a retained unsafe raw pointer.
30
+ * This acquires one additional strong reference on the object!
31
+ */
32
+ @inline(__always)
33
+ public func toUnsafe() -> UnsafeMutableRawPointer {
34
+ return Unmanaged.passRetained(self).toOpaque()
35
+ }
36
+
37
+ /**
38
+ * Casts an unsafe pointer to a `Func_void_bool`.
39
+ * The pointer has to be a retained opaque `Unmanaged<Func_void_bool>`.
40
+ * This removes one strong reference from the object!
41
+ */
42
+ @inline(__always)
43
+ public static func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> Func_void_bool {
44
+ return Unmanaged<Func_void_bool>.fromOpaque(pointer).takeRetainedValue()
45
+ }
46
+ }
@@ -11,6 +11,9 @@ import NitroModules
11
11
  public protocol HybridNativeListSpec_protocol: HybridObject, HybridView {
12
12
  // Properties
13
13
  var snapshotJson: String { get set }
14
+ var containerSlotHeightsJson: String { get set }
15
+ var scrollPositionThresholdsJson: String { get set }
16
+ var onScrollPositionThresholdChange: ((_ isBeyondThreshold: Bool) -> Void)? { get set }
14
17
  var keyboardDismissMode: NativeListKeyboardDismissMode { get set }
15
18
  var keyboardShouldPersistTaps: NativeListKeyboardShouldPersistTaps { get set }
16
19
  var onRowAction: ((_ payloadJson: String) -> Void)? { get set }
@@ -132,6 +132,60 @@ open class HybridNativeListSpec_cxx {
132
132
  }
133
133
  }
134
134
 
135
+ public final var containerSlotHeightsJson: std.string {
136
+ @inline(__always)
137
+ get {
138
+ return std.string(self.__implementation.containerSlotHeightsJson)
139
+ }
140
+ @inline(__always)
141
+ set {
142
+ self.__implementation.containerSlotHeightsJson = String(newValue)
143
+ }
144
+ }
145
+
146
+ public final var scrollPositionThresholdsJson: std.string {
147
+ @inline(__always)
148
+ get {
149
+ return std.string(self.__implementation.scrollPositionThresholdsJson)
150
+ }
151
+ @inline(__always)
152
+ set {
153
+ self.__implementation.scrollPositionThresholdsJson = String(newValue)
154
+ }
155
+ }
156
+
157
+ public final var onScrollPositionThresholdChange: bridge.std__optional_std__function_void_bool____isBeyondThreshold______ {
158
+ @inline(__always)
159
+ get {
160
+ return { () -> bridge.std__optional_std__function_void_bool____isBeyondThreshold______ in
161
+ if let __unwrappedValue = self.__implementation.onScrollPositionThresholdChange {
162
+ return bridge.create_std__optional_std__function_void_bool____isBeyondThreshold______({ () -> bridge.Func_void_bool in
163
+ let __closureWrapper = Func_void_bool(__unwrappedValue)
164
+ return bridge.create_Func_void_bool(__closureWrapper.toUnsafe())
165
+ }())
166
+ } else {
167
+ return .init()
168
+ }
169
+ }()
170
+ }
171
+ @inline(__always)
172
+ set {
173
+ self.__implementation.onScrollPositionThresholdChange = { () -> ((_ isBeyondThreshold: Bool) -> Void)? in
174
+ if bridge.has_value_std__optional_std__function_void_bool____isBeyondThreshold______(newValue) {
175
+ let __unwrapped = bridge.get_std__optional_std__function_void_bool____isBeyondThreshold______(newValue)
176
+ return { () -> (Bool) -> Void in
177
+ let __wrappedFunction = bridge.wrap_Func_void_bool(__unwrapped)
178
+ return { (__isBeyondThreshold: Bool) -> Void in
179
+ __wrappedFunction.call(__isBeyondThreshold)
180
+ }
181
+ }()
182
+ } else {
183
+ return nil
184
+ }
185
+ }()
186
+ }
187
+ }
188
+
135
189
  public final var keyboardDismissMode: Int32 {
136
190
  @inline(__always)
137
191
  get {
@@ -16,6 +16,12 @@ namespace margelo::nitro::nativelist {
16
16
  registerHybrids(this, [](Prototype& prototype) {
17
17
  prototype.registerHybridGetter("snapshotJson", &HybridNativeListSpec::getSnapshotJson);
18
18
  prototype.registerHybridSetter("snapshotJson", &HybridNativeListSpec::setSnapshotJson);
19
+ prototype.registerHybridGetter("containerSlotHeightsJson", &HybridNativeListSpec::getContainerSlotHeightsJson);
20
+ prototype.registerHybridSetter("containerSlotHeightsJson", &HybridNativeListSpec::setContainerSlotHeightsJson);
21
+ prototype.registerHybridGetter("scrollPositionThresholdsJson", &HybridNativeListSpec::getScrollPositionThresholdsJson);
22
+ prototype.registerHybridSetter("scrollPositionThresholdsJson", &HybridNativeListSpec::setScrollPositionThresholdsJson);
23
+ prototype.registerHybridGetter("onScrollPositionThresholdChange", &HybridNativeListSpec::getOnScrollPositionThresholdChange);
24
+ prototype.registerHybridSetter("onScrollPositionThresholdChange", &HybridNativeListSpec::setOnScrollPositionThresholdChange);
19
25
  prototype.registerHybridGetter("keyboardDismissMode", &HybridNativeListSpec::getKeyboardDismissMode);
20
26
  prototype.registerHybridSetter("keyboardDismissMode", &HybridNativeListSpec::setKeyboardDismissMode);
21
27
  prototype.registerHybridGetter("keyboardShouldPersistTaps", &HybridNativeListSpec::getKeyboardShouldPersistTaps);
@@ -21,10 +21,10 @@ namespace margelo::nitro::nativelist { enum class NativeListKeyboardShouldPersis
21
21
  namespace margelo::nitro::nativelist { enum class NativeListScrollAlignment; }
22
22
 
23
23
  #include <string>
24
- #include "NativeListKeyboardDismissMode.hpp"
25
- #include "NativeListKeyboardShouldPersistTaps.hpp"
26
24
  #include <functional>
27
25
  #include <optional>
26
+ #include "NativeListKeyboardDismissMode.hpp"
27
+ #include "NativeListKeyboardShouldPersistTaps.hpp"
28
28
  #include "NativeListScrollAlignment.hpp"
29
29
 
30
30
  namespace margelo::nitro::nativelist {
@@ -56,6 +56,12 @@ namespace margelo::nitro::nativelist {
56
56
  // Properties
57
57
  virtual std::string getSnapshotJson() = 0;
58
58
  virtual void setSnapshotJson(const std::string& snapshotJson) = 0;
59
+ virtual std::string getContainerSlotHeightsJson() = 0;
60
+ virtual void setContainerSlotHeightsJson(const std::string& containerSlotHeightsJson) = 0;
61
+ virtual std::string getScrollPositionThresholdsJson() = 0;
62
+ virtual void setScrollPositionThresholdsJson(const std::string& scrollPositionThresholdsJson) = 0;
63
+ virtual std::optional<std::function<void(bool /* isBeyondThreshold */)>> getOnScrollPositionThresholdChange() = 0;
64
+ virtual void setOnScrollPositionThresholdChange(const std::optional<std::function<void(bool /* isBeyondThreshold */)>>& onScrollPositionThresholdChange) = 0;
59
65
  virtual NativeListKeyboardDismissMode getKeyboardDismissMode() = 0;
60
66
  virtual void setKeyboardDismissMode(NativeListKeyboardDismissMode keyboardDismissMode) = 0;
61
67
  virtual NativeListKeyboardShouldPersistTaps getKeyboardShouldPersistTaps() = 0;
@@ -21,6 +21,9 @@ namespace margelo::nitro::nativelist::views {
21
21
  const react::RawProps& rawProps):
22
22
  react::ViewProps(context, sourceProps, rawProps, filterObjectKeys),
23
23
  snapshotJson(nitro::ReactProp<std::string>::fromRawValue("NativeList", "snapshotJson", rawProps, sourceProps.snapshotJson)),
24
+ containerSlotHeightsJson(nitro::ReactProp<std::string>::fromRawValue("NativeList", "containerSlotHeightsJson", rawProps, sourceProps.containerSlotHeightsJson)),
25
+ scrollPositionThresholdsJson(nitro::ReactProp<std::string>::fromRawValue("NativeList", "scrollPositionThresholdsJson", rawProps, sourceProps.scrollPositionThresholdsJson)),
26
+ onScrollPositionThresholdChange(nitro::ReactProp<std::optional<std::function<void(bool /* isBeyondThreshold */)>>>::fromRawValue("NativeList", "onScrollPositionThresholdChange", rawProps, sourceProps.onScrollPositionThresholdChange)),
24
27
  keyboardDismissMode(nitro::ReactProp<NativeListKeyboardDismissMode>::fromRawValue("NativeList", "keyboardDismissMode", rawProps, sourceProps.keyboardDismissMode)),
25
28
  keyboardShouldPersistTaps(nitro::ReactProp<NativeListKeyboardShouldPersistTaps>::fromRawValue("NativeList", "keyboardShouldPersistTaps", rawProps, sourceProps.keyboardShouldPersistTaps)),
26
29
  onRowAction(nitro::ReactProp<std::optional<std::function<void(const std::string& /* payloadJson */)>>>::fromRawValue("NativeList", "onRowAction", rawProps, sourceProps.onRowAction)),
@@ -34,6 +37,9 @@ namespace margelo::nitro::nativelist::views {
34
37
  bool HybridNativeListProps::filterObjectKeys(const std::string& propName) {
35
38
  switch (hashString(propName)) {
36
39
  case hashString("snapshotJson"): return true;
40
+ case hashString("containerSlotHeightsJson"): return true;
41
+ case hashString("scrollPositionThresholdsJson"): return true;
42
+ case hashString("onScrollPositionThresholdChange"): return true;
37
43
  case hashString("keyboardDismissMode"): return true;
38
44
  case hashString("keyboardShouldPersistTaps"): return true;
39
45
  case hashString("onRowAction"): return true;
@@ -18,10 +18,10 @@
18
18
  #include <string>
19
19
 
20
20
  #include <string>
21
- #include "NativeListKeyboardDismissMode.hpp"
22
- #include "NativeListKeyboardShouldPersistTaps.hpp"
23
21
  #include <functional>
24
22
  #include <optional>
23
+ #include "NativeListKeyboardDismissMode.hpp"
24
+ #include "NativeListKeyboardShouldPersistTaps.hpp"
25
25
  #include <memory>
26
26
  #include "HybridNativeListSpec.hpp"
27
27
 
@@ -46,6 +46,9 @@ namespace margelo::nitro::nativelist::views {
46
46
 
47
47
  public:
48
48
  nitro::ReactProp<std::string> snapshotJson;
49
+ nitro::ReactProp<std::string> containerSlotHeightsJson;
50
+ nitro::ReactProp<std::string> scrollPositionThresholdsJson;
51
+ nitro::ReactProp<std::optional<std::function<void(bool /* isBeyondThreshold */)>>> onScrollPositionThresholdChange;
49
52
  nitro::ReactProp<NativeListKeyboardDismissMode> keyboardDismissMode;
50
53
  nitro::ReactProp<NativeListKeyboardShouldPersistTaps> keyboardShouldPersistTaps;
51
54
  nitro::ReactProp<std::optional<std::function<void(const std::string& /* payloadJson */)>>> onRowAction;
@@ -59,6 +62,9 @@ namespace margelo::nitro::nativelist::views {
59
62
  [[nodiscard]]
60
63
  bool hasSameProps(const HybridNativeListProps& other) const noexcept {
61
64
  return snapshotJson.hasSameValue(other.snapshotJson) &&
65
+ containerSlotHeightsJson.hasSameValue(other.containerSlotHeightsJson) &&
66
+ scrollPositionThresholdsJson.hasSameValue(other.scrollPositionThresholdsJson) &&
67
+ onScrollPositionThresholdChange.hasSameValue(other.onScrollPositionThresholdChange) &&
62
68
  keyboardDismissMode.hasSameValue(other.keyboardDismissMode) &&
63
69
  keyboardShouldPersistTaps.hasSameValue(other.keyboardShouldPersistTaps) &&
64
70
  onRowAction.hasSameValue(other.onRowAction) &&
@@ -73,6 +79,9 @@ namespace margelo::nitro::nativelist::views {
73
79
  [[nodiscard]]
74
80
  bool hasAnyProvidedProps() const noexcept {
75
81
  return snapshotJson.isProvided() ||
82
+ containerSlotHeightsJson.isProvided() ||
83
+ scrollPositionThresholdsJson.isProvided() ||
84
+ onScrollPositionThresholdChange.isProvided() ||
76
85
  keyboardDismissMode.isProvided() ||
77
86
  keyboardShouldPersistTaps.isProvided() ||
78
87
  onRowAction.isProvided() ||
@@ -5,6 +5,9 @@
5
5
  "directEventTypes": {},
6
6
  "validAttributes": {
7
7
  "snapshotJson": true,
8
+ "containerSlotHeightsJson": true,
9
+ "scrollPositionThresholdsJson": true,
10
+ "onScrollPositionThresholdChange": true,
8
11
  "keyboardDismissMode": true,
9
12
  "keyboardShouldPersistTaps": true,
10
13
  "onRowAction": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-native-list",
3
- "version": "3.0.157-alpha.253",
3
+ "version": "3.0.157-alpha.255",
4
4
  "description": "Template-driven native RecyclerView and UICollectionView for React Native",
5
5
  "source": "./src/index.ts",
6
6
  "main": "./lib/module/index.js",
@@ -30,12 +30,13 @@
30
30
  "!android/build",
31
31
  "!android/app/build",
32
32
  "!**/__tests__",
33
- "!**/*.map"
33
+ "!**/*.map",
34
+ "scripts"
34
35
  ],
35
36
  "scripts": {
36
37
  "clean": "del-cli lib",
37
38
  "prepare": "del-cli lib && bob build && cp -r nitrogen lib/nitrogen",
38
- "nitrogen": "nitrogen",
39
+ "nitrogen": "nitrogen && node scripts/enable-container-slots.mjs",
39
40
  "typecheck": "tsc -b",
40
41
  "lint": "eslint \"**/*.{js,ts,tsx}\"",
41
42
  "test": "jest --runInBand",
@@ -83,8 +84,8 @@
83
84
  "typescript": "^5.9.2"
84
85
  },
85
86
  "peerDependencies": {
86
- "@onekeyfe/react-native-image": "3.0.157-alpha.253",
87
- "@onekeyfe/react-native-native-logger": "3.0.157-alpha.253",
87
+ "@onekeyfe/react-native-image": "3.0.157-alpha.255",
88
+ "@onekeyfe/react-native-native-logger": "3.0.157-alpha.255",
88
89
  "react": "*",
89
90
  "react-native": "*",
90
91
  "react-native-nitro-modules": "0.37.0"
@@ -13,6 +13,7 @@ Pod::Spec.new do |s|
13
13
  s.module_name = "NativeListModule"
14
14
  s.source = { :git => "https://github.com/OneKeyHQ/app-modules.git", :tag => "#{s.version}" }
15
15
  s.source_files = ["ios/**/*.{swift,h,m,mm,cpp}"]
16
+ s.exclude_files = "ios/tests/**/*"
16
17
  s.resource_bundles = {
17
18
  "NativeListResources" => [
18
19
  "common/fonts/*.ttf",
@@ -32,6 +33,11 @@ Pod::Spec.new do |s|
32
33
  s.dependency "React-jsi"
33
34
  s.dependency "React-callinvoker"
34
35
 
36
+ s.test_spec "Tests" do |test_spec|
37
+ test_spec.source_files = "ios/tests/**/*.swift"
38
+ test_spec.pod_target_xcconfig = { "PRODUCT_MODULE_NAME" => "NativeListModuleTests" }
39
+ end
40
+
35
41
  load "nitrogen/generated/ios/NativeListModule+autolinking.rb"
36
42
  add_nitrogen_files(s)
37
43
  install_modules_dependencies(s)
@@ -0,0 +1,58 @@
1
+ // Nitro 0.37 emits leaf view managers. Container slots need explicit Fabric
2
+ // child ownership, reapplied deterministically after every nitrogen build.
3
+ import { readFileSync, writeFileSync } from 'node:fs';
4
+ import { dirname, join } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const root = join(dirname(fileURLToPath(import.meta.url)), '..');
8
+ const android = join(root, 'nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/views/HybridNativeListManager.kt');
9
+ const ios = join(root, 'nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm');
10
+ const marker = '// NativeList container slot mounting';
11
+ let kotlin = readFileSync(android, 'utf8');
12
+ if (!kotlin.includes(marker)) {
13
+ if (!kotlin.includes('SimpleViewManager<View>')) throw new Error('Unexpected Nitro Android manager shape');
14
+ kotlin = kotlin.replace('import android.view.View\n', 'import android.view.View\nimport android.view.ViewGroup\n');
15
+ kotlin = kotlin.replace('import com.facebook.react.uimanager.SimpleViewManager', 'import com.facebook.react.uimanager.ViewGroupManager');
16
+ kotlin = kotlin.replace('SimpleViewManager<View>()', 'ViewGroupManager<ViewGroup>()');
17
+ kotlin = kotlin.replaceAll('view: View', 'view: ViewGroup');
18
+ kotlin = kotlin.replace('): View {', '): ViewGroup {').replace('): View? {', '): ViewGroup? {');
19
+ kotlin = kotlin.replace('val view = hybridView.view', 'val view = hybridView.view as ViewGroup');
20
+ kotlin = kotlin.replace('return hybridView.view', 'return hybridView.view as ViewGroup');
21
+ kotlin = kotlin.replace(' override fun getName(): String {', ` ${marker}
22
+ override fun needsCustomLayoutForChildren(): Boolean = true
23
+ override fun addView(parent: ViewGroup, child: View, index: Int) {
24
+ (parent as NativeListView).mountContainerSlot(child, index)
25
+ }
26
+ override fun getChildCount(parent: ViewGroup): Int = (parent as NativeListView).containerSlotCount()
27
+ override fun getChildAt(parent: ViewGroup, index: Int): View = (parent as NativeListView).containerSlotAt(index)
28
+ override fun removeViewAt(parent: ViewGroup, index: Int) {
29
+ (parent as NativeListView).unmountContainerSlot(index)
30
+ }
31
+ override fun removeAllViews(parent: ViewGroup) {
32
+ while (getChildCount(parent) > 0) removeViewAt(parent, getChildCount(parent) - 1)
33
+ }
34
+
35
+ override fun getName(): String {`);
36
+ writeFileSync(android, kotlin);
37
+ }
38
+ let objc = readFileSync(ios, 'utf8');
39
+ if (!objc.includes(marker)) {
40
+ if (!objc.includes('- (void) updateView {')) throw new Error('Unexpected Nitro iOS component shape');
41
+ objc = objc.replace('@implementation HybridNativeListComponent {', `@interface UIView (NativeListContainerSlots)
42
+ - (void)mountContainerSlot:(UIView *)view atIndex:(NSInteger)index;
43
+ - (void)unmountContainerSlot:(UIView *)view;
44
+ @end
45
+
46
+ @implementation HybridNativeListComponent {`);
47
+ objc = objc.replace('- (void) updateView {', `${marker}
48
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)child index:(NSInteger)index {
49
+ [self.contentView mountContainerSlot:child atIndex:index];
50
+ }
51
+
52
+ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)child index:(NSInteger)index {
53
+ [self.contentView unmountContainerSlot:child];
54
+ }
55
+
56
+ - (void) updateView {`);
57
+ writeFileSync(ios, objc);
58
+ }
@@ -0,0 +1,58 @@
1
+ import assert from 'node:assert/strict';
2
+ import { execFileSync, spawnSync } from 'node:child_process';
3
+ import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { dirname, join } from 'node:path';
6
+ import { test } from 'node:test';
7
+ import { fileURLToPath } from 'node:url';
8
+
9
+ const script = readFileSync(join(dirname(fileURLToPath(import.meta.url)), 'enable-container-slots.mjs'), 'utf8');
10
+ const androidPath = 'nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/views/HybridNativeListManager.kt';
11
+ const iosPath = 'nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm';
12
+
13
+ function fixture(android, ios) {
14
+ const root = mkdtempSync(join(tmpdir(), 'native-list-slots-'));
15
+ for (const [relative, content] of [['scripts/enable-container-slots.mjs', script], [androidPath, android], [iosPath, ios]]) {
16
+ const path = join(root, relative);
17
+ mkdirSync(dirname(path), { recursive: true });
18
+ writeFileSync(path, content);
19
+ }
20
+ return root;
21
+ }
22
+
23
+ test('post-nitrogen child ownership transformation is idempotent', () => {
24
+ const root = fixture(`import android.view.View
25
+ import com.facebook.react.uimanager.SimpleViewManager
26
+ public class HybridNativeListManager: SimpleViewManager<View>() {
27
+ override fun getName(): String { return "NativeList" }
28
+ override fun createViewInstance(reactContext: ThemedReactContext): View {
29
+ val view = hybridView.view
30
+ return view
31
+ }
32
+ }`, `@implementation HybridNativeListComponent {
33
+ }
34
+ - (void) updateView {
35
+ }`);
36
+ try {
37
+ const path = join(root, 'scripts/enable-container-slots.mjs');
38
+ execFileSync(process.execPath, [path]);
39
+ const firstAndroid = readFileSync(join(root, androidPath), 'utf8');
40
+ const firstIOS = readFileSync(join(root, iosPath), 'utf8');
41
+ assert.match(firstAndroid, /ViewGroupManager<ViewGroup>/);
42
+ assert.match(firstAndroid, /unmountContainerSlot\(index\)/);
43
+ assert.match(firstIOS, /mountChildComponentView/);
44
+ assert.match(firstIOS, /unmountContainerSlot:child/);
45
+ execFileSync(process.execPath, [path]);
46
+ assert.equal(readFileSync(join(root, androidPath), 'utf8'), firstAndroid);
47
+ assert.equal(readFileSync(join(root, iosPath), 'utf8'), firstIOS);
48
+ } finally { rmSync(root, { recursive: true, force: true }); }
49
+ });
50
+
51
+ test('unexpected nitrogen output fails instead of silently losing child mounting', () => {
52
+ const root = fixture('unrecognized generator output', '- (void) updateView {');
53
+ try {
54
+ const result = spawnSync(process.execPath, [join(root, 'scripts/enable-container-slots.mjs')]);
55
+ assert.notEqual(result.status, 0);
56
+ assert.match(result.stderr.toString(), /Unexpected Nitro Android manager shape/);
57
+ } finally { rmSync(root, { recursive: true, force: true }); }
58
+ });
@@ -11,6 +11,9 @@ import type {
11
11
  */
12
12
  export interface NativeListNativeProps extends HybridViewProps {
13
13
  snapshotJson: string;
14
+ containerSlotHeightsJson: string;
15
+ scrollPositionThresholdsJson: string;
16
+ onScrollPositionThresholdChange?: (isBeyondThreshold: boolean) => void;
14
17
  keyboardDismissMode: NativeListKeyboardDismissMode;
15
18
  keyboardShouldPersistTaps: NativeListKeyboardShouldPersistTaps;
16
19
  onRowAction?: (payloadJson: string) => void;