aix 0.1.0 → 0.3.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.
- package/README.md +32 -1
- package/ios/HybridAix.swift +96 -14
- package/ios/HybridAixComposer.swift +63 -24
- package/lib/commonjs/aix.js +16 -1
- package/lib/commonjs/aix.js.map +1 -1
- package/lib/commonjs/hooks/useContentInsetHandler.js +30 -0
- package/lib/commonjs/hooks/useContentInsetHandler.js.map +1 -0
- package/lib/commonjs/index.js +9 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/aix.js +16 -1
- package/lib/module/aix.js.map +1 -1
- package/lib/module/hooks/useContentInsetHandler.js +26 -0
- package/lib/module/hooks/useContentInsetHandler.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/aix.d.ts +239 -11
- package/lib/typescript/src/aix.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useContentInsetHandler.d.ts +21 -0
- package/lib/typescript/src/hooks/useContentInsetHandler.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/views/aix.nitro.d.ts +44 -0
- package/lib/typescript/src/views/aix.nitro.d.ts.map +1 -1
- package/nitrogen/generated/android/AixOnLoad.cpp +4 -0
- package/nitrogen/generated/android/c++/JAixContentInsets.hpp +69 -0
- package/nitrogen/generated/android/c++/JAixStickToKeyboard.hpp +63 -0
- package/nitrogen/generated/android/c++/JAixStickToKeyboardOffset.hpp +61 -0
- package/nitrogen/generated/android/c++/JFunc_void_AixContentInsets.hpp +78 -0
- package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +75 -0
- package/nitrogen/generated/android/c++/JHybridAixComposerSpec.cpp +18 -3
- package/nitrogen/generated/android/c++/JHybridAixComposerSpec.hpp +2 -1
- package/nitrogen/generated/android/c++/JHybridAixSpec.cpp +51 -0
- package/nitrogen/generated/android/c++/JHybridAixSpec.hpp +6 -0
- package/nitrogen/generated/android/c++/views/JHybridAixComposerStateUpdater.cpp +4 -1
- package/nitrogen/generated/android/c++/views/JHybridAixStateUpdater.cpp +12 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixContentInsets.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixStickToKeyboard.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/AixStickToKeyboardOffset.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/Func_void_AixContentInsets.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/Func_void_bool.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/HybridAixComposerSpec.kt +5 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/aix/HybridAixSpec.kt +34 -0
- package/nitrogen/generated/ios/Aix-Swift-Cxx-Bridge.cpp +16 -0
- package/nitrogen/generated/ios/Aix-Swift-Cxx-Bridge.hpp +114 -0
- package/nitrogen/generated/ios/Aix-Swift-Cxx-Umbrella.hpp +10 -0
- package/nitrogen/generated/ios/c++/HybridAixComposerSpecSwift.hpp +14 -3
- package/nitrogen/generated/ios/c++/HybridAixSpecSwift.hpp +25 -0
- package/nitrogen/generated/ios/c++/views/HybridAixComponent.mm +15 -0
- package/nitrogen/generated/ios/c++/views/HybridAixComposerComponent.mm +5 -1
- package/nitrogen/generated/ios/swift/AixContentInsets.swift +117 -0
- package/nitrogen/generated/ios/swift/AixStickToKeyboard.swift +59 -0
- package/nitrogen/generated/ios/swift/AixStickToKeyboardOffset.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_AixContentInsets.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridAixComposerSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridAixComposerSpec_cxx.swift +16 -1
- package/nitrogen/generated/ios/swift/HybridAixSpec.swift +3 -0
- package/nitrogen/generated/ios/swift/HybridAixSpec_cxx.swift +88 -0
- package/nitrogen/generated/shared/c++/AixContentInsets.hpp +87 -0
- package/nitrogen/generated/shared/c++/AixStickToKeyboard.hpp +81 -0
- package/nitrogen/generated/shared/c++/AixStickToKeyboardOffset.hpp +79 -0
- package/nitrogen/generated/shared/c++/HybridAixComposerSpec.cpp +2 -1
- package/nitrogen/generated/shared/c++/HybridAixComposerSpec.hpp +6 -3
- package/nitrogen/generated/shared/c++/HybridAixSpec.cpp +6 -0
- package/nitrogen/generated/shared/c++/HybridAixSpec.hpp +10 -0
- package/nitrogen/generated/shared/c++/views/HybridAixComponent.cpp +36 -0
- package/nitrogen/generated/shared/c++/views/HybridAixComponent.hpp +5 -1
- package/nitrogen/generated/shared/c++/views/HybridAixComposerComponent.cpp +12 -0
- package/nitrogen/generated/shared/c++/views/HybridAixComposerComponent.hpp +3 -1
- package/nitrogen/generated/shared/json/AixComposerConfig.json +1 -0
- package/nitrogen/generated/shared/json/AixConfig.json +3 -0
- package/package.json +9 -7
- package/src/aix.tsx +33 -11
- package/src/hooks/useContentInsetHandler.ts +28 -0
- package/src/index.ts +2 -0
- package/src/views/aix.nitro.ts +28 -1
package/README.md
CHANGED
|
@@ -97,7 +97,8 @@ The main container component that provides keyboard-aware behavior and manages s
|
|
|
97
97
|
|------|------|---------|-------------|
|
|
98
98
|
| `shouldStartAtEnd` | `boolean` | - | Whether the scroll view should start scrolled to the end of the content. |
|
|
99
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. |
|
|
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 by `onScrolledNearEndChange` and to determine if content should shift up when keyboard opens. |
|
|
101
|
+
| `onScrolledNearEndChange` | `(isNearEnd: boolean) => void` | - | Callback fired when the scroll position transitions between "near end" and "not near end" states. Reactive to user scrolling, content size changes, parent size changes, and keyboard height changes. Uses `scrollEndReachedThreshold` to determine the threshold. |
|
|
101
102
|
| `additionalContentInsets` | `object` | - | Additional content insets applied when keyboard is open or closed. Shape: `{ top?: { whenKeyboardOpen, whenKeyboardClosed }, bottom?: { whenKeyboardOpen, whenKeyboardClosed } }` |
|
|
102
103
|
| `additionalScrollIndicatorInsets` | `object` | - | Additional insets for the scroll indicator, added to existing safe area insets. Applied to `verticalScrollIndicatorInsets` on iOS. |
|
|
103
104
|
| `mainScrollViewID` | `string` | - | The `nativeID` of the scroll view to use. If provided, will search for a scroll view with this `accessibilityIdentifier`. |
|
|
@@ -180,6 +181,36 @@ function Chat({ messages }) {
|
|
|
180
181
|
}
|
|
181
182
|
```
|
|
182
183
|
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
### Scroll to End Button
|
|
187
|
+
|
|
188
|
+
You can use `onScrolledNearEndChange` to show a "scroll to end" button when the user scrolls away from the bottom:
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
import { Aix, useAixRef } from 'aix';
|
|
192
|
+
import { useState } from 'react';
|
|
193
|
+
|
|
194
|
+
function Chat() {
|
|
195
|
+
const aix = useAixRef();
|
|
196
|
+
const [isNearEnd, setIsNearEnd] = useState(false);
|
|
197
|
+
|
|
198
|
+
return (
|
|
199
|
+
<Aix
|
|
200
|
+
ref={aix}
|
|
201
|
+
scrollEndReachedThreshold={200}
|
|
202
|
+
onScrolledNearEndChange={setIsNearEnd}
|
|
203
|
+
>
|
|
204
|
+
{/* ScrollView and messages... */}
|
|
205
|
+
|
|
206
|
+
{!isNearEnd && (
|
|
207
|
+
<Button onPress={() => aix.current?.scrollToEnd(true)} />
|
|
208
|
+
)}
|
|
209
|
+
</Aix>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
183
214
|
## TODOs
|
|
184
215
|
|
|
185
216
|
|
package/ios/HybridAix.swift
CHANGED
|
@@ -15,33 +15,35 @@ private var aixContextKey: UInt8 = 0
|
|
|
15
15
|
protocol AixContext: AnyObject {
|
|
16
16
|
/// The blank view (last cell) - used for calculating blank size
|
|
17
17
|
var blankView: HybridAixCellView? { get set }
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
/// The composer view
|
|
20
20
|
var composerView: HybridAixComposer? { get set }
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
/// Called when the blank view's size changes
|
|
23
23
|
func reportBlankViewSizeChange(size: CGSize, index: Int)
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
/// Register a cell with the context
|
|
26
26
|
func registerCell(_ cell: HybridAixCellView)
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
/// Unregister a cell from the context
|
|
29
29
|
func unregisterCell(_ cell: HybridAixCellView)
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
/// Register the composer view
|
|
32
32
|
func registerComposerView(_ composerView: HybridAixComposer)
|
|
33
|
-
<<<<<<< HEAD
|
|
34
33
|
|
|
35
34
|
/// Unregister the composer view
|
|
36
35
|
func unregisterComposerView(_ composerView: HybridAixComposer)
|
|
37
36
|
|
|
38
37
|
/// Called when the composer's height changes
|
|
39
38
|
func reportComposerHeightChange(height: CGFloat)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
|
|
40
|
+
// MARK: - Keyboard State (for composer sticky behavior)
|
|
41
|
+
|
|
42
|
+
/// Current keyboard height
|
|
43
|
+
var keyboardHeight: CGFloat { get }
|
|
44
|
+
|
|
45
|
+
/// Keyboard height when fully open (for calculating progress)
|
|
46
|
+
var keyboardHeightWhenOpen: CGFloat { get }
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
extension UIView {
|
|
@@ -96,6 +98,10 @@ extension UIView {
|
|
|
96
98
|
class HybridAix: HybridAixSpec, AixContext, KeyboardNotificationsDelegate {
|
|
97
99
|
|
|
98
100
|
var penultimateCellIndex: Double?
|
|
101
|
+
|
|
102
|
+
var shouldApplyContentInsets: Bool? = nil
|
|
103
|
+
var onWillApplyContentInsets: ((_ insets: AixContentInsets) -> Void)? = nil
|
|
104
|
+
var onScrolledNearEndChange: ((_ isNearEnd: Bool) -> Void)? = nil
|
|
99
105
|
|
|
100
106
|
var additionalContentInsets: AixAdditionalContentInsetsProp?
|
|
101
107
|
|
|
@@ -202,6 +208,14 @@ class HybridAix: HybridAixSpec, AixContext, KeyboardNotificationsDelegate {
|
|
|
202
208
|
/// Flag to track if we're currently in an interactive keyboard dismiss
|
|
203
209
|
private var isInInteractiveDismiss = false
|
|
204
210
|
|
|
211
|
+
/// Previous "scrolled near end" state for change detection
|
|
212
|
+
private var prevIsScrolledNearEnd: Bool? = nil
|
|
213
|
+
|
|
214
|
+
/// KVO observation tokens for scroll view
|
|
215
|
+
private var contentOffsetObservation: NSKeyValueObservation?
|
|
216
|
+
private var contentSizeObservation: NSKeyValueObservation?
|
|
217
|
+
private var boundsObservation: NSKeyValueObservation?
|
|
218
|
+
|
|
205
219
|
// MARK: - Context References (weak to avoid retain cycles)
|
|
206
220
|
|
|
207
221
|
weak var blankView: HybridAixCellView? = nil {
|
|
@@ -247,12 +261,41 @@ class HybridAix: HybridAixSpec, AixContext, KeyboardNotificationsDelegate {
|
|
|
247
261
|
scrollView.automaticallyAdjustsScrollIndicatorInsets = false
|
|
248
262
|
|
|
249
263
|
setupPanGestureObserver()
|
|
264
|
+
setupScrollViewObservers(scrollView)
|
|
250
265
|
applyScrollIndicatorInsets()
|
|
251
266
|
}
|
|
252
267
|
|
|
253
268
|
return sv
|
|
254
269
|
}
|
|
255
270
|
|
|
271
|
+
/// Set up KVO observers on scroll view for contentOffset, contentSize, and bounds changes
|
|
272
|
+
private func setupScrollViewObservers(_ scrollView: UIScrollView) {
|
|
273
|
+
// Observe contentOffset (user scrolling)
|
|
274
|
+
contentOffsetObservation = scrollView.observe(\.contentOffset, options: [.new]) { [weak self] _, _ in
|
|
275
|
+
self?.updateScrolledNearEndState()
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Observe contentSize (content size changes)
|
|
279
|
+
contentSizeObservation = scrollView.observe(\.contentSize, options: [.new]) { [weak self] _, _ in
|
|
280
|
+
self?.updateScrolledNearEndState()
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Observe bounds (parent size changes)
|
|
284
|
+
boundsObservation = scrollView.observe(\.bounds, options: [.new]) { [weak self] _, _ in
|
|
285
|
+
self?.updateScrolledNearEndState()
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/// Clean up KVO observers
|
|
290
|
+
private func removeScrollViewObservers() {
|
|
291
|
+
contentOffsetObservation?.invalidate()
|
|
292
|
+
contentOffsetObservation = nil
|
|
293
|
+
contentSizeObservation?.invalidate()
|
|
294
|
+
contentSizeObservation = nil
|
|
295
|
+
boundsObservation?.invalidate()
|
|
296
|
+
boundsObservation = nil
|
|
297
|
+
}
|
|
298
|
+
|
|
256
299
|
/// Set up observer on scroll view's pan gesture to detect interactive keyboard dismiss
|
|
257
300
|
private func setupPanGestureObserver() {
|
|
258
301
|
guard let scrollView = cachedScrollView else { return }
|
|
@@ -394,14 +437,44 @@ class HybridAix: HybridAixSpec, AixContext, KeyboardNotificationsDelegate {
|
|
|
394
437
|
guard let scrollView else { return }
|
|
395
438
|
|
|
396
439
|
let targetTop = additionalContentInsetTop
|
|
440
|
+
let targetBottom = overrideContentInsetBottom ?? self.contentInsetBottom
|
|
441
|
+
|
|
442
|
+
// Create insets struct for callback (fields are optional in the interface)
|
|
443
|
+
let insets = AixContentInsets(
|
|
444
|
+
top: Double(targetTop),
|
|
445
|
+
left: nil,
|
|
446
|
+
bottom: Double(targetBottom),
|
|
447
|
+
right: nil
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
print("[aix] applyContentInset \(targetBottom)")
|
|
451
|
+
|
|
452
|
+
// If shouldApplyContentInsets is explicitly false, call callback and return
|
|
453
|
+
if shouldApplyContentInsets == false {
|
|
454
|
+
onWillApplyContentInsets?(insets)
|
|
455
|
+
return
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Default behavior: apply insets directly
|
|
397
459
|
if scrollView.contentInset.top != targetTop {
|
|
398
460
|
scrollView.contentInset.top = targetTop
|
|
399
461
|
}
|
|
400
|
-
|
|
401
|
-
let targetBottom = overrideContentInsetBottom ?? self.contentInsetBottom
|
|
402
462
|
if scrollView.contentInset.bottom != targetBottom {
|
|
403
463
|
scrollView.contentInset.bottom = targetBottom
|
|
404
464
|
}
|
|
465
|
+
|
|
466
|
+
// Update scrolled near end state after insets change
|
|
467
|
+
updateScrolledNearEndState()
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/// Centralized function to check and fire onScrolledNearEndChange callback
|
|
471
|
+
/// Called from KVO observers and after content inset changes
|
|
472
|
+
private func updateScrolledNearEndState() {
|
|
473
|
+
guard scrollView != nil else { return }
|
|
474
|
+
let isNearEnd = getIsScrolledNearEnd(distFromEnd: distFromEnd)
|
|
475
|
+
guard isNearEnd != prevIsScrolledNearEnd else { return }
|
|
476
|
+
prevIsScrolledNearEnd = isNearEnd
|
|
477
|
+
onScrolledNearEndChange?(isNearEnd)
|
|
405
478
|
}
|
|
406
479
|
|
|
407
480
|
/// Apply scroll indicator insets to the scroll view
|
|
@@ -554,9 +627,12 @@ class HybridAix: HybridAixSpec, AixContext, KeyboardNotificationsDelegate {
|
|
|
554
627
|
startEvent = event
|
|
555
628
|
}
|
|
556
629
|
}
|
|
557
|
-
|
|
630
|
+
|
|
558
631
|
// Update keyboard state
|
|
559
632
|
handleKeyboardMove(height: height, progress: progress)
|
|
633
|
+
|
|
634
|
+
// Update composer transform
|
|
635
|
+
composerView?.applyKeyboardTransform(height: height, heightWhenOpen: keyboardHeightWhenOpen, animated: false)
|
|
560
636
|
}
|
|
561
637
|
|
|
562
638
|
// MARK: - Initialization
|
|
@@ -573,6 +649,7 @@ class HybridAix: HybridAixSpec, AixContext, KeyboardNotificationsDelegate {
|
|
|
573
649
|
|
|
574
650
|
deinit {
|
|
575
651
|
removePanGestureObserver()
|
|
652
|
+
removeScrollViewObservers()
|
|
576
653
|
}
|
|
577
654
|
|
|
578
655
|
// MARK: - Lifecycle
|
|
@@ -643,6 +720,7 @@ class HybridAix: HybridAixSpec, AixContext, KeyboardNotificationsDelegate {
|
|
|
643
720
|
applyContentInset()
|
|
644
721
|
applyScrollIndicatorInsets()
|
|
645
722
|
scrollToEndInternal(animated: false)
|
|
723
|
+
updateScrolledNearEndState()
|
|
646
724
|
}
|
|
647
725
|
didScrollToEndInitially = true
|
|
648
726
|
} else {
|
|
@@ -798,6 +876,7 @@ class HybridAix: HybridAixSpec, AixContext, KeyboardNotificationsDelegate {
|
|
|
798
876
|
keyboardProgress = 1.0
|
|
799
877
|
applyContentInset()
|
|
800
878
|
applyScrollIndicatorInsets()
|
|
879
|
+
composerView?.applyKeyboardTransform(height: targetHeight, heightWhenOpen: keyboardHeightWhenOpen, animated: false)
|
|
801
880
|
return
|
|
802
881
|
}
|
|
803
882
|
|
|
@@ -812,6 +891,7 @@ class HybridAix: HybridAixSpec, AixContext, KeyboardNotificationsDelegate {
|
|
|
812
891
|
}
|
|
813
892
|
self.applyContentInset()
|
|
814
893
|
self.applyScrollIndicatorInsets()
|
|
894
|
+
self.composerView?.applyKeyboardTransform(height: targetHeight, heightWhenOpen: self.keyboardHeightWhenOpen, animated: false)
|
|
815
895
|
|
|
816
896
|
if let (startY, endY) = self.startEvent?.interpolateContentOffsetY {
|
|
817
897
|
self.scrollView?.setContentOffset(CGPoint(x: 0, y: endY), animated: false)
|
|
@@ -839,6 +919,7 @@ class HybridAix: HybridAixSpec, AixContext, KeyboardNotificationsDelegate {
|
|
|
839
919
|
self.keyboardProgress = 0
|
|
840
920
|
self.applyContentInset()
|
|
841
921
|
self.applyScrollIndicatorInsets()
|
|
922
|
+
self.composerView?.applyKeyboardTransform(height: 0, heightWhenOpen: self.keyboardHeightWhenOpen, animated: false)
|
|
842
923
|
}, completion: { [weak self] _ in
|
|
843
924
|
self?.handleKeyboardDidMove(height: 0, progress: 0)
|
|
844
925
|
})
|
|
@@ -851,6 +932,7 @@ class HybridAix: HybridAixSpec, AixContext, KeyboardNotificationsDelegate {
|
|
|
851
932
|
func keyboardDidHide(notification: NSNotification) {
|
|
852
933
|
print("[Aix] keyboardDidHide")
|
|
853
934
|
keyboardHeightWhenOpen = 0
|
|
935
|
+
composerView?.applyKeyboardTransform(height: 0, heightWhenOpen: 0, animated: false)
|
|
854
936
|
}
|
|
855
937
|
|
|
856
938
|
func keyboardWillChangeFrame(notification: NSNotification) {
|
|
@@ -12,23 +12,34 @@ import UIKit
|
|
|
12
12
|
/// It registers itself with the AixContext so the context can track composer height
|
|
13
13
|
/// for calculating content insets
|
|
14
14
|
class HybridAixComposer: HybridAixComposerSpec {
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
// MARK: - Props
|
|
17
|
+
|
|
18
|
+
var stickToKeyboard: AixStickToKeyboard? {
|
|
19
|
+
didSet {
|
|
20
|
+
// When stickToKeyboard changes, re-apply transform with current keyboard state
|
|
21
|
+
if let ctx = cachedAixContext {
|
|
22
|
+
applyKeyboardTransform(height: ctx.keyboardHeight, heightWhenOpen: ctx.keyboardHeightWhenOpen, animated: false)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
16
27
|
// MARK: - Inner View
|
|
17
|
-
|
|
28
|
+
|
|
18
29
|
/// Custom UIView that notifies owner when layout changes
|
|
19
30
|
private final class InnerView: UIView {
|
|
20
31
|
weak var owner: HybridAixComposer?
|
|
21
|
-
|
|
32
|
+
|
|
22
33
|
override func layoutSubviews() {
|
|
23
34
|
super.layoutSubviews()
|
|
24
35
|
owner?.handleLayoutChange()
|
|
25
36
|
}
|
|
26
|
-
|
|
37
|
+
|
|
27
38
|
override func didMoveToWindow() {
|
|
28
39
|
super.didMoveToWindow()
|
|
29
40
|
owner?.handleDidMoveToWindow()
|
|
30
41
|
}
|
|
31
|
-
|
|
42
|
+
|
|
32
43
|
override func willMove(toSuperview newSuperview: UIView?) {
|
|
33
44
|
super.willMove(toSuperview: newSuperview)
|
|
34
45
|
if newSuperview == nil {
|
|
@@ -36,37 +47,37 @@ class HybridAixComposer: HybridAixComposerSpec {
|
|
|
36
47
|
owner?.handleWillRemoveFromSuperview()
|
|
37
48
|
}
|
|
38
49
|
}
|
|
39
|
-
|
|
50
|
+
|
|
40
51
|
// MARK: - Touch Handling
|
|
41
|
-
|
|
52
|
+
|
|
42
53
|
/// Let touches pass through to React Native children
|
|
43
54
|
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
|
44
55
|
return false
|
|
45
56
|
}
|
|
46
57
|
}
|
|
47
|
-
|
|
58
|
+
|
|
48
59
|
// MARK: - Properties
|
|
49
|
-
|
|
60
|
+
|
|
50
61
|
/// The UIView for this composer
|
|
51
62
|
let view: UIView
|
|
52
|
-
|
|
63
|
+
|
|
53
64
|
/// Cached reference to the AixContext (found on first access)
|
|
54
65
|
private weak var cachedAixContext: AixContext?
|
|
55
66
|
|
|
56
67
|
/// Last reported height (to avoid reporting unchanged heights)
|
|
57
68
|
private var lastReportedHeight: CGFloat = 0
|
|
58
|
-
|
|
69
|
+
|
|
59
70
|
// MARK: - Initialization
|
|
60
|
-
|
|
71
|
+
|
|
61
72
|
override init() {
|
|
62
73
|
let inner = InnerView()
|
|
63
74
|
self.view = inner
|
|
64
75
|
super.init()
|
|
65
76
|
inner.owner = self
|
|
66
77
|
}
|
|
67
|
-
|
|
78
|
+
|
|
68
79
|
// MARK: - Context Access
|
|
69
|
-
|
|
80
|
+
|
|
70
81
|
/// Get the AixContext, caching it for performance
|
|
71
82
|
private func getAixContext() -> AixContext? {
|
|
72
83
|
if let cached = cachedAixContext {
|
|
@@ -76,22 +87,26 @@ class HybridAixComposer: HybridAixComposerSpec {
|
|
|
76
87
|
cachedAixContext = ctx
|
|
77
88
|
return ctx
|
|
78
89
|
}
|
|
79
|
-
|
|
90
|
+
|
|
80
91
|
// MARK: - Lifecycle Handlers
|
|
81
|
-
|
|
92
|
+
|
|
82
93
|
/// Called when the view is added to a window (full hierarchy is connected)
|
|
83
94
|
private func handleDidMoveToWindow() {
|
|
84
|
-
guard view.window != nil else {
|
|
85
|
-
|
|
95
|
+
guard view.window != nil else {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
86
99
|
// Clear cached context since hierarchy changed
|
|
87
100
|
cachedAixContext = nil
|
|
88
|
-
|
|
101
|
+
|
|
89
102
|
// Register with the new context
|
|
90
103
|
if let ctx = getAixContext() {
|
|
91
104
|
ctx.registerComposerView(self)
|
|
105
|
+
// Initial state
|
|
106
|
+
applyKeyboardTransform(height: ctx.keyboardHeight, heightWhenOpen: ctx.keyboardHeightWhenOpen, animated: false)
|
|
92
107
|
}
|
|
93
108
|
}
|
|
94
|
-
|
|
109
|
+
|
|
95
110
|
/// Called when the view is about to be removed from superview
|
|
96
111
|
private func handleWillRemoveFromSuperview() {
|
|
97
112
|
// Unregister from context before removal
|
|
@@ -100,7 +115,7 @@ class HybridAixComposer: HybridAixComposerSpec {
|
|
|
100
115
|
}
|
|
101
116
|
cachedAixContext = nil
|
|
102
117
|
}
|
|
103
|
-
|
|
118
|
+
|
|
104
119
|
/// Called when layoutSubviews fires (size may have changed)
|
|
105
120
|
private func handleLayoutChange() {
|
|
106
121
|
let currentHeight = view.bounds.height
|
|
@@ -109,11 +124,35 @@ class HybridAixComposer: HybridAixComposerSpec {
|
|
|
109
124
|
getAixContext()?.reportComposerHeightChange(height: currentHeight)
|
|
110
125
|
}
|
|
111
126
|
}
|
|
112
|
-
|
|
127
|
+
|
|
128
|
+
// MARK: - Keyboard handling
|
|
129
|
+
|
|
130
|
+
/// Apply keyboard transform to move the composer with the keyboard
|
|
131
|
+
/// Called by the AixContext when keyboard state changes
|
|
132
|
+
func applyKeyboardTransform(height: CGFloat, heightWhenOpen: CGFloat, animated: Bool) {
|
|
133
|
+
guard let targetView = view.superview else {
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
guard let settings = stickToKeyboard, settings.enabled else {
|
|
138
|
+
targetView.transform = .identity
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let progress = heightWhenOpen > 0 ? height / heightWhenOpen : 0
|
|
143
|
+
|
|
144
|
+
let offsetWhenClosed = CGFloat(settings.offset?.whenKeyboardClosed ?? 0)
|
|
145
|
+
let offsetWhenOpen = CGFloat(settings.offset?.whenKeyboardOpen ?? 0)
|
|
146
|
+
|
|
147
|
+
let currentOffset = offsetWhenClosed + (offsetWhenOpen - offsetWhenClosed) * progress
|
|
148
|
+
|
|
149
|
+
let translateY = -height - currentOffset
|
|
150
|
+
|
|
151
|
+
targetView.transform = CGAffineTransform(translationX: 0, y: translateY)
|
|
152
|
+
}
|
|
153
|
+
|
|
113
154
|
// MARK: - Deinitialization
|
|
114
|
-
|
|
115
155
|
deinit {
|
|
116
|
-
// Ensure we unregister when deallocated
|
|
117
156
|
cachedAixContext?.unregisterComposerView(self)
|
|
118
157
|
}
|
|
119
158
|
}
|
package/lib/commonjs/aix.js
CHANGED
|
@@ -7,12 +7,27 @@ exports.Aix = void 0;
|
|
|
7
7
|
var _reactNativeNitroModules = require("react-native-nitro-modules");
|
|
8
8
|
var _AixConfig = _interopRequireDefault(require("../nitrogen/generated/shared/json/AixConfig.json"));
|
|
9
9
|
var _react = require("react");
|
|
10
|
+
var _reactNativeReanimated = _interopRequireDefault(require("react-native-reanimated"));
|
|
10
11
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
12
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
-
const AixInternal = (0, _reactNativeNitroModules.getHostComponent)('Aix', () => _AixConfig.default);
|
|
13
|
+
const AixInternal = _reactNativeReanimated.default.createAnimatedComponent((0, _reactNativeNitroModules.getHostComponent)('Aix', () => _AixConfig.default));
|
|
14
|
+
|
|
15
|
+
// User-facing props type that accepts regular functions (not wrapped callbacks)
|
|
16
|
+
|
|
13
17
|
const Aix = exports.Aix = /*#__PURE__*/(0, _react.forwardRef)(function Aix(props, ref) {
|
|
14
18
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(AixInternal, {
|
|
15
19
|
...props,
|
|
20
|
+
scrollOnFooterSizeUpdate: props.scrollOnFooterSizeUpdate ?? {
|
|
21
|
+
enabled: true,
|
|
22
|
+
scrolledToEndThreshold: 100,
|
|
23
|
+
animated: false
|
|
24
|
+
}
|
|
25
|
+
// Wrap onWillApplyContentInsets with callback() if provided
|
|
26
|
+
,
|
|
27
|
+
onWillApplyContentInsets: props.onWillApplyContentInsets ? (0, _reactNativeNitroModules.callback)(props.onWillApplyContentInsets) : undefined
|
|
28
|
+
// Wrap onScrolledNearEndChange with callback() if provided
|
|
29
|
+
,
|
|
30
|
+
onScrolledNearEndChange: props.onScrolledNearEndChange ? (0, _reactNativeNitroModules.callback)(props.onScrolledNearEndChange) : undefined,
|
|
16
31
|
hybridRef: ref ? (0, _reactNativeNitroModules.callback)(r => {
|
|
17
32
|
if (typeof ref === 'function') {
|
|
18
33
|
ref(r);
|
package/lib/commonjs/aix.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNativeNitroModules","require","_AixConfig","_interopRequireDefault","_react","_jsxRuntime","e","__esModule","default","AixInternal","getHostComponent","AixConfig","Aix","exports","forwardRef","props","ref","jsx","
|
|
1
|
+
{"version":3,"names":["_reactNativeNitroModules","require","_AixConfig","_interopRequireDefault","_react","_reactNativeReanimated","_jsxRuntime","e","__esModule","default","AixInternal","Animated","createAnimatedComponent","getHostComponent","AixConfig","Aix","exports","forwardRef","props","ref","jsx","scrollOnFooterSizeUpdate","enabled","scrolledToEndThreshold","animated","onWillApplyContentInsets","callback","undefined","onScrolledNearEndChange","hybridRef","r","current"],"sourceRoot":"../../src","sources":["aix.tsx"],"mappings":";;;;;;AAAA,IAAAA,wBAAA,GAAAC,OAAA;AAKA,IAAAC,UAAA,GAAAC,sBAAA,CAAAF,OAAA;AAEA,IAAAG,MAAA,GAAAH,OAAA;AACA,IAAAI,sBAAA,GAAAF,sBAAA,CAAAF,OAAA;AAA8C,IAAAK,WAAA,GAAAL,OAAA;AAAA,SAAAE,uBAAAI,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAI9C,MAAMG,WAAW,GAAGC,8BAAQ,CAACC,uBAAuB,CAAC,IAAAC,yCAAgB,EACnE,KAAK,EACL,MAAMC,kBACR,CAAC,CAAC;;AAEF;;AASO,MAAMC,GAAG,GAAAC,OAAA,CAAAD,GAAA,gBAAG,IAAAE,iBAAU,EAC3B,SAASF,GAAGA,CAACG,KAAK,EAAEC,GAAG,EAAE;EACvB,oBACE,IAAAb,WAAA,CAAAc,GAAA,EAACV,WAAW;IAAA,GACNQ,KAAK;IACTG,wBAAwB,EACtBH,KAAK,CAACG,wBAAwB,IAAI;MAChCC,OAAO,EAAE,IAAI;MACbC,sBAAsB,EAAE,GAAG;MAC3BC,QAAQ,EAAE;IACZ;IAEF;IAAA;IACAC,wBAAwB,EACtBP,KAAK,CAACO,wBAAwB,GAC1B,IAAAC,iCAAQ,EAACR,KAAK,CAACO,wBAAwB,CAAC,GACxCE;IAEN;IAAA;IACAC,uBAAuB,EACrBV,KAAK,CAACU,uBAAuB,GACzB,IAAAF,iCAAQ,EAACR,KAAK,CAACU,uBAAuB,CAAC,GACvCD,SACL;IACDE,SAAS,EACPV,GAAG,GACC,IAAAO,iCAAQ,EAAEI,CAAC,IAAK;MAChB,IAAI,OAAOX,GAAG,KAAK,UAAU,EAAE;QAC7BA,GAAG,CAACW,CAAC,CAAC;MACR,CAAC,MAAM;QACLX,GAAG,CAACY,OAAO,GAAGD,CAAC;MACjB;IACF,CAAC,CAAC,GACAH;EACL,CACF,CAAC;AAEN,CACF,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useContentInsetHandler = useContentInsetHandler;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
/**
|
|
9
|
+
* Hook that creates a stable callback handler for content inset updates.
|
|
10
|
+
* Use this with `onWillApplyContentInsets` prop to receive inset updates.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* const bottomInset = useSharedValue<number | null>(null)
|
|
15
|
+
*
|
|
16
|
+
* const contentInsetHandler = useContentInsetHandler((insets) => {
|
|
17
|
+
* bottomInset.value = insets.bottom ?? null
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* <Aix
|
|
21
|
+
* shouldApplyContentInsets={false}
|
|
22
|
+
* onWillApplyContentInsets={contentInsetHandler}
|
|
23
|
+
* />
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
function useContentInsetHandler(handler, dependencies = []) {
|
|
27
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
28
|
+
return (0, _react.useCallback)(handler, dependencies);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=useContentInsetHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","require","useContentInsetHandler","handler","dependencies","useCallback"],"sourceRoot":"../../../src","sources":["hooks/useContentInsetHandler.ts"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,sBAAsBA,CACpCC,OAA2C,EAC3CC,YAAuB,GAAG,EAAE,EAC5B;EACA;EACA,OAAO,IAAAC,kBAAW,EAACF,OAAO,EAAEC,YAAY,CAAC;AAC3C","ignoreList":[]}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -7,7 +7,8 @@ var _exportNames = {
|
|
|
7
7
|
AixCell: true,
|
|
8
8
|
useAixRef: true,
|
|
9
9
|
Aix: true,
|
|
10
|
-
AixFooter: true
|
|
10
|
+
AixFooter: true,
|
|
11
|
+
useContentInsetHandler: true
|
|
11
12
|
};
|
|
12
13
|
Object.defineProperty(exports, "Aix", {
|
|
13
14
|
enumerable: true,
|
|
@@ -23,6 +24,12 @@ Object.defineProperty(exports, "AixFooter", {
|
|
|
23
24
|
}
|
|
24
25
|
});
|
|
25
26
|
exports.useAixRef = useAixRef;
|
|
27
|
+
Object.defineProperty(exports, "useContentInsetHandler", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function () {
|
|
30
|
+
return _useContentInsetHandler.useContentInsetHandler;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
26
33
|
var _reactNativeNitroModules = require("react-native-nitro-modules");
|
|
27
34
|
var _AixCellViewConfig = _interopRequireDefault(require("../nitrogen/generated/shared/json/AixCellViewConfig.json"));
|
|
28
35
|
var _react = require("react");
|
|
@@ -40,6 +47,7 @@ Object.keys(_fadeIn).forEach(function (key) {
|
|
|
40
47
|
});
|
|
41
48
|
var _aix = require("./aix");
|
|
42
49
|
var _footer = require("./footer");
|
|
50
|
+
var _useContentInsetHandler = require("./hooks/useContentInsetHandler");
|
|
43
51
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
44
52
|
const AixCell = exports.AixCell = (0, _reactNativeNitroModules.getHostComponent)('AixCellView', () => _AixCellViewConfig.default);
|
|
45
53
|
function useAixRef() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNativeNitroModules","require","_AixCellViewConfig","_interopRequireDefault","_react","_fadeIn","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_aix","_footer","e","__esModule","default","AixCell","getHostComponent","AixCellViewConfig","useAixRef","useRef"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"names":["_reactNativeNitroModules","require","_AixCellViewConfig","_interopRequireDefault","_react","_fadeIn","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_aix","_footer","_useContentInsetHandler","e","__esModule","default","AixCell","getHostComponent","AixCellViewConfig","useAixRef","useRef"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,wBAAA,GAAAC,OAAA;AACA,IAAAC,kBAAA,GAAAC,sBAAA,CAAAF,OAAA;AAEA,IAAAG,MAAA,GAAAH,OAAA;AAEA,IAAAI,OAAA,GAAAJ,OAAA;AAAAK,MAAA,CAAAC,IAAA,CAAAF,OAAA,EAAAG,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAJ,OAAA,CAAAI,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAZ,OAAA,CAAAI,GAAA;IAAA;EAAA;AAAA;AAEA,IAAAS,IAAA,GAAAjB,OAAA;AACA,IAAAkB,OAAA,GAAAlB,OAAA;AACA,IAAAmB,uBAAA,GAAAnB,OAAA;AAAuE,SAAAE,uBAAAkB,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAGhE,MAAMG,OAAO,GAAAV,OAAA,CAAAU,OAAA,GAAG,IAAAC,yCAAgB,EACrC,aAAa,EACb,MAAMC,0BACR,CAAC;AAIM,SAASC,SAASA,CAAA,EAAG;EAC1B,OAAO,IAAAC,aAAM,EAAgB,IAAI,CAAC;AACpC","ignoreList":[]}
|
package/lib/module/aix.js
CHANGED
|
@@ -3,11 +3,26 @@
|
|
|
3
3
|
import { callback, getHostComponent } from 'react-native-nitro-modules';
|
|
4
4
|
import AixConfig from '../nitrogen/generated/shared/json/AixConfig.json';
|
|
5
5
|
import { forwardRef } from 'react';
|
|
6
|
+
import Animated from 'react-native-reanimated';
|
|
6
7
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
-
const AixInternal = getHostComponent('Aix', () => AixConfig);
|
|
8
|
+
const AixInternal = Animated.createAnimatedComponent(getHostComponent('Aix', () => AixConfig));
|
|
9
|
+
|
|
10
|
+
// User-facing props type that accepts regular functions (not wrapped callbacks)
|
|
11
|
+
|
|
8
12
|
export const Aix = /*#__PURE__*/forwardRef(function Aix(props, ref) {
|
|
9
13
|
return /*#__PURE__*/_jsx(AixInternal, {
|
|
10
14
|
...props,
|
|
15
|
+
scrollOnFooterSizeUpdate: props.scrollOnFooterSizeUpdate ?? {
|
|
16
|
+
enabled: true,
|
|
17
|
+
scrolledToEndThreshold: 100,
|
|
18
|
+
animated: false
|
|
19
|
+
}
|
|
20
|
+
// Wrap onWillApplyContentInsets with callback() if provided
|
|
21
|
+
,
|
|
22
|
+
onWillApplyContentInsets: props.onWillApplyContentInsets ? callback(props.onWillApplyContentInsets) : undefined
|
|
23
|
+
// Wrap onScrolledNearEndChange with callback() if provided
|
|
24
|
+
,
|
|
25
|
+
onScrolledNearEndChange: props.onScrolledNearEndChange ? callback(props.onScrolledNearEndChange) : undefined,
|
|
11
26
|
hybridRef: ref ? callback(r => {
|
|
12
27
|
if (typeof ref === 'function') {
|
|
13
28
|
ref(r);
|
package/lib/module/aix.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["callback","getHostComponent","AixConfig","forwardRef","jsx","_jsx","AixInternal","Aix","props","ref","
|
|
1
|
+
{"version":3,"names":["callback","getHostComponent","AixConfig","forwardRef","Animated","jsx","_jsx","AixInternal","createAnimatedComponent","Aix","props","ref","scrollOnFooterSizeUpdate","enabled","scrolledToEndThreshold","animated","onWillApplyContentInsets","undefined","onScrolledNearEndChange","hybridRef","r","current"],"sourceRoot":"../../src","sources":["aix.tsx"],"mappings":";;AAAA,SACEA,QAAQ,EACRC,gBAAgB,QAEX,4BAA4B;AACnC,OAAOC,SAAS,MAAM,kDAAkD;AAExE,SAASC,UAAU,QAA6B,OAAO;AACvD,OAAOC,QAAQ,MAAM,yBAAyB;AAAA,SAAAC,GAAA,IAAAC,IAAA;AAI9C,MAAMC,WAAW,GAAGH,QAAQ,CAACI,uBAAuB,CAACP,gBAAgB,CACnE,KAAK,EACL,MAAMC,SACR,CAAC,CAAC;;AAEF;;AASA,OAAO,MAAMO,GAAG,gBAAGN,UAAU,CAC3B,SAASM,GAAGA,CAACC,KAAK,EAAEC,GAAG,EAAE;EACvB,oBACEL,IAAA,CAACC,WAAW;IAAA,GACNG,KAAK;IACTE,wBAAwB,EACtBF,KAAK,CAACE,wBAAwB,IAAI;MAChCC,OAAO,EAAE,IAAI;MACbC,sBAAsB,EAAE,GAAG;MAC3BC,QAAQ,EAAE;IACZ;IAEF;IAAA;IACAC,wBAAwB,EACtBN,KAAK,CAACM,wBAAwB,GAC1BhB,QAAQ,CAACU,KAAK,CAACM,wBAAwB,CAAC,GACxCC;IAEN;IAAA;IACAC,uBAAuB,EACrBR,KAAK,CAACQ,uBAAuB,GACzBlB,QAAQ,CAACU,KAAK,CAACQ,uBAAuB,CAAC,GACvCD,SACL;IACDE,SAAS,EACPR,GAAG,GACCX,QAAQ,CAAEoB,CAAC,IAAK;MAChB,IAAI,OAAOT,GAAG,KAAK,UAAU,EAAE;QAC7BA,GAAG,CAACS,CAAC,CAAC;MACR,CAAC,MAAM;QACLT,GAAG,CAACU,OAAO,GAAGD,CAAC;MACjB;IACF,CAAC,CAAC,GACAH;EACL,CACF,CAAC;AAEN,CACF,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useCallback } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* Hook that creates a stable callback handler for content inset updates.
|
|
6
|
+
* Use this with `onWillApplyContentInsets` prop to receive inset updates.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const bottomInset = useSharedValue<number | null>(null)
|
|
11
|
+
*
|
|
12
|
+
* const contentInsetHandler = useContentInsetHandler((insets) => {
|
|
13
|
+
* bottomInset.value = insets.bottom ?? null
|
|
14
|
+
* })
|
|
15
|
+
*
|
|
16
|
+
* <Aix
|
|
17
|
+
* shouldApplyContentInsets={false}
|
|
18
|
+
* onWillApplyContentInsets={contentInsetHandler}
|
|
19
|
+
* />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function useContentInsetHandler(handler, dependencies = []) {
|
|
23
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
24
|
+
return useCallback(handler, dependencies);
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=useContentInsetHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useCallback","useContentInsetHandler","handler","dependencies"],"sourceRoot":"../../../src","sources":["hooks/useContentInsetHandler.ts"],"mappings":";;AAAA,SAASA,WAAW,QAAQ,OAAO;AAGnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,sBAAsBA,CACpCC,OAA2C,EAC3CC,YAAuB,GAAG,EAAE,EAC5B;EACA;EACA,OAAOH,WAAW,CAACE,OAAO,EAAEC,YAAY,CAAC;AAC3C","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { useRef } from 'react';
|
|
|
6
6
|
export * from './fade-in';
|
|
7
7
|
export { Aix } from './aix';
|
|
8
8
|
export { AixFooter } from './footer';
|
|
9
|
+
export { useContentInsetHandler } from './hooks/useContentInsetHandler';
|
|
9
10
|
export const AixCell = getHostComponent('AixCellView', () => AixCellViewConfig);
|
|
10
11
|
export function useAixRef() {
|
|
11
12
|
return useRef(null);
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["getHostComponent","AixCellViewConfig","useRef","Aix","AixFooter","AixCell","useAixRef"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,gBAAgB,QAAwB,4BAA4B;AAC7E,OAAOC,iBAAiB,MAAM,0DAA0D;AAExF,SAASC,MAAM,QAAQ,OAAO;AAE9B,cAAc,WAAW;AAEzB,SAASC,GAAG,QAAqB,OAAO;AACxC,SAASC,SAAS,QAAQ,UAAU;
|
|
1
|
+
{"version":3,"names":["getHostComponent","AixCellViewConfig","useRef","Aix","AixFooter","useContentInsetHandler","AixCell","useAixRef"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,gBAAgB,QAAwB,4BAA4B;AAC7E,OAAOC,iBAAiB,MAAM,0DAA0D;AAExF,SAASC,MAAM,QAAQ,OAAO;AAE9B,cAAc,WAAW;AAEzB,SAASC,GAAG,QAAqB,OAAO;AACxC,SAASC,SAAS,QAAQ,UAAU;AACpC,SAASC,sBAAsB,QAAQ,gCAAgC;AAGvE,OAAO,MAAMC,OAAO,GAAGN,gBAAgB,CACrC,aAAa,EACb,MAAMC,iBACR,CAAC;AAID,OAAO,SAASM,SAASA,CAAA,EAAG;EAC1B,OAAOL,MAAM,CAAgB,IAAI,CAAC;AACpC","ignoreList":[]}
|