aix 0.0.14 → 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Aix.podspec +32 -0
- package/LICENSE +2 -2
- package/README.md +165 -33
- package/android/CMakeLists.txt +32 -0
- package/android/build.gradle +148 -0
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/cpp-adapter.cpp +6 -0
- package/android/src/main/java/com/aix/AixPackage.kt +29 -0
- package/android/src/main/java/com/aix/HybridAix.kt +27 -0
- package/ios/Bridge.h +8 -0
- package/ios/HybridAix.swift +1072 -0
- package/ios/HybridAixCellView.swift +174 -0
- package/ios/HybridAixComposer.swift +119 -0
- package/lib/commonjs/aix.js +25 -0
- package/lib/commonjs/aix.js.map +1 -0
- package/lib/commonjs/fade-in/createUsePool.js +50 -0
- package/lib/commonjs/fade-in/createUsePool.js.map +1 -0
- package/lib/commonjs/fade-in/createUseStaggered.js +82 -0
- package/lib/commonjs/fade-in/createUseStaggered.js.map +1 -0
- package/lib/commonjs/fade-in/index.js +78 -0
- package/lib/commonjs/fade-in/index.js.map +1 -0
- package/lib/commonjs/footer.js +28 -0
- package/lib/commonjs/footer.js.map +1 -0
- package/lib/commonjs/index.js +48 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/views/aix.nitro.js +6 -0
- package/lib/commonjs/views/aix.nitro.js.map +1 -0
- package/lib/module/aix.js +20 -0
- package/lib/module/aix.js.map +1 -0
- package/lib/module/fade-in/createUsePool.js +46 -0
- package/lib/module/fade-in/createUsePool.js.map +1 -0
- package/lib/module/fade-in/createUseStaggered.js +79 -0
- package/lib/module/fade-in/createUseStaggered.js.map +1 -0
- package/lib/module/fade-in/index.js +74 -0
- package/lib/module/fade-in/index.js.map +1 -0
- package/lib/module/footer.js +23 -0
- package/lib/module/footer.js.map +1 -0
- package/lib/module/index.js +13 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/views/aix.nitro.js +4 -0
- package/lib/module/views/aix.nitro.js.map +1 -0
- package/lib/typescript/src/aix.d.ts +14 -0
- package/lib/typescript/src/aix.d.ts.map +1 -0
- package/lib/typescript/src/fade-in/createUsePool.d.ts +5 -0
- package/lib/typescript/src/fade-in/createUsePool.d.ts.map +1 -0
- package/lib/typescript/src/fade-in/createUseStaggered.d.ts +2 -0
- package/lib/typescript/src/fade-in/createUseStaggered.d.ts.map +1 -0
- package/lib/typescript/src/fade-in/index.d.ts +5 -0
- package/lib/typescript/src/fade-in/index.d.ts.map +1 -0
- package/lib/typescript/src/footer.d.ts +5 -0
- package/lib/typescript/src/footer.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +10 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/views/aix.nitro.d.ts +101 -0
- package/lib/typescript/src/views/aix.nitro.d.ts.map +1 -0
- package/nitro.json +26 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/Aix+autolinking.cmake +91 -0
- package/nitrogen/generated/android/Aix+autolinking.gradle +27 -0
- package/nitrogen/generated/android/AixOnLoad.cpp +70 -0
- package/nitrogen/generated/android/AixOnLoad.hpp +25 -0
- package/nitrogen/generated/android/c++/JAixAdditionalContentInsets.hpp +61 -0
- package/nitrogen/generated/android/c++/JAixAdditionalContentInsetsProp.hpp +63 -0
- package/nitrogen/generated/android/c++/JAixScrollIndicatorInsetValue.hpp +61 -0
- package/nitrogen/generated/android/c++/JAixScrollIndicatorInsets.hpp +63 -0
- package/nitrogen/generated/android/c++/JAixScrollOnFooterSizeUpdate.hpp +65 -0
- package/nitrogen/generated/android/c++/JHybridAixCellViewSpec.cpp +65 -0
- package/nitrogen/generated/android/c++/JHybridAixCellViewSpec.hpp +68 -0
- package/nitrogen/generated/android/c++/JHybridAixComposerSpec.cpp +48 -0
- package/nitrogen/generated/android/c++/JHybridAixComposerSpec.hpp +65 -0
- package/nitrogen/generated/android/c++/JHybridAixSpec.cpp +137 -0
- package/nitrogen/generated/android/c++/JHybridAixSpec.hpp +79 -0
- package/nitrogen/generated/android/c++/views/JHybridAixCellViewStateUpdater.cpp +60 -0
- package/nitrogen/generated/android/c++/views/JHybridAixCellViewStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/c++/views/JHybridAixComposerStateUpdater.cpp +53 -0
- package/nitrogen/generated/android/c++/views/JHybridAixComposerStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/c++/views/JHybridAixStateUpdater.cpp +80 -0
- package/nitrogen/generated/android/c++/views/JHybridAixStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixAdditionalContentInsets.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixAdditionalContentInsetsProp.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixScrollIndicatorInsetValue.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixScrollIndicatorInsets.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixScrollOnFooterSizeUpdate.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/HybridAixCellViewSpec.kt +65 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/HybridAixComposerSpec.kt +55 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/HybridAixSpec.kt +101 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/views/HybridAixCellViewManager.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/views/HybridAixCellViewStateUpdater.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/views/HybridAixComposerManager.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/views/HybridAixComposerStateUpdater.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/views/HybridAixManager.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/views/HybridAixStateUpdater.kt +23 -0
- package/nitrogen/generated/ios/Aix+autolinking.rb +60 -0
- package/nitrogen/generated/ios/Aix-Swift-Cxx-Bridge.cpp +67 -0
- package/nitrogen/generated/ios/Aix-Swift-Cxx-Bridge.hpp +222 -0
- package/nitrogen/generated/ios/Aix-Swift-Cxx-Umbrella.hpp +70 -0
- package/nitrogen/generated/ios/AixAutolinking.mm +49 -0
- package/nitrogen/generated/ios/AixAutolinking.swift +55 -0
- package/nitrogen/generated/ios/c++/HybridAixCellViewSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridAixCellViewSpecSwift.hpp +80 -0
- package/nitrogen/generated/ios/c++/HybridAixComposerSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridAixComposerSpecSwift.hpp +69 -0
- package/nitrogen/generated/ios/c++/HybridAixSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridAixSpecSwift.hpp +142 -0
- package/nitrogen/generated/ios/c++/views/HybridAixCellViewComponent.mm +101 -0
- package/nitrogen/generated/ios/c++/views/HybridAixComponent.mm +126 -0
- package/nitrogen/generated/ios/c++/views/HybridAixComposerComponent.mm +92 -0
- package/nitrogen/generated/ios/swift/AixAdditionalContentInsets.swift +47 -0
- package/nitrogen/generated/ios/swift/AixAdditionalContentInsetsProp.swift +71 -0
- package/nitrogen/generated/ios/swift/AixScrollIndicatorInsetValue.swift +47 -0
- package/nitrogen/generated/ios/swift/AixScrollIndicatorInsets.swift +71 -0
- package/nitrogen/generated/ios/swift/AixScrollOnFooterSizeUpdate.swift +89 -0
- package/nitrogen/generated/ios/swift/HybridAixCellViewSpec.swift +57 -0
- package/nitrogen/generated/ios/swift/HybridAixCellViewSpec_cxx.swift +151 -0
- package/nitrogen/generated/ios/swift/HybridAixComposerSpec.swift +56 -0
- package/nitrogen/generated/ios/swift/HybridAixComposerSpec_cxx.swift +131 -0
- package/nitrogen/generated/ios/swift/HybridAixSpec.swift +63 -0
- package/nitrogen/generated/ios/swift/HybridAixSpec_cxx.swift +292 -0
- package/nitrogen/generated/shared/c++/AixAdditionalContentInsets.hpp +79 -0
- package/nitrogen/generated/shared/c++/AixAdditionalContentInsetsProp.hpp +81 -0
- package/nitrogen/generated/shared/c++/AixScrollIndicatorInsetValue.hpp +79 -0
- package/nitrogen/generated/shared/c++/AixScrollIndicatorInsets.hpp +81 -0
- package/nitrogen/generated/shared/c++/AixScrollOnFooterSizeUpdate.hpp +83 -0
- package/nitrogen/generated/shared/c++/HybridAixCellViewSpec.cpp +24 -0
- package/nitrogen/generated/shared/c++/HybridAixCellViewSpec.hpp +65 -0
- package/nitrogen/generated/shared/c++/HybridAixComposerSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridAixComposerSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridAixSpec.cpp +36 -0
- package/nitrogen/generated/shared/c++/HybridAixSpec.hpp +85 -0
- package/nitrogen/generated/shared/c++/views/HybridAixCellViewComponent.cpp +99 -0
- package/nitrogen/generated/shared/c++/views/HybridAixCellViewComponent.hpp +108 -0
- package/nitrogen/generated/shared/c++/views/HybridAixComponent.cpp +159 -0
- package/nitrogen/generated/shared/c++/views/HybridAixComponent.hpp +117 -0
- package/nitrogen/generated/shared/c++/views/HybridAixComposerComponent.cpp +75 -0
- package/nitrogen/generated/shared/c++/views/HybridAixComposerComponent.hpp +106 -0
- package/nitrogen/generated/shared/json/AixCellViewConfig.json +11 -0
- package/nitrogen/generated/shared/json/AixComposerConfig.json +9 -0
- package/nitrogen/generated/shared/json/AixConfig.json +16 -0
- package/package.json +115 -12
- package/src/aix.tsx +43 -0
- package/src/fade-in/createUsePool.ts +46 -0
- package/src/fade-in/createUseStaggered.ts +82 -0
- package/src/fade-in/index.tsx +97 -0
- package/src/footer.tsx +30 -0
- package/src/index.ts +20 -16
- package/src/views/aix.nitro.ts +148 -0
- package/docs/API.md +0 -193
- package/jest.config.js +0 -17
- package/lib/__tests__/deferredIterable.test.d.ts +0 -1
- package/lib/__tests__/deferredIterable.test.js +0 -111
- package/lib/__tests__/filter.test.d.ts +0 -1
- package/lib/__tests__/filter.test.js +0 -56
- package/lib/__tests__/flatMap.test.d.ts +0 -1
- package/lib/__tests__/flatMap.test.js +0 -80
- package/lib/__tests__/lookahead.test.d.ts +0 -1
- package/lib/__tests__/lookahead.test.js +0 -60
- package/lib/__tests__/map.test.d.ts +0 -1
- package/lib/__tests__/map.test.js +0 -56
- package/lib/__tests__/merge.test.d.ts +0 -1
- package/lib/__tests__/merge.test.js +0 -58
- package/lib/__tests__/reduce.test.d.ts +0 -1
- package/lib/__tests__/reduce.test.js +0 -55
- package/lib/__tests__/spanAll.test.d.ts +0 -1
- package/lib/__tests__/spanAll.test.js +0 -123
- package/lib/concat.d.ts +0 -5
- package/lib/concat.js +0 -127
- package/lib/deferred.d.ts +0 -10
- package/lib/deferred.js +0 -19
- package/lib/deferredIterable.d.ts +0 -23
- package/lib/deferredIterable.js +0 -112
- package/lib/filter.d.ts +0 -8
- package/lib/filter.js +0 -100
- package/lib/flatMap.d.ts +0 -2
- package/lib/flatMap.js +0 -120
- package/lib/fromEvent.d.ts +0 -6
- package/lib/fromEvent.js +0 -17
- package/lib/index.d.ts +0 -16
- package/lib/index.js +0 -34
- package/lib/insert.d.ts +0 -5
- package/lib/insert.js +0 -114
- package/lib/interval.d.ts +0 -5
- package/lib/interval.js +0 -68
- package/lib/iterableToArray.d.ts +0 -2
- package/lib/iterableToArray.js +0 -88
- package/lib/iteratorToIterable.d.ts +0 -7
- package/lib/iteratorToIterable.js +0 -71
- package/lib/lookahead.d.ts +0 -11
- package/lib/lookahead.js +0 -82
- package/lib/map.d.ts +0 -5
- package/lib/map.js +0 -99
- package/lib/merge.d.ts +0 -7
- package/lib/merge.js +0 -25
- package/lib/reduce.d.ts +0 -5
- package/lib/reduce.js +0 -93
- package/lib/restToIterable.d.ts +0 -5
- package/lib/restToIterable.js +0 -74
- package/lib/spanAll.d.ts +0 -2
- package/lib/spanAll.js +0 -34
- package/lib/tap.d.ts +0 -5
- package/lib/tap.js +0 -97
- package/lib/toCallbacks.d.ts +0 -12
- package/lib/toCallbacks.js +0 -98
- package/lib/zip.d.ts +0 -5
- package/lib/zip.js +0 -76
- package/src/__tests__/deferredIterable.test.ts +0 -22
- package/src/__tests__/filter.test.ts +0 -10
- package/src/__tests__/flatMap.test.ts +0 -12
- package/src/__tests__/lookahead.test.ts +0 -9
- package/src/__tests__/map.test.ts +0 -10
- package/src/__tests__/merge.test.ts +0 -9
- package/src/__tests__/reduce.test.ts +0 -10
- package/src/__tests__/spanAll.test.ts +0 -17
- package/src/concat.ts +0 -13
- package/src/deferred.ts +0 -15
- package/src/deferredIterable.ts +0 -111
- package/src/filter.ts +0 -16
- package/src/flatMap.ts +0 -9
- package/src/fromEvent.ts +0 -16
- package/src/insert.ts +0 -13
- package/src/interval.ts +0 -20
- package/src/iterableToArray.ts +0 -7
- package/src/iteratorToIterable.ts +0 -12
- package/src/lookahead.ts +0 -27
- package/src/map.ts +0 -11
- package/src/merge.ts +0 -16
- package/src/of.ts +0 -4
- package/src/reduce.ts +0 -12
- package/src/restToIterable.ts +0 -8
- package/src/spanAll.ts +0 -26
- package/src/tap.ts +0 -11
- package/src/toCallbacks.ts +0 -27
- package/src/zip.ts +0 -19
- package/tsconfig.json +0 -63
- 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)
|
|
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
|
-
#
|
|
1
|
+
# aix
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Primitives for building beautiful AI chat apps with React Native.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> aix is currently in alpha preview. The API will change, and it is not yet feature complete.
|
|
6
6
|
|
|
7
|
-
|
|
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
|
-
|
|
9
|
+
aix is a native module with UIKit with Nitro Modules.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
of utility methods similar to those found in lodash, underscore or Ramda.
|
|
11
|
+
## Installation
|
|
13
12
|
|
|
14
|
-
|
|
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
|
-
|
|
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
|
-
|
|
82
|
+
## TODOs
|
|
19
83
|
|
|
20
|
-
|
|
21
|
-
|
|
84
|
+
- [ ] Android support
|
|
85
|
+
- [ ] LegendList support
|
|
86
|
+
- [ ] FlashList support
|
|
22
87
|
|
|
23
|
-
|
|
88
|
+
## API Reference
|
|
24
89
|
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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
|
-
|
|
33
|
-
is essentially how ```fromEvents``` was implemented.
|
|
125
|
+
---
|
|
34
126
|
|
|
35
|
-
|
|
36
|
-
import { DeferredIterable } from "aix/deferredIterable";
|
|
127
|
+
### `AixCell`
|
|
37
128
|
|
|
38
|
-
|
|
129
|
+
A wrapper component for each message in the list. It communicates cell position and dimensions to the parent `Aix` component.
|
|
39
130
|
|
|
40
|
-
|
|
41
|
-
const callback = value => deferredIterable.value(value);
|
|
131
|
+
#### Props
|
|
42
132
|
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
47
|
-
deferredIterable.finally(() => document.removeEventListener('click', deferredIterable.value));
|
|
138
|
+
---
|
|
48
139
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
183
|
+
## TODOs
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
## Requirements
|
|
56
187
|
|
|
57
|
-
|
|
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,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
|
+
}
|