aix 0.0.15 → 0.1.0

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 (241) hide show
  1. package/Aix.podspec +32 -0
  2. package/LICENSE +2 -2
  3. package/README.md +165 -33
  4. package/android/CMakeLists.txt +32 -0
  5. package/android/build.gradle +148 -0
  6. package/android/fix-prefab.gradle +51 -0
  7. package/android/gradle.properties +5 -0
  8. package/android/src/main/AndroidManifest.xml +2 -0
  9. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  10. package/android/src/main/java/com/aix/AixPackage.kt +29 -0
  11. package/android/src/main/java/com/aix/HybridAix.kt +27 -0
  12. package/ios/Bridge.h +8 -0
  13. package/ios/HybridAix.swift +1072 -0
  14. package/ios/HybridAixCellView.swift +174 -0
  15. package/ios/HybridAixComposer.swift +119 -0
  16. package/lib/commonjs/aix.js +25 -0
  17. package/lib/commonjs/aix.js.map +1 -0
  18. package/lib/commonjs/fade-in/createUsePool.js +50 -0
  19. package/lib/commonjs/fade-in/createUsePool.js.map +1 -0
  20. package/lib/commonjs/fade-in/createUseStaggered.js +82 -0
  21. package/lib/commonjs/fade-in/createUseStaggered.js.map +1 -0
  22. package/lib/commonjs/fade-in/index.js +78 -0
  23. package/lib/commonjs/fade-in/index.js.map +1 -0
  24. package/lib/commonjs/footer.js +28 -0
  25. package/lib/commonjs/footer.js.map +1 -0
  26. package/lib/commonjs/index.js +48 -0
  27. package/lib/commonjs/index.js.map +1 -0
  28. package/lib/commonjs/package.json +1 -0
  29. package/lib/commonjs/views/aix.nitro.js +6 -0
  30. package/lib/commonjs/views/aix.nitro.js.map +1 -0
  31. package/lib/module/aix.js +20 -0
  32. package/lib/module/aix.js.map +1 -0
  33. package/lib/module/fade-in/createUsePool.js +46 -0
  34. package/lib/module/fade-in/createUsePool.js.map +1 -0
  35. package/lib/module/fade-in/createUseStaggered.js +79 -0
  36. package/lib/module/fade-in/createUseStaggered.js.map +1 -0
  37. package/lib/module/fade-in/index.js +74 -0
  38. package/lib/module/fade-in/index.js.map +1 -0
  39. package/lib/module/footer.js +23 -0
  40. package/lib/module/footer.js.map +1 -0
  41. package/lib/module/index.js +13 -0
  42. package/lib/module/index.js.map +1 -0
  43. package/lib/module/package.json +1 -0
  44. package/lib/module/views/aix.nitro.js +4 -0
  45. package/lib/module/views/aix.nitro.js.map +1 -0
  46. package/lib/typescript/src/aix.d.ts +14 -0
  47. package/lib/typescript/src/aix.d.ts.map +1 -0
  48. package/lib/typescript/src/fade-in/createUsePool.d.ts +5 -0
  49. package/lib/typescript/src/fade-in/createUsePool.d.ts.map +1 -0
  50. package/lib/typescript/src/fade-in/createUseStaggered.d.ts +2 -0
  51. package/lib/typescript/src/fade-in/createUseStaggered.d.ts.map +1 -0
  52. package/lib/typescript/src/fade-in/index.d.ts +5 -0
  53. package/lib/typescript/src/fade-in/index.d.ts.map +1 -0
  54. package/lib/typescript/src/footer.d.ts +5 -0
  55. package/lib/typescript/src/footer.d.ts.map +1 -0
  56. package/lib/typescript/src/index.d.ts +10 -0
  57. package/lib/typescript/src/index.d.ts.map +1 -0
  58. package/lib/typescript/src/views/aix.nitro.d.ts +101 -0
  59. package/lib/typescript/src/views/aix.nitro.d.ts.map +1 -0
  60. package/nitro.json +26 -0
  61. package/nitrogen/generated/.gitattributes +1 -0
  62. package/nitrogen/generated/android/Aix+autolinking.cmake +91 -0
  63. package/nitrogen/generated/android/Aix+autolinking.gradle +27 -0
  64. package/nitrogen/generated/android/AixOnLoad.cpp +70 -0
  65. package/nitrogen/generated/android/AixOnLoad.hpp +25 -0
  66. package/nitrogen/generated/android/c++/JAixAdditionalContentInsets.hpp +61 -0
  67. package/nitrogen/generated/android/c++/JAixAdditionalContentInsetsProp.hpp +63 -0
  68. package/nitrogen/generated/android/c++/JAixScrollIndicatorInsetValue.hpp +61 -0
  69. package/nitrogen/generated/android/c++/JAixScrollIndicatorInsets.hpp +63 -0
  70. package/nitrogen/generated/android/c++/JAixScrollOnFooterSizeUpdate.hpp +65 -0
  71. package/nitrogen/generated/android/c++/JHybridAixCellViewSpec.cpp +65 -0
  72. package/nitrogen/generated/android/c++/JHybridAixCellViewSpec.hpp +68 -0
  73. package/nitrogen/generated/android/c++/JHybridAixComposerSpec.cpp +48 -0
  74. package/nitrogen/generated/android/c++/JHybridAixComposerSpec.hpp +65 -0
  75. package/nitrogen/generated/android/c++/JHybridAixSpec.cpp +137 -0
  76. package/nitrogen/generated/android/c++/JHybridAixSpec.hpp +79 -0
  77. package/nitrogen/generated/android/c++/views/JHybridAixCellViewStateUpdater.cpp +60 -0
  78. package/nitrogen/generated/android/c++/views/JHybridAixCellViewStateUpdater.hpp +49 -0
  79. package/nitrogen/generated/android/c++/views/JHybridAixComposerStateUpdater.cpp +53 -0
  80. package/nitrogen/generated/android/c++/views/JHybridAixComposerStateUpdater.hpp +49 -0
  81. package/nitrogen/generated/android/c++/views/JHybridAixStateUpdater.cpp +80 -0
  82. package/nitrogen/generated/android/c++/views/JHybridAixStateUpdater.hpp +49 -0
  83. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixAdditionalContentInsets.kt +41 -0
  84. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixAdditionalContentInsetsProp.kt +41 -0
  85. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixOnLoad.kt +35 -0
  86. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixScrollIndicatorInsetValue.kt +41 -0
  87. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixScrollIndicatorInsets.kt +41 -0
  88. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixScrollOnFooterSizeUpdate.kt +44 -0
  89. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/HybridAixCellViewSpec.kt +65 -0
  90. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/HybridAixComposerSpec.kt +55 -0
  91. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/HybridAixSpec.kt +101 -0
  92. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/views/HybridAixCellViewManager.kt +50 -0
  93. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/views/HybridAixCellViewStateUpdater.kt +23 -0
  94. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/views/HybridAixComposerManager.kt +50 -0
  95. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/views/HybridAixComposerStateUpdater.kt +23 -0
  96. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/views/HybridAixManager.kt +50 -0
  97. package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/views/HybridAixStateUpdater.kt +23 -0
  98. package/nitrogen/generated/ios/Aix+autolinking.rb +60 -0
  99. package/nitrogen/generated/ios/Aix-Swift-Cxx-Bridge.cpp +67 -0
  100. package/nitrogen/generated/ios/Aix-Swift-Cxx-Bridge.hpp +222 -0
  101. package/nitrogen/generated/ios/Aix-Swift-Cxx-Umbrella.hpp +70 -0
  102. package/nitrogen/generated/ios/AixAutolinking.mm +49 -0
  103. package/nitrogen/generated/ios/AixAutolinking.swift +55 -0
  104. package/nitrogen/generated/ios/c++/HybridAixCellViewSpecSwift.cpp +11 -0
  105. package/nitrogen/generated/ios/c++/HybridAixCellViewSpecSwift.hpp +80 -0
  106. package/nitrogen/generated/ios/c++/HybridAixComposerSpecSwift.cpp +11 -0
  107. package/nitrogen/generated/ios/c++/HybridAixComposerSpecSwift.hpp +69 -0
  108. package/nitrogen/generated/ios/c++/HybridAixSpecSwift.cpp +11 -0
  109. package/nitrogen/generated/ios/c++/HybridAixSpecSwift.hpp +142 -0
  110. package/nitrogen/generated/ios/c++/views/HybridAixCellViewComponent.mm +101 -0
  111. package/nitrogen/generated/ios/c++/views/HybridAixComponent.mm +126 -0
  112. package/nitrogen/generated/ios/c++/views/HybridAixComposerComponent.mm +92 -0
  113. package/nitrogen/generated/ios/swift/AixAdditionalContentInsets.swift +47 -0
  114. package/nitrogen/generated/ios/swift/AixAdditionalContentInsetsProp.swift +71 -0
  115. package/nitrogen/generated/ios/swift/AixScrollIndicatorInsetValue.swift +47 -0
  116. package/nitrogen/generated/ios/swift/AixScrollIndicatorInsets.swift +71 -0
  117. package/nitrogen/generated/ios/swift/AixScrollOnFooterSizeUpdate.swift +89 -0
  118. package/nitrogen/generated/ios/swift/HybridAixCellViewSpec.swift +57 -0
  119. package/nitrogen/generated/ios/swift/HybridAixCellViewSpec_cxx.swift +151 -0
  120. package/nitrogen/generated/ios/swift/HybridAixComposerSpec.swift +56 -0
  121. package/nitrogen/generated/ios/swift/HybridAixComposerSpec_cxx.swift +131 -0
  122. package/nitrogen/generated/ios/swift/HybridAixSpec.swift +63 -0
  123. package/nitrogen/generated/ios/swift/HybridAixSpec_cxx.swift +292 -0
  124. package/nitrogen/generated/shared/c++/AixAdditionalContentInsets.hpp +79 -0
  125. package/nitrogen/generated/shared/c++/AixAdditionalContentInsetsProp.hpp +81 -0
  126. package/nitrogen/generated/shared/c++/AixScrollIndicatorInsetValue.hpp +79 -0
  127. package/nitrogen/generated/shared/c++/AixScrollIndicatorInsets.hpp +81 -0
  128. package/nitrogen/generated/shared/c++/AixScrollOnFooterSizeUpdate.hpp +83 -0
  129. package/nitrogen/generated/shared/c++/HybridAixCellViewSpec.cpp +24 -0
  130. package/nitrogen/generated/shared/c++/HybridAixCellViewSpec.hpp +65 -0
  131. package/nitrogen/generated/shared/c++/HybridAixComposerSpec.cpp +21 -0
  132. package/nitrogen/generated/shared/c++/HybridAixComposerSpec.hpp +62 -0
  133. package/nitrogen/generated/shared/c++/HybridAixSpec.cpp +36 -0
  134. package/nitrogen/generated/shared/c++/HybridAixSpec.hpp +85 -0
  135. package/nitrogen/generated/shared/c++/views/HybridAixCellViewComponent.cpp +99 -0
  136. package/nitrogen/generated/shared/c++/views/HybridAixCellViewComponent.hpp +108 -0
  137. package/nitrogen/generated/shared/c++/views/HybridAixComponent.cpp +159 -0
  138. package/nitrogen/generated/shared/c++/views/HybridAixComponent.hpp +117 -0
  139. package/nitrogen/generated/shared/c++/views/HybridAixComposerComponent.cpp +75 -0
  140. package/nitrogen/generated/shared/c++/views/HybridAixComposerComponent.hpp +106 -0
  141. package/nitrogen/generated/shared/json/AixCellViewConfig.json +11 -0
  142. package/nitrogen/generated/shared/json/AixComposerConfig.json +9 -0
  143. package/nitrogen/generated/shared/json/AixConfig.json +16 -0
  144. package/package.json +113 -14
  145. package/src/aix.tsx +43 -0
  146. package/src/fade-in/createUsePool.ts +46 -0
  147. package/src/fade-in/createUseStaggered.ts +82 -0
  148. package/src/fade-in/index.tsx +97 -0
  149. package/src/footer.tsx +30 -0
  150. package/src/index.ts +20 -16
  151. package/src/views/aix.nitro.ts +148 -0
  152. package/docs/API.md +0 -288
  153. package/jest.config.js +0 -17
  154. package/lib/__tests__/deferredIterable.test.d.ts +0 -1
  155. package/lib/__tests__/deferredIterable.test.js +0 -108
  156. package/lib/__tests__/filter.test.d.ts +0 -1
  157. package/lib/__tests__/filter.test.js +0 -53
  158. package/lib/__tests__/flatMap.test.d.ts +0 -1
  159. package/lib/__tests__/flatMap.test.js +0 -77
  160. package/lib/__tests__/lookahead.test.d.ts +0 -1
  161. package/lib/__tests__/lookahead.test.js +0 -57
  162. package/lib/__tests__/map.test.d.ts +0 -1
  163. package/lib/__tests__/map.test.js +0 -53
  164. package/lib/__tests__/merge.test.d.ts +0 -1
  165. package/lib/__tests__/merge.test.js +0 -55
  166. package/lib/__tests__/reduce.test.d.ts +0 -1
  167. package/lib/__tests__/reduce.test.js +0 -52
  168. package/lib/__tests__/spanAll.test.d.ts +0 -1
  169. package/lib/__tests__/spanAll.test.js +0 -120
  170. package/lib/concat.d.ts +0 -4
  171. package/lib/concat.js +0 -126
  172. package/lib/deferred.d.ts +0 -9
  173. package/lib/deferred.js +0 -18
  174. package/lib/deferredIterable.d.ts +0 -22
  175. package/lib/deferredIterable.js +0 -111
  176. package/lib/filter.d.ts +0 -7
  177. package/lib/filter.js +0 -99
  178. package/lib/flatMap.d.ts +0 -1
  179. package/lib/flatMap.js +0 -119
  180. package/lib/fromEvent.d.ts +0 -5
  181. package/lib/fromEvent.js +0 -13
  182. package/lib/index.d.ts +0 -16
  183. package/lib/index.js +0 -34
  184. package/lib/insert.d.ts +0 -4
  185. package/lib/insert.js +0 -113
  186. package/lib/interval.d.ts +0 -4
  187. package/lib/interval.js +0 -64
  188. package/lib/iterableToArray.d.ts +0 -1
  189. package/lib/iterableToArray.js +0 -87
  190. package/lib/iteratorToIterable.d.ts +0 -6
  191. package/lib/iteratorToIterable.js +0 -70
  192. package/lib/lookahead.d.ts +0 -10
  193. package/lib/lookahead.js +0 -78
  194. package/lib/map.d.ts +0 -4
  195. package/lib/map.js +0 -98
  196. package/lib/merge.d.ts +0 -6
  197. package/lib/merge.js +0 -21
  198. package/lib/of.d.ts +0 -3
  199. package/lib/of.js +0 -5
  200. package/lib/reduce.d.ts +0 -4
  201. package/lib/reduce.js +0 -92
  202. package/lib/restToIterable.d.ts +0 -4
  203. package/lib/restToIterable.js +0 -73
  204. package/lib/spanAll.d.ts +0 -1
  205. package/lib/spanAll.js +0 -29
  206. package/lib/tap.d.ts +0 -4
  207. package/lib/tap.js +0 -96
  208. package/lib/toCallbacks.d.ts +0 -11
  209. package/lib/toCallbacks.js +0 -97
  210. package/lib/zip.d.ts +0 -4
  211. package/lib/zip.js +0 -75
  212. package/src/__tests__/deferredIterable.test.ts +0 -22
  213. package/src/__tests__/filter.test.ts +0 -10
  214. package/src/__tests__/flatMap.test.ts +0 -12
  215. package/src/__tests__/lookahead.test.ts +0 -9
  216. package/src/__tests__/map.test.ts +0 -10
  217. package/src/__tests__/merge.test.ts +0 -9
  218. package/src/__tests__/reduce.test.ts +0 -10
  219. package/src/__tests__/spanAll.test.ts +0 -17
  220. package/src/concat.ts +0 -13
  221. package/src/deferred.ts +0 -16
  222. package/src/deferredIterable.ts +0 -111
  223. package/src/filter.ts +0 -16
  224. package/src/flatMap.ts +0 -9
  225. package/src/fromEvent.ts +0 -16
  226. package/src/insert.ts +0 -13
  227. package/src/interval.ts +0 -20
  228. package/src/iterableToArray.ts +0 -7
  229. package/src/iteratorToIterable.ts +0 -12
  230. package/src/lookahead.ts +0 -27
  231. package/src/map.ts +0 -11
  232. package/src/merge.ts +0 -18
  233. package/src/of.ts +0 -4
  234. package/src/reduce.ts +0 -12
  235. package/src/restToIterable.ts +0 -8
  236. package/src/spanAll.ts +0 -26
  237. package/src/tap.ts +0 -11
  238. package/src/toCallbacks.ts +0 -27
  239. package/src/zip.ts +0 -19
  240. package/tsconfig.json +0 -63
  241. package/yarn.lock +0 -3514
package/Aix.podspec ADDED
@@ -0,0 +1,32 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "Aix"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => min_ios_version_supported, :visionos => 1.0 }
14
+ s.source = { :git => "https://github.com/vercel/aix.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = [
17
+ # Implementation (Swift)
18
+ "ios/**/*.{swift}",
19
+ # Autolinking/Registration (Objective-C++)
20
+ "ios/**/*.{m,mm}",
21
+ # Implementation (C++ objects)
22
+ "cpp/**/*.{hpp,cpp}",
23
+ ]
24
+
25
+ load 'nitrogen/generated/ios/Aix+autolinking.rb'
26
+ add_nitrogen_files(s)
27
+
28
+ s.dependency 'React-jsi'
29
+ s.dependency 'React-callinvoker'
30
+ s.dependency 'react-native-keyboard-controller'
31
+ install_modules_dependencies(s)
32
+ end
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2018 Jamie McCrindle
3
+ Copyright (c) 2025 Fernando Rojo
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,57 +1,189 @@
1
- # Async Iterator Extensions
1
+ # aix
2
2
 
3
- A library of async iterator extensions for JavaScript
3
+ Primitives for building beautiful AI chat apps with React Native.
4
4
 
5
- # Installation
5
+ > aix is currently in alpha preview. The API will change, and it is not yet feature complete.
6
6
 
7
- npm install aix # or yarn install aix
7
+ We're rewriting the engine that powers the chat experience in the v0 mobile app with a focus on native feel.
8
8
 
9
- # Why Aix?
9
+ aix is a native module with UIKit with Nitro Modules.
10
10
 
11
- Async iterators are a useful way to handle asynchronous streams. This library adds a number
12
- of utility methods similar to those found in lodash, underscore or Ramda.
11
+ ## Installation
13
12
 
14
- # Examples
13
+ ```bash
14
+ npm i aix react-native-nitro-modules
15
+ ```
16
+
17
+ Next, rebuild your native app. For Expo users, run `npx expo prebuild` and rebuild.
18
+
19
+ ## Usage
20
+
21
+ Wrap your `ScrollView` with `Aix`, and wrap your messages with `AixCell`.
22
+
23
+ <details>
24
+ <summary>Click here to view a full example</summary>
25
+ </details>
26
+
27
+ ```tsx
28
+ import { Aix, AixCell } from 'aix';
29
+ import { Message } from 'path/to/your/message';
30
+ import { Composer } from 'path/to/your/composer';
31
+
32
+ export function ChatScreen({ messages }) {
33
+ return (
34
+ <Aix style={{ flex: 1 }}>
35
+ <ScrollView>
36
+ {messages.map((message) => (
37
+ <AixCell
38
+ key={message.id}
39
+ index={index}
40
+ isLast={index === messages.length - 1}
41
+ >
42
+ <Message message={message} />
43
+ </AixCell>
44
+ ))}
45
+ </ScrollView>
46
+ </Aix>
47
+ );
48
+ }
49
+ ```
15
50
 
16
- ## fromEvents
51
+ To add a floating composer which lets content scroll under it, you can use the `AixFooter` and `KeyboardStickyView` from `react-native-keyboard-controller`:
52
+
53
+ ```tsx
54
+ import { Aix, AixCell, AixFooter } from 'aix';
55
+ import { KeyboardStickyView } from 'react-native-keyboard-controller';
56
+
57
+ export function ChatScreen({ messages }) {
58
+ return (
59
+ <Aix style={{ flex: 1 }}>
60
+ <ScrollView>
61
+ {messages.map((message) => (
62
+ <AixCell
63
+ key={message.id}
64
+ index={index}
65
+ isLast={index === messages.length - 1}
66
+ >
67
+ <Message message={message} />
68
+ </AixCell>
69
+ ))}
70
+ </ScrollView>
71
+
72
+ <KeyboardStickyView offset={{ opened: 0, closed: -bottomInsetPadding }}>
73
+ <AixFooter style={{ position: 'absolute', inset: 0, top: 'auto'}}>
74
+ <Composer />
75
+ </AixFooter>
76
+ </KeyboardStickyView>
77
+ </Aix>
78
+ );
79
+ }
80
+ ```
17
81
 
18
- ```fromEvents``` turns DOM events into an iterable.
82
+ ## TODOs
19
83
 
20
- ```javascript
21
- import { fromEvents } from "aix/fromEvents";
84
+ - [ ] Android support
85
+ - [ ] LegendList support
86
+ - [ ] FlashList support
22
87
 
23
- const clicks = fromEvents(document, 'click');
88
+ ## API Reference
24
89
 
25
- for await (const click of clicks) {
26
- console.log('a button was clicked');
27
- }
90
+ ### `Aix`
91
+
92
+ The main container component that provides keyboard-aware behavior and manages scrolling for chat interfaces.
93
+
94
+ #### Props
95
+
96
+ | Prop | Type | Default | Description |
97
+ |------|------|---------|-------------|
98
+ | `shouldStartAtEnd` | `boolean` | - | Whether the scroll view should start scrolled to the end of the content. |
99
+ | `scrollOnFooterSizeUpdate` | `object` | `{ enabled: true, scrolledToEndThreshold: 100, animated: false }` | Control the behavior of scrolling when the footer size changes. By default, changing the height of the footer will shift content up in the scroll view. |
100
+ | `scrollEndReachedThreshold` | `number` | `max(blankSize, 200)` | The number of pixels from the bottom of the scroll view to the end of the content that is considered "near the end". Used to determine if content should shift up when keyboard opens. |
101
+ | `additionalContentInsets` | `object` | - | Additional content insets applied when keyboard is open or closed. Shape: `{ top?: { whenKeyboardOpen, whenKeyboardClosed }, bottom?: { whenKeyboardOpen, whenKeyboardClosed } }` |
102
+ | `additionalScrollIndicatorInsets` | `object` | - | Additional insets for the scroll indicator, added to existing safe area insets. Applied to `verticalScrollIndicatorInsets` on iOS. |
103
+ | `mainScrollViewID` | `string` | - | The `nativeID` of the scroll view to use. If provided, will search for a scroll view with this `accessibilityIdentifier`. |
104
+ | `penultimateCellIndex` | `number` | - | The index of the second-to-last message (typically the last user message in AI chat apps). Used to determine which message will be scrolled into view. Useful when you have custom message types like timestamps in your list. |
105
+
106
+ #### Ref Methods
107
+
108
+ Access these methods via `useAixRef()`:
109
+
110
+ ```tsx
111
+ const aix = useAixRef();
112
+
113
+ // Scroll to the end of the content
114
+ aix.current?.scrollToEnd(animated);
115
+
116
+ // Scroll to a specific index when the blank size is ready
117
+ aix.current?.scrollToIndexWhenBlankSizeReady(index, animated, waitForKeyboardToEnd);
28
118
  ```
29
119
 
30
- ## DeferredIterable
120
+ | Method | Parameters | Description |
121
+ |--------|------------|-------------|
122
+ | `scrollToEnd` | `animated?: boolean` | Scrolls to the end of the content. |
123
+ | `scrollToIndexWhenBlankSizeReady` | `index: number, animated?: boolean, waitForKeyboardToEnd?: boolean` | Scrolls to a specific cell index once the blank size calculation is ready. |
31
124
 
32
- ```DeferredIterable``` makes it easy to turn stream of events into an iterable. The code below
33
- is essentially how ```fromEvents``` was implemented.
125
+ ---
34
126
 
35
- ```javascript
36
- import { DeferredIterable } from "aix/deferredIterable";
127
+ ### `AixCell`
37
128
 
38
- const deferredIterable = new DeferredIterable();
129
+ A wrapper component for each message in the list. It communicates cell position and dimensions to the parent `Aix` component.
39
130
 
40
- // set up a callback that calls value on the deferredIterable
41
- const callback = value => deferredIterable.value(value);
131
+ #### Props
42
132
 
43
- // attach the callback to the click event
44
- document.addEventListener('click', callback);
133
+ | Prop | Type | Required | Description |
134
+ |------|------|----------|-------------|
135
+ | `index` | `number` | Yes | The index of this cell in the message list. |
136
+ | `isLast` | `boolean` | Yes | Whether this cell is the last item in the list. Used for scroll positioning and animations. |
45
137
 
46
- // remove the callback when / if the iterable stops
47
- deferredIterable.finally(() => document.removeEventListener('click', deferredIterable.value));
138
+ ---
48
139
 
49
- // go through all the click events
50
- for await (const click of deferredIterable.iterable) {
51
- console.log('a button was clicked');
140
+ ### `AixFooter`
141
+
142
+ A footer component for floating composers that allows content to scroll underneath it. The footer's height is automatically tracked for proper scroll offset calculations.
143
+
144
+ #### Props
145
+
146
+ Accepts all standard React Native `View` props.
147
+
148
+ #### Important Notes
149
+
150
+ - **Do not apply vertical padding** (`padding`, `paddingBottom`) directly to `AixFooter`. Apply padding to a child view instead.
151
+ - Position the footer absolutely at the bottom of the `Aix` container:
152
+
153
+ ```tsx
154
+ <AixFooter style={{ position: 'absolute', inset: 0, top: 'auto' }}>
155
+ <Composer />
156
+ </AixFooter>
157
+ ```
158
+
159
+ ---
160
+
161
+ ### `useAixRef`
162
+
163
+ A hook that returns a ref to access imperative methods on the `Aix` component.
164
+
165
+ ```tsx
166
+ import { useAixRef } from 'aix';
167
+
168
+ function Chat({ messages }) {
169
+ const aix = useAixRef();
170
+ const send = useSendMessage()
171
+
172
+ const handleSend = () => {
173
+ // Scroll to end after sending a message
174
+ send(message);
175
+ aix.current?.scrollToIndexWhenBlankSizeReady(messages.length + 1, true);
176
+ requestAnimationFrame(Keyboard.dismiss);
177
+ };
178
+
179
+ return <Aix ref={aix}>{/* ... */}</Aix>;
52
180
  }
53
181
  ```
54
182
 
55
- # Reference Documentation
183
+ ## TODOs
184
+
185
+
186
+ ## Requirements
56
187
 
57
- * [API Reference](https://github.com/jamiemccrindle/aix/blob/master/docs/API.md)
188
+ - React Native v0.78.0 or higher
189
+ - Node 18.0.0 or higher
@@ -0,0 +1,32 @@
1
+ project(Aix)
2
+ cmake_minimum_required(VERSION 3.9.0)
3
+
4
+ set (PACKAGE_NAME Aix)
5
+ set (CMAKE_VERBOSE_MAKEFILE ON)
6
+ set (CMAKE_CXX_STANDARD 20)
7
+
8
+ # Enable Raw Props parsing in react-native (for Nitro Views)
9
+ add_compile_options(-DRN_SERIALIZABLE_STATE=1)
10
+
11
+ # Define C++ library and add all sources
12
+ add_library(${PACKAGE_NAME} SHARED
13
+ src/main/cpp/cpp-adapter.cpp
14
+ )
15
+
16
+ # Add Nitrogen specs :)
17
+ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/Aix+autolinking.cmake)
18
+
19
+ # Set up local includes
20
+ include_directories(
21
+ "src/main/cpp"
22
+ "../cpp"
23
+ )
24
+
25
+ find_library(LOG_LIB log)
26
+
27
+ # Link all libraries together
28
+ target_link_libraries(
29
+ ${PACKAGE_NAME}
30
+ ${LOG_LIB}
31
+ android # <-- Android core
32
+ )
@@ -0,0 +1,148 @@
1
+ buildscript {
2
+ repositories {
3
+ google()
4
+ mavenCentral()
5
+ }
6
+
7
+ dependencies {
8
+ classpath "com.android.tools.build:gradle:8.8.0"
9
+ }
10
+ }
11
+
12
+ def reactNativeArchitectures() {
13
+ def value = rootProject.getProperties().get("reactNativeArchitectures")
14
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
15
+ }
16
+
17
+ def isNewArchitectureEnabled() {
18
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
19
+ }
20
+
21
+ apply plugin: "com.android.library"
22
+ apply plugin: 'org.jetbrains.kotlin.android'
23
+ apply from: '../nitrogen/generated/android/Aix+autolinking.gradle'
24
+ apply from: "./fix-prefab.gradle"
25
+
26
+ if (isNewArchitectureEnabled()) {
27
+ apply plugin: "com.facebook.react"
28
+ }
29
+
30
+ def getExtOrDefault(name) {
31
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["Aix_" + name]
32
+ }
33
+
34
+ def getExtOrIntegerDefault(name) {
35
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Aix_" + name]).toInteger()
36
+ }
37
+
38
+ android {
39
+ namespace "com.aix"
40
+
41
+ ndkVersion getExtOrDefault("ndkVersion")
42
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
43
+
44
+ defaultConfig {
45
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
46
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
47
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
48
+
49
+ externalNativeBuild {
50
+ cmake {
51
+ cppFlags "-frtti -fexceptions -Wall -Wextra -fstack-protector-all"
52
+ arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
53
+ abiFilters (*reactNativeArchitectures())
54
+
55
+ buildTypes {
56
+ debug {
57
+ cppFlags "-O1 -g"
58
+ }
59
+ release {
60
+ cppFlags "-O2"
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ externalNativeBuild {
68
+ cmake {
69
+ path "CMakeLists.txt"
70
+ }
71
+ }
72
+
73
+ packagingOptions {
74
+ excludes = [
75
+ "META-INF",
76
+ "META-INF/**",
77
+ "**/libc++_shared.so",
78
+ "**/libfbjni.so",
79
+ "**/libjsi.so",
80
+ "**/libfolly_json.so",
81
+ "**/libfolly_runtime.so",
82
+ "**/libglog.so",
83
+ "**/libhermes.so",
84
+ "**/libhermes-executor-debug.so",
85
+ "**/libhermes_executor.so",
86
+ "**/libreactnative.so",
87
+ "**/libreactnativejni.so",
88
+ "**/libturbomodulejsijni.so",
89
+ "**/libreact_nativemodule_core.so",
90
+ "**/libjscexecutor.so"
91
+ ]
92
+ }
93
+
94
+ buildFeatures {
95
+ buildConfig true
96
+ prefab true
97
+ }
98
+
99
+ buildTypes {
100
+ release {
101
+ minifyEnabled false
102
+ }
103
+ }
104
+
105
+ lintOptions {
106
+ disable "GradleCompatible"
107
+ }
108
+
109
+ compileOptions {
110
+ sourceCompatibility JavaVersion.VERSION_1_8
111
+ targetCompatibility JavaVersion.VERSION_1_8
112
+ }
113
+
114
+ sourceSets {
115
+ main {
116
+ if (isNewArchitectureEnabled()) {
117
+ java.srcDirs += [
118
+ // React Codegen files
119
+ "${project.buildDir}/generated/source/codegen/java"
120
+ ]
121
+ }
122
+ }
123
+ }
124
+ }
125
+
126
+ repositories {
127
+ mavenCentral()
128
+ google()
129
+ }
130
+
131
+
132
+ dependencies {
133
+ // For < 0.71, this will be from the local maven repo
134
+ // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
135
+ //noinspection GradleDynamicVersion
136
+ implementation "com.facebook.react:react-native:+"
137
+
138
+ // Add a dependency on NitroModules
139
+ implementation project(":react-native-nitro-modules")
140
+ }
141
+
142
+ if (isNewArchitectureEnabled()) {
143
+ react {
144
+ jsRootDir = file("../src/")
145
+ libraryName = "Aix"
146
+ codegenJavaPackageName = "com.aix"
147
+ }
148
+ }
@@ -0,0 +1,51 @@
1
+ tasks.configureEach { task ->
2
+ // Make sure that we generate our prefab publication file only after having built the native library
3
+ // so that not a header publication file, but a full configuration publication will be generated, which
4
+ // will include the .so file
5
+
6
+ def prefabConfigurePattern = ~/^prefab(.+)ConfigurePackage$/
7
+ def matcher = task.name =~ prefabConfigurePattern
8
+ if (matcher.matches()) {
9
+ def variantName = matcher[0][1]
10
+ task.outputs.upToDateWhen { false }
11
+ task.dependsOn("externalNativeBuild${variantName}")
12
+ }
13
+ }
14
+
15
+ afterEvaluate {
16
+ def abis = reactNativeArchitectures()
17
+ rootProject.allprojects.each { proj ->
18
+ if (proj === rootProject) return
19
+
20
+ def dependsOnThisLib = proj.configurations.findAll { it.canBeResolved }.any { config ->
21
+ config.dependencies.any { dep ->
22
+ dep.group == project.group && dep.name == project.name
23
+ }
24
+ }
25
+ if (!dependsOnThisLib && proj != project) return
26
+
27
+ if (!proj.plugins.hasPlugin('com.android.application') && !proj.plugins.hasPlugin('com.android.library')) {
28
+ return
29
+ }
30
+
31
+ def variants = proj.android.hasProperty('applicationVariants') ? proj.android.applicationVariants : proj.android.libraryVariants
32
+ // Touch the prefab_config.json files to ensure that in ExternalNativeJsonGenerator.kt we will re-trigger the prefab CLI to
33
+ // generate a libnameConfig.cmake file that will contain our native library (.so).
34
+ // See this condition: https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ExternalNativeJsonGenerator.kt;l=207-219?q=createPrefabBuildSystemGlue
35
+ variants.all { variant ->
36
+ def variantName = variant.name
37
+ abis.each { abi ->
38
+ def searchDir = new File(proj.projectDir, ".cxx/${variantName}")
39
+ if (!searchDir.exists()) return
40
+ def matches = []
41
+ searchDir.eachDir { randomDir ->
42
+ def prefabFile = new File(randomDir, "${abi}/prefab_config.json")
43
+ if (prefabFile.exists()) matches << prefabFile
44
+ }
45
+ matches.each { prefabConfig ->
46
+ prefabConfig.setLastModified(System.currentTimeMillis())
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,5 @@
1
+ Aix_kotlinVersion=2.1.20
2
+ Aix_minSdkVersion=23
3
+ Aix_targetSdkVersion=35
4
+ Aix_compileSdkVersion=34
5
+ Aix_ndkVersion=27.1.12297006
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,6 @@
1
+ #include <jni.h>
2
+ #include "AixOnLoad.hpp"
3
+
4
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
5
+ return margelo::nitro::aix::initialize(vm);
6
+ }
@@ -0,0 +1,29 @@
1
+ package com.aix;
2
+
3
+ import com.facebook.react.bridge.NativeModule;
4
+ import com.facebook.react.bridge.ReactApplicationContext;
5
+ import com.facebook.react.module.model.ReactModuleInfoProvider;
6
+ import com.facebook.react.TurboReactPackage;
7
+ import com.facebook.react.uimanager.ViewManager;
8
+ import com.margelo.nitro.aix.*;
9
+ import com.margelo.nitro.aix.views.*;
10
+
11
+
12
+ public class AixPackage : TurboReactPackage() {
13
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? = null
14
+
15
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider = ReactModuleInfoProvider { emptyMap() }
16
+
17
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
18
+ val viewManagers = ArrayList<ViewManager<*, *>>()
19
+ viewManagers.add(HybridAixManager())
20
+ return viewManagers
21
+ }
22
+
23
+ companion object {
24
+ init {
25
+ AixOnLoad.initializeNative()
26
+ }
27
+ }
28
+ }
29
+
@@ -0,0 +1,27 @@
1
+ package com.aix
2
+
3
+ import android.graphics.Color
4
+ import android.view.View
5
+ import androidx.annotation.Keep
6
+ import com.facebook.proguard.annotations.DoNotStrip
7
+ import com.facebook.react.uimanager.ThemedReactContext
8
+ import com.margelo.nitro.aix.HybridAixSpec
9
+
10
+ @Keep
11
+ @DoNotStrip
12
+ class HybridAix(val context: ThemedReactContext): HybridAixSpec() {
13
+ // View
14
+ override val view: View = View(context)
15
+
16
+ // Props
17
+ private var _isRed = false
18
+ override var isRed: Boolean
19
+ get() = _isRed
20
+ set(value) {
21
+ _isRed = value
22
+ view.setBackgroundColor(
23
+ if (value) Color.RED
24
+ else Color.BLACK
25
+ )
26
+ }
27
+ }
package/ios/Bridge.h ADDED
@@ -0,0 +1,8 @@
1
+ //
2
+ // Bridge.h
3
+ // aix
4
+ //
5
+ // Created by Fernando Rojo on 12/11/2025
6
+ //
7
+
8
+ #pragma once