@apexnative/navigation 1.0.0-alpha.1 → 1.0.0-alpha.2
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/CHANGELOG.md +16 -0
- package/README.md +147 -51
- package/android/CLAUDE.md +10 -4
- package/android/CORE.md +4 -1
- package/android/RECIPES.md +4 -3
- package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +5 -4
- package/android/src/main/java/dev/apexnative/navigation/react/ErrorTexts.kt +75 -60
- package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +3 -2
- package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +5 -4
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +7 -6
- package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +3 -35
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +101 -87
- package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
- package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +12 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +12 -11
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +25 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +1 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +4 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +8 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +2 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +2 -1
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +5 -5
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +85 -27
- package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +5 -4
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +45 -1
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +3 -5
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +3 -5
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +3 -5
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +2 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +4 -6
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +4 -6
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +4 -3
- package/cli/app.js +1 -1
- package/cli/project.js +6 -2
- package/cli/setup/index.js +13 -0
- package/cli/setup/steps/appDelegate.js +66 -11
- package/cli/setup/steps/sceneDelegate.js +108 -0
- package/docs-md/architecture/transitions.md +1 -1
- package/docs-md/guides/deep-links.md +15 -33
- package/docs-md/start/installation.md +1 -0
- package/ios/Animations/ANNTransitionAnimator.mm +13 -11
- package/ios/Animations/ANNTransitionWait.mm +6 -7
- package/ios/Animations/Elements/ANNElementFinder.h +57 -0
- package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
- package/ios/Animations/Elements/ANNElementTransition.h +7 -5
- package/ios/Animations/Elements/ANNElementTransition.mm +17 -19
- package/ios/Animations/Elements/ANNSharedElementFlight.h +13 -8
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +59 -24
- package/ios/CLAUDE.md +10 -2
- package/ios/CORE.md +3 -2
- package/ios/Contract/ANNCommandAnswer.h +4 -3
- package/ios/Contract/ANNCommandAnswer.mm +12 -2
- package/ios/Contract/ANNCommandRunner.h +2 -2
- package/ios/Contract/ANNCommandRunner.mm +1 -1
- package/ios/Contract/ANNErrorTexts.h +6 -2
- package/ios/Contract/ANNErrorTexts.mm +18 -10
- package/ios/Core/ANNDeepLinkQueue.h +20 -1
- package/ios/Core/ANNDeepLinkQueue.mm +107 -12
- package/ios/Core/ANNErrorHandler.h +8 -3
- package/ios/Core/ANNErrorHandler.mm +17 -1
- package/ios/Core/ANNEventContract.h +246 -0
- package/ios/Core/ANNEventContract.mm +225 -0
- package/ios/Core/ANNEventEmitter.h +5 -1
- package/ios/Core/ANNEventEmitter.mm +117 -80
- package/ios/Core/ANNHinge.mm +6 -4
- package/ios/Core/ANNSceneDelegate.mm +25 -15
- package/ios/Core/ANNSystemUI.h +3 -2
- package/ios/Core/ANNSystemUI.mm +7 -0
- package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +6 -4
- package/ios/Layouts/Modal/ANNModalCoordinator.mm +1 -1
- package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
- package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
- package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
- package/ios/Layouts/Root/ANNRootCoordinator.mm +12 -3
- package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
- package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
- package/ios/Layouts/Screen/ANNComponentViewController.mm +28 -7
- package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
- package/ios/Layouts/Screen/ANNScreenInsets.mm +6 -4
- package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -6
- package/ios/Layouts/SplitView/ANNSplitViewController.mm +4 -7
- package/ios/Options/ANNSheetOptions.h +4 -1
- package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
- package/ios/RECIPES.md +2 -1
- package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
- package/ios/TurboModules/ANNTurboModule.mm +5 -2
- package/lib/module/ARCHITECTURE.md +7 -4
- package/lib/module/api/app/createNavigation.js +2 -0
- package/lib/module/api/app/createNavigation.js.map +1 -1
- package/lib/module/api/linking/dispatchedLinks.js +23 -0
- package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
- package/lib/module/interfaces/contract/errors.json +275 -0
- package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
- package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
- package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
- package/lib/typescript/interfaces/Events.d.ts +9 -0
- package/lib/typescript/interfaces/Events.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/animations.d.ts +17 -13
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/modals.d.ts +15 -11
- package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/sideMenu.d.ts +7 -6
- package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/system.d.ts +4 -3
- package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ARCHITECTURE.md +7 -4
- package/src/api/app/createNavigation.ts +2 -0
- package/src/api/linking/dispatchedLinks.ts +18 -0
- package/src/interfaces/Events.ts +10 -0
- package/src/interfaces/contract/errors.json +275 -0
- package/src/interfaces/options/animations.ts +17 -13
- package/src/interfaces/options/modals.ts +15 -11
- package/src/interfaces/options/sideMenu.ts +7 -6
- package/src/interfaces/options/system.ts +4 -3
|
@@ -118,21 +118,21 @@ static NSDictionary<NSString *, NSNumber *> *ANNTransitionStyles(void) {
|
|
|
118
118
|
return nil;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
// UIKit
|
|
122
|
-
// shown with `partialCurl` presents nothing more: the command
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
// UIKit curls only a full-screen modal over a controller that fills the screen: elsewhere `partialCurl` is
|
|
122
|
+
// `coverVertical`, so the modal still shows. A controller shown with `partialCurl` presents nothing more: the command
|
|
123
|
+
// rejects before it asks UIKit.
|
|
124
|
+
- (NSString *)fitToPresenting:(UIViewController *)presenting
|
|
125
|
+
windowRoot:(UIViewController *)windowRoot {
|
|
125
126
|
if (presenting.presentingViewController &&
|
|
126
127
|
presenting.modalTransitionStyle == UIModalTransitionStylePartialCurl) {
|
|
127
|
-
return @"partialCurl
|
|
128
|
+
return @"a modal shown with partialCurl can't show another modal";
|
|
128
129
|
}
|
|
129
|
-
if (_transitionStyle
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return @"partialCurl needs a full screen modal";
|
|
130
|
+
if (_transitionStyle == UIModalTransitionStylePartialCurl) {
|
|
131
|
+
BOOL presentingFills = presenting == windowRoot ||
|
|
132
|
+
presenting.modalPresentationStyle == UIModalPresentationFullScreen;
|
|
133
|
+
if (_style != UIModalPresentationFullScreen || !presentingFills) {
|
|
134
|
+
_transitionStyle = UIModalTransitionStyleCoverVertical;
|
|
135
|
+
}
|
|
136
136
|
}
|
|
137
137
|
return nil;
|
|
138
138
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#import "ANNSheetPresenter.h"
|
|
2
2
|
#import "ANNModalSizePresenter.h"
|
|
3
3
|
#import "ANNReactView.h"
|
|
4
|
+
#import "ANNUtils.h"
|
|
4
5
|
#import "UIViewController+LayoutProtocol.h"
|
|
5
6
|
#import <React/RCTLog.h>
|
|
6
7
|
#import <objc/runtime.h>
|
|
@@ -53,7 +54,7 @@ static NSString *const ANNContentDetent = @"content";
|
|
|
53
54
|
+ (void)applyOptions:(ANNSheetOptions *)options toSheet:(UISheetPresentationController *)sheet {
|
|
54
55
|
if (options.detents) {
|
|
55
56
|
NSMutableArray<UISheetPresentationControllerDetent *> *detents = [NSMutableArray new];
|
|
56
|
-
for (id value in options.detents) {
|
|
57
|
+
for (id value in [self sortedDetents:options.detents ofSheet:sheet]) {
|
|
57
58
|
UISheetPresentationControllerDetent *detent = [self detentFor:value ofSheet:sheet];
|
|
58
59
|
if (detent) {
|
|
59
60
|
[detents addObject:detent];
|
|
@@ -81,6 +82,85 @@ static NSString *const ANNContentDetent = @"content";
|
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
|
|
85
|
+
// UIKit wants the detents once each, from the lowest to the highest: it takes the last for the largest and closes the
|
|
86
|
+
// sheet on a drag down from the first. The options may give them in any order and more than once; the first of a
|
|
87
|
+
// repeat stays, and detents of the same height keep their order.
|
|
88
|
+
+ (NSArray *)sortedDetents:(NSArray *)values ofSheet:(UISheetPresentationController *)sheet {
|
|
89
|
+
NSMutableArray *detents = [NSMutableArray new];
|
|
90
|
+
NSMutableSet<NSString *> *identifiers = [NSMutableSet new];
|
|
91
|
+
for (id value in values) {
|
|
92
|
+
NSString *identifier = [self identifierFor:value];
|
|
93
|
+
if (identifier && ![identifiers containsObject:identifier]) {
|
|
94
|
+
[identifiers addObject:identifier];
|
|
95
|
+
[detents addObject:value];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
CGFloat maximum = [self maximumDetentHeightOf:sheet];
|
|
99
|
+
return [detents sortedArrayWithOptions:NSSortStable
|
|
100
|
+
usingComparator:^NSComparisonResult(id a, id b) {
|
|
101
|
+
return [self compareHeightOf:a
|
|
102
|
+
with:b
|
|
103
|
+
maximum:maximum
|
|
104
|
+
ofSheet:sheet];
|
|
105
|
+
}];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// The content of a sheet sized to it changed its height, and with it maybe its place among the other detents.
|
|
109
|
+
+ (void)sortDetentsOfSheet:(UISheetPresentationController *)sheet API_AVAILABLE(ios(16.0)) {
|
|
110
|
+
CGFloat maximum = [self maximumDetentHeightOf:sheet];
|
|
111
|
+
NSArray<UISheetPresentationControllerDetent *> *detents = sheet.detents;
|
|
112
|
+
NSArray<UISheetPresentationControllerDetent *> *sorted = [detents
|
|
113
|
+
sortedArrayWithOptions:NSSortStable
|
|
114
|
+
usingComparator:^NSComparisonResult(UISheetPresentationControllerDetent *a,
|
|
115
|
+
UISheetPresentationControllerDetent *b) {
|
|
116
|
+
return [self compareHeightOf:[self detentForIdentifier:a.identifier]
|
|
117
|
+
with:[self detentForIdentifier:b.identifier]
|
|
118
|
+
maximum:maximum
|
|
119
|
+
ofSheet:sheet];
|
|
120
|
+
}];
|
|
121
|
+
if (![sorted isEqualToArray:detents]) {
|
|
122
|
+
sheet.detents = sorted;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
+ (NSComparisonResult)compareHeightOf:(id)a
|
|
127
|
+
with:(id)b
|
|
128
|
+
maximum:(CGFloat)maximum
|
|
129
|
+
ofSheet:(UISheetPresentationController *)sheet {
|
|
130
|
+
CGFloat heightA = [self heightOf:a maximum:maximum ofSheet:sheet];
|
|
131
|
+
CGFloat heightB = [self heightOf:b maximum:maximum ofSheet:sheet];
|
|
132
|
+
return heightA < heightB ? NSOrderedAscending
|
|
133
|
+
: heightA > heightB ? NSOrderedDescending : NSOrderedSame;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// The height a detent of the options stands at, to sort them, as its resolver gives it: 'medium' half of the largest
|
|
137
|
+
// height (UIKit's is about half), 'large' all of it, a height capped at it, 'content' the content's height now, all of
|
|
138
|
+
// it while the content isn't measured.
|
|
139
|
+
+ (CGFloat)heightOf:(id)value
|
|
140
|
+
maximum:(CGFloat)maximum
|
|
141
|
+
ofSheet:(UISheetPresentationController *)sheet {
|
|
142
|
+
if ([value isEqual:@"medium"]) {
|
|
143
|
+
return maximum / 2;
|
|
144
|
+
}
|
|
145
|
+
if ([value isKindOfClass:NSNumber.class]) {
|
|
146
|
+
return MIN([value doubleValue], maximum);
|
|
147
|
+
}
|
|
148
|
+
if ([value isEqual:ANNContentDetent]) {
|
|
149
|
+
CGFloat height = [self contentHeightOf:sheet.presentedViewController];
|
|
150
|
+
return height > 0 ? MIN(height, maximum) : maximum;
|
|
151
|
+
}
|
|
152
|
+
return maximum;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// About the largest height of a sheet: its container, or the window before it is shown, below the top safe area.
|
|
156
|
+
+ (CGFloat)maximumDetentHeightOf:(UISheetPresentationController *)sheet {
|
|
157
|
+
UIView *view = sheet.containerView ?: ANNUtils.mainWindow;
|
|
158
|
+
if (!view) {
|
|
159
|
+
return ANNUtils.mainScreen.bounds.size.height;
|
|
160
|
+
}
|
|
161
|
+
return view.bounds.size.height - view.safeAreaInsets.top;
|
|
162
|
+
}
|
|
163
|
+
|
|
84
164
|
+ (UISheetPresentationControllerDetent *)detentFor:(id)value
|
|
85
165
|
ofSheet:(UISheetPresentationController *)sheet {
|
|
86
166
|
if ([value isEqual:@"medium"]) {
|
|
@@ -180,6 +260,7 @@ static NSString *const ANNContentDetent = @"content";
|
|
|
180
260
|
}
|
|
181
261
|
height = newHeight;
|
|
182
262
|
[strongSheet animateChanges:^{
|
|
263
|
+
[self sortDetentsOfSheet:strongSheet];
|
|
183
264
|
[strongSheet invalidateDetents];
|
|
184
265
|
}];
|
|
185
266
|
}
|
|
@@ -201,6 +282,7 @@ static NSString *const ANNContentDetent = @"content";
|
|
|
201
282
|
// The new screen's content mounts may come later: its mounts resolve the detents again too.
|
|
202
283
|
[self followContentOfSheet:sheet when:YES];
|
|
203
284
|
[sheet animateChanges:^{
|
|
285
|
+
[self sortDetentsOfSheet:sheet];
|
|
204
286
|
[sheet invalidateDetents];
|
|
205
287
|
}];
|
|
206
288
|
}
|
|
@@ -69,7 +69,10 @@ typedef NS_ENUM(NSInteger, ANNRootShowState) {
|
|
|
69
69
|
// The nodes whose appearance the transition reports itself (`driveAppearanceOf:`), while `driving`.
|
|
70
70
|
@property(nonatomic, copy) NSArray<UIViewController *> *driven;
|
|
71
71
|
@property(nonatomic) BOOL driving;
|
|
72
|
+
// The snapshot of the window as it was: it dissolves over the new root (`dissolves`), plays its `exit` (`custom`), or
|
|
73
|
+
// only covers the old root's modals while they go, and leaves as the new root is the window's.
|
|
72
74
|
@property(nonatomic, strong, nullable) UIView *snapshot;
|
|
75
|
+
@property(nonatomic) BOOL dissolves;
|
|
73
76
|
// The root is the window's root: the old root's modals went before it (`startTransitionOf:done:`).
|
|
74
77
|
@property(nonatomic) BOOL installed;
|
|
75
78
|
// The root's view waits in the window under the current root (`park:`).
|
|
@@ -415,9 +418,14 @@ static __weak ANNRootShow *ANNAnimatingShow;
|
|
|
415
418
|
BOOL seen = !window.hidden && scene != nil &&
|
|
416
419
|
scene.activationState != UISceneActivationStateBackground;
|
|
417
420
|
BOOL dissolves = !overSplash && !enterDisabled && !custom && seen;
|
|
421
|
+
show.dissolves = dissolves;
|
|
418
422
|
show.custom = custom && seen;
|
|
419
|
-
|
|
420
|
-
|
|
423
|
+
// UIKit draws the dismissal of the old root's modals, without animation too (a sheet's dim goes a frame before
|
|
424
|
+
// its card): with nothing to dissolve, the snapshot covers them until the new root is in place.
|
|
425
|
+
BOOL covers = seen && old.presentedViewController != nil;
|
|
426
|
+
UIView *snapshot = dissolves || show.custom || covers
|
|
427
|
+
? [window snapshotViewAfterScreenUpdates:NO]
|
|
428
|
+
: nil;
|
|
421
429
|
|
|
422
430
|
show.state = ANNRootShowStateTransition;
|
|
423
431
|
// It shows from here: a stack in it counts as on screen.
|
|
@@ -480,7 +488,8 @@ static __weak ANNRootShow *ANNAnimatingShow;
|
|
|
480
488
|
[self endTransitionOf:show];
|
|
481
489
|
return;
|
|
482
490
|
}
|
|
483
|
-
|
|
491
|
+
// A snapshot that only covered the old root's modals leaves in this turn, with the new root in place under it.
|
|
492
|
+
if (!snapshot || !show.dissolves) {
|
|
484
493
|
[self endTransitionOf:show];
|
|
485
494
|
return;
|
|
486
495
|
}
|
|
@@ -19,11 +19,19 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
19
19
|
/// it. Nothing before the screen's view is loaded.
|
|
20
20
|
- (void)applyBackground:(ANNNavigationOptions *)resolvedOptions;
|
|
21
21
|
|
|
22
|
-
/// `statusBar.blur` (iOS): UIKit's regular blur over the screen's own view in the frame of the scene's status bar
|
|
23
|
-
///
|
|
24
|
-
///
|
|
22
|
+
/// `statusBar.blur` (iOS): UIKit's regular blur over the screen's own view in the frame of the scene's status bar (x 0,
|
|
23
|
+
/// the view's width), laid out at once; `false` or none removes it. At each appearance and at a merge that names it;
|
|
24
|
+
/// nothing before the screen's view is loaded.
|
|
25
25
|
- (void)applyStatusBarBlur:(ANNNavigationOptions *)resolvedOptions;
|
|
26
26
|
|
|
27
|
+
/// The blur takes the status bar's frame as it is now; nothing without a blur. The single place of its frame: the blur
|
|
28
|
+
/// as it is applied, the screen's view laid out (a rotation, a new window size, a new safe area), a size transition
|
|
29
|
+
/// along its animation and at its end, the turn after new traits, and `statusBarDidChange`.
|
|
30
|
+
- (void)layOutStatusBarBlur;
|
|
31
|
+
|
|
32
|
+
/// The status bar was asked again (hidden or shown, a new style): every blur takes its frame.
|
|
33
|
+
+ (void)statusBarDidChange;
|
|
34
|
+
|
|
27
35
|
/// The blur stays the last subview of the screen's view: the content added after it goes under it.
|
|
28
36
|
- (void)keepStatusBarBlurOnTop;
|
|
29
37
|
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
#import "ANNTopBarPresenter.h"
|
|
6
6
|
#import "ANNUtils.h"
|
|
7
7
|
|
|
8
|
+
// The presenters whose screen shows `statusBar.blur`: the status bar hidden or shown lays out no view, so they hear of
|
|
9
|
+
// it from the system UI (`statusBarDidChange`).
|
|
10
|
+
static NSHashTable<ANNComponentPresenter *> *ANNBlurringPresenters;
|
|
11
|
+
|
|
8
12
|
@implementation ANNComponentPresenter {
|
|
9
13
|
// `statusBar.blur` while it is on.
|
|
10
14
|
UIVisualEffectView *_statusBarBlur;
|
|
@@ -95,9 +99,7 @@
|
|
|
95
99
|
|
|
96
100
|
#pragma mark - The status bar's blur (`statusBar.blur`)
|
|
97
101
|
|
|
98
|
-
// Over the screen's own view, never over a React view; no touches, nothing for VoiceOver.
|
|
99
|
-
// status bar's as it is now, in the view's own coordinates without a conversion: a pushed screen's view may still be
|
|
100
|
-
// out of place while it appears.
|
|
102
|
+
// Over the screen's own view, never over a React view; no touches, nothing for VoiceOver.
|
|
101
103
|
- (void)applyStatusBarBlur:(ANNNavigationOptions *)resolvedOptions {
|
|
102
104
|
ANNComponentViewController *screen = self.screen;
|
|
103
105
|
if (!screen.isViewLoaded) {
|
|
@@ -106,6 +108,7 @@
|
|
|
106
108
|
if (![resolvedOptions.statusBar.blur withDefault:NO]) {
|
|
107
109
|
[_statusBarBlur removeFromSuperview];
|
|
108
110
|
_statusBarBlur = nil;
|
|
111
|
+
[ANNBlurringPresenters removeObject:self];
|
|
109
112
|
return;
|
|
110
113
|
}
|
|
111
114
|
UIView *view = screen.view;
|
|
@@ -115,15 +118,40 @@
|
|
|
115
118
|
_statusBarBlur.userInteractionEnabled = NO;
|
|
116
119
|
_statusBarBlur.isAccessibilityElement = NO;
|
|
117
120
|
_statusBarBlur.accessibilityElementsHidden = YES;
|
|
121
|
+
if (!ANNBlurringPresenters) {
|
|
122
|
+
ANNBlurringPresenters = [NSHashTable weakObjectsHashTable];
|
|
123
|
+
}
|
|
124
|
+
[ANNBlurringPresenters addObject:self];
|
|
118
125
|
}
|
|
119
|
-
CGRect statusBar = ANNUtils.statusBarFrame;
|
|
120
|
-
_statusBarBlur.frame = CGRectMake(0, CGRectGetMinY(statusBar), CGRectGetWidth(view.bounds),
|
|
121
|
-
CGRectGetHeight(statusBar));
|
|
122
126
|
if (_statusBarBlur.superview != view) {
|
|
123
127
|
[view addSubview:_statusBarBlur];
|
|
124
128
|
} else {
|
|
125
129
|
[view bringSubviewToFront:_statusBarBlur];
|
|
126
130
|
}
|
|
131
|
+
[self layOutStatusBarBlur];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// The status bar's frame in the scene of the screen's window (the main window's before the screen is in one), in the
|
|
135
|
+
// view's own coordinates without a conversion: a pushed screen's view may still be out of place while it appears. A
|
|
136
|
+
// hidden status bar has no frame, and the blur no height.
|
|
137
|
+
- (void)layOutStatusBarBlur {
|
|
138
|
+
UIView *view = _statusBarBlur.superview;
|
|
139
|
+
if (!view) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
UIWindowScene *scene = view.window.windowScene;
|
|
143
|
+
CGRect statusBar = scene ? scene.statusBarManager.statusBarFrame : ANNUtils.statusBarFrame;
|
|
144
|
+
CGRect frame = CGRectMake(0, CGRectGetMinY(statusBar), CGRectGetWidth(view.bounds),
|
|
145
|
+
CGRectGetHeight(statusBar));
|
|
146
|
+
if (!CGRectEqualToRect(_statusBarBlur.frame, frame)) {
|
|
147
|
+
_statusBarBlur.frame = frame;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
+ (void)statusBarDidChange {
|
|
152
|
+
for (ANNComponentPresenter *presenter in ANNBlurringPresenters.allObjects) {
|
|
153
|
+
[presenter layOutStatusBarBlur];
|
|
154
|
+
}
|
|
127
155
|
}
|
|
128
156
|
|
|
129
157
|
- (void)keepStatusBarBlurOnTop {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#import "ANNArrangementState.h"
|
|
4
4
|
#import "ANNBottomTabsController.h"
|
|
5
5
|
#import "ANNComponentPresenter.h"
|
|
6
|
+
#import "ANNEventContract.h"
|
|
6
7
|
#import "ANNHinge.h"
|
|
7
8
|
#import "ANNKeyCommands.h"
|
|
8
9
|
#import "ANNNodeRegistry.h"
|
|
@@ -66,6 +67,12 @@
|
|
|
66
67
|
|
|
67
68
|
#pragma mark - The view
|
|
68
69
|
|
|
70
|
+
- (nullable ANNComponentPresenter *)componentPresenter {
|
|
71
|
+
ANNNodePresenter *presenter = self.presenter;
|
|
72
|
+
return [presenter isKindOfClass:ANNComponentPresenter.class] ? (ANNComponentPresenter *)presenter
|
|
73
|
+
: nil;
|
|
74
|
+
}
|
|
75
|
+
|
|
69
76
|
// The size of the screen of the navigation window's scene, not the deprecated main screen: a surface made before the
|
|
70
77
|
// screen is in a window starts with the width it will have.
|
|
71
78
|
- (void)loadView {
|
|
@@ -94,6 +101,22 @@
|
|
|
94
101
|
}
|
|
95
102
|
// The pair the screen is in may lie otherwise now.
|
|
96
103
|
[self.arrangement screenDidChangeLayout:self];
|
|
104
|
+
[self.componentPresenter layOutStatusBarBlur];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// UIKit names the size transition as the moment the status bar's frame changes (a rotation, a new window size): the
|
|
108
|
+
// blur follows it along the animation and takes the final frame at its end.
|
|
109
|
+
- (void)viewWillTransitionToSize:(CGSize)size
|
|
110
|
+
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
|
111
|
+
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
|
112
|
+
__weak ANNComponentViewController *weakSelf = self;
|
|
113
|
+
[coordinator
|
|
114
|
+
animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
|
|
115
|
+
[weakSelf.componentPresenter layOutStatusBarBlur];
|
|
116
|
+
}
|
|
117
|
+
completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
|
|
118
|
+
[weakSelf.componentPresenter layOutStatusBarBlur];
|
|
119
|
+
}];
|
|
97
120
|
}
|
|
98
121
|
|
|
99
122
|
- (void)viewSafeAreaInsetsDidChange {
|
|
@@ -110,6 +133,7 @@
|
|
|
110
133
|
__weak ANNComponentViewController *weakSelf = self;
|
|
111
134
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
112
135
|
[weakSelf updateRootLayout];
|
|
136
|
+
[weakSelf.componentPresenter layOutStatusBarBlur];
|
|
113
137
|
});
|
|
114
138
|
}
|
|
115
139
|
|
|
@@ -200,9 +224,7 @@
|
|
|
200
224
|
#pragma mark - The root frame and the safe area
|
|
201
225
|
|
|
202
226
|
- (void)applyBackground {
|
|
203
|
-
|
|
204
|
-
[(ANNComponentPresenter *)self.presenter applyBackground:[self resolveOptionsWithDefault]];
|
|
205
|
-
}
|
|
227
|
+
[self.componentPresenter applyBackground:[self resolveOptionsWithDefault]];
|
|
206
228
|
}
|
|
207
229
|
|
|
208
230
|
// The navigation controller that shows the screen's stack: the stack, or UIKit's More navigation while a tab of More
|
|
@@ -434,7 +456,8 @@
|
|
|
434
456
|
if (!regions) {
|
|
435
457
|
return;
|
|
436
458
|
}
|
|
437
|
-
|
|
459
|
+
const auto &keys = ANNEventContract.ScreenRegionsChanged;
|
|
460
|
+
BOOL empty = [regions[keys.division] count] == 0 && [regions[keys.occlusion] count] == 0;
|
|
438
461
|
if (empty && ![ANNScreenRegions regionsForScreenId:componentId]) {
|
|
439
462
|
return;
|
|
440
463
|
}
|
|
@@ -606,9 +629,7 @@
|
|
|
606
629
|
content.autoresizingMask = UIViewAutoresizingNone;
|
|
607
630
|
content.frame = [self rootFrameForOptions:[self resolveOptionsWithDefault]];
|
|
608
631
|
[view addSubview:content];
|
|
609
|
-
|
|
610
|
-
[(ANNComponentPresenter *)self.presenter keepStatusBarBlurOnTop];
|
|
611
|
-
}
|
|
632
|
+
[self.componentPresenter keepStatusBarBlurOnTop];
|
|
612
633
|
[self applyBackground];
|
|
613
634
|
[self updateRootLayout];
|
|
614
635
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#import "ANNNativeScreenContext+Internal.h"
|
|
2
2
|
#import "ANNErrorTexts.h"
|
|
3
|
+
#import "ANNEventContract.h"
|
|
3
4
|
#import "ANNEventEmitter.h"
|
|
4
5
|
#import "ANNNativeScreenCalls.h"
|
|
5
6
|
#import <React/RCTUtils.h>
|
|
@@ -71,12 +72,13 @@
|
|
|
71
72
|
componentId:self->_componentId]];
|
|
72
73
|
return;
|
|
73
74
|
}
|
|
75
|
+
const auto &keys = ANNEventContract.NativeScreenCall;
|
|
74
76
|
[eventEmitter sendNativeScreenCall:@{
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
keys.componentId : self->_componentId,
|
|
78
|
+
keys.callId : callId,
|
|
79
|
+
keys.kind : kind,
|
|
80
|
+
keys.name : name,
|
|
81
|
+
keys.args : arguments ?: @[],
|
|
80
82
|
}];
|
|
81
83
|
});
|
|
82
84
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#import "ANNScreenInsets.h"
|
|
2
|
+
#import "ANNEventContract.h"
|
|
2
3
|
|
|
3
4
|
NSNotificationName const ANNScreenSafeAreaPaddingDidChangeNotification = @"ANNScreenSafeAreaPaddingDidChange";
|
|
4
5
|
|
|
@@ -26,11 +27,12 @@ static NSMutableDictionary<NSString *, NSValue *> *ANNScreenPaddingById;
|
|
|
26
27
|
object:screenId];
|
|
27
28
|
}
|
|
28
29
|
// JavaScript gets what still covers the content: the edges the safe area view keeps it off are 0.
|
|
30
|
+
const auto &keys = ANNEventContract.ScreenInsetsChanged;
|
|
29
31
|
NSDictionary<NSString *, NSNumber *> *value = @{
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
keys.top : @(MAX(insets.top - padding.top, 0)),
|
|
33
|
+
keys.right : @(MAX(insets.right - padding.right, 0)),
|
|
34
|
+
keys.bottom : @(MAX(insets.bottom - padding.bottom, 0)),
|
|
35
|
+
keys.left : @(MAX(insets.left - padding.left, 0)),
|
|
34
36
|
};
|
|
35
37
|
@synchronized(ANNScreenInsetsById) {
|
|
36
38
|
if ([ANNScreenInsetsById[screenId] isEqualToDictionary:value]) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#import "ANNScreenRegions.h"
|
|
2
|
+
#import "ANNEventContract.h"
|
|
2
3
|
|
|
3
4
|
static NSMutableDictionary<NSString *, NSDictionary<NSString *, NSArray *> *> *ANNScreenRegionsById;
|
|
4
5
|
|
|
@@ -36,11 +37,12 @@ ANNRegionRects(NSArray<UIViewReservedRegion *> *regions, UIView *view, UIView *c
|
|
|
36
37
|
if (CGRectIsNull(frame)) {
|
|
37
38
|
continue;
|
|
38
39
|
}
|
|
40
|
+
const auto &keys = ANNEventContract.ScreenRegionRect;
|
|
39
41
|
[rects addObject:@{
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
keys.x : @(frame.origin.x),
|
|
43
|
+
keys.y : @(frame.origin.y),
|
|
44
|
+
keys.width : @(frame.size.width),
|
|
45
|
+
keys.height : @(frame.size.height),
|
|
44
46
|
}];
|
|
45
47
|
}
|
|
46
48
|
return rects;
|
|
@@ -63,9 +65,10 @@ ANNRegionRects(NSArray<UIViewReservedRegion *> *regions, UIView *view, UIView *c
|
|
|
63
65
|
[view reservedRegionsOfKind:[UIViewReservedRegionKind divisionRegionKind]];
|
|
64
66
|
NSArray<UIViewReservedRegion *> *occlusion =
|
|
65
67
|
[view reservedRegionsOfKind:[UIViewReservedRegionKind occlusionRegionKind]];
|
|
68
|
+
const auto &keys = ANNEventContract.ScreenRegionsChanged;
|
|
66
69
|
return @{
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
keys.division : ANNRegionRects(division, view, coordinateView),
|
|
71
|
+
keys.occlusion : ANNRegionRects(occlusion, view, coordinateView),
|
|
69
72
|
};
|
|
70
73
|
}
|
|
71
74
|
#endif
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#import "ANNSplitViewController.h"
|
|
2
2
|
#import "ANNErrorHandler.h"
|
|
3
|
+
#import "ANNErrorTexts.h"
|
|
3
4
|
#import "ANNShownScreens.h"
|
|
4
5
|
#import "UISplitViewController+ANNOptions.h"
|
|
5
6
|
#import "UIViewController+LayoutProtocol.h"
|
|
@@ -213,19 +214,15 @@ static UISplitViewControllerColumn ANNSplitViewColumn(NSString *name) {
|
|
|
213
214
|
completion:(ANNTransitionCompletionBlock)completion
|
|
214
215
|
rejection:(ANNTransitionRejectionBlock)rejection {
|
|
215
216
|
UIViewController *previous = _columns[column];
|
|
217
|
+
NSString *fromId = fromViewController.layoutInfo.componentId;
|
|
216
218
|
if (!previous) {
|
|
217
|
-
rejection([
|
|
218
|
-
fromViewController.layoutInfo.componentId, column],
|
|
219
|
-
nil);
|
|
219
|
+
rejection([ANNErrorTexts noSuchColumn:fromId column:column], nil);
|
|
220
220
|
return;
|
|
221
221
|
}
|
|
222
222
|
if ([previous isKindOfClass:UINavigationController.class]) {
|
|
223
223
|
// UIKit does not take a navigation controller among the screens of another.
|
|
224
224
|
if ([screen isKindOfClass:UINavigationController.class]) {
|
|
225
|
-
rejection([
|
|
226
|
-
@"stack: it takes a screen, not a stack",
|
|
227
|
-
column, fromViewController.layoutInfo.componentId],
|
|
228
|
-
nil);
|
|
225
|
+
rejection([ANNErrorTexts columnIsStack:fromId column:column], nil);
|
|
229
226
|
return;
|
|
230
227
|
}
|
|
231
228
|
// In place, as a column of UIKit apps changes; UIKit animates a column it brings on top.
|
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
*/
|
|
8
8
|
@interface ANNSheetOptions : ANNOptions
|
|
9
9
|
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* The detents as the options give them, in any order and with repeats: NSString ('medium', 'large', 'content') or
|
|
12
|
+
* NSNumber. ANNSheetPresenter sorts them and drops the repeats.
|
|
13
|
+
*/
|
|
11
14
|
@property(nonatomic, strong) NSArray *detents;
|
|
12
15
|
@property(nonatomic, strong) Param *selectedDetent;
|
|
13
16
|
/** The largest detent the screen below stays undimmed and touchable at. */
|
|
@@ -9,6 +9,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
9
9
|
* When the scene connects, the navigation window moves into it. URLs, user activities and foreground/background
|
|
10
10
|
* changes that UIKit now delivers to the scene are forwarded to the app delegate's usual methods, so
|
|
11
11
|
* the deep links (`dispatchDeepLinkURL:`) and app delegate overrides keep working.
|
|
12
|
+
*
|
|
13
|
+
* The app's own scene delegate can extend it (`class SceneDelegate: ANNSceneDelegate {}`, which `setup` makes of React
|
|
14
|
+
* Native 0.88's template); a method it overrides calls `super`.
|
|
12
15
|
*/
|
|
13
16
|
@interface ANNSceneDelegate : UIResponder <UIWindowSceneDelegate>
|
|
14
17
|
|
package/ios/RECIPES.md
CHANGED
|
@@ -34,7 +34,8 @@ you do exactly that; the map is `ios/CLAUDE.md`.
|
|
|
34
34
|
4. **The layout check:** a new node type goes into `ANNLayoutType` and `ANNLayoutReader` (its place, its children), and
|
|
35
35
|
gets a maker in `ANNLayoutFactory`.
|
|
36
36
|
5. **Error texts** come from `ANNErrorTexts`, one sentence per case, the same as Android; a text deep in a maker is
|
|
37
|
-
thrown with `+[ANNErrorTexts rejection:]`.
|
|
37
|
+
thrown with `+[ANNErrorTexts rejection:]`. A new text goes into `src/interfaces/contract/errors.json`, and
|
|
38
|
+
`node scripts/contract.mjs` makes `ANNErrorTexts` (and Android's `ErrorTexts`) from it; never edit them by hand.
|
|
38
39
|
6. **The answer:** end through `ANNAppearanceDispatcher` (`endTransitionHiding:…answer:value:`) or call
|
|
39
40
|
`-[ANNCommandAnswer resolve:]`; the state and `ANN.CommandCompleted` follow by themselves for the names in
|
|
40
41
|
`ANNCompletedCommandNames`. Add the name there when the command shows or dismisses.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#import "ANNTurboEventEmitter.h"
|
|
2
2
|
#import "ANNAssert.h"
|
|
3
|
+
#import "ANNEventContract.h"
|
|
3
4
|
#import "ANNEventEmitter.h"
|
|
4
5
|
#import "ANNReloadCoordinator.h"
|
|
5
6
|
#import <React/RCTUtils.h>
|
|
@@ -40,41 +41,9 @@ RCT_EXPORT_MODULE(ANNTurboEventEmitter)
|
|
|
40
41
|
return self;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
// Every event of the navigation and of the modules.
|
|
44
|
+
// Every event of the navigation and of the modules, as the types of `src/interfaces/` name them.
|
|
44
45
|
- (NSArray<NSString *> *)supportedEvents {
|
|
45
|
-
return
|
|
46
|
-
@"ANN.AppLaunched",
|
|
47
|
-
@"ANN.ArrangementChanged",
|
|
48
|
-
@"ANN.BottomAccessoryPlacementChanged",
|
|
49
|
-
@"ANN.BottomTabLongPressed",
|
|
50
|
-
@"ANN.BottomTabPressed",
|
|
51
|
-
@"ANN.BottomTabSelected",
|
|
52
|
-
@"ANN.CommandCompleted",
|
|
53
|
-
@"ANN.ComponentDidAppear",
|
|
54
|
-
@"ANN.ComponentDidDisappear",
|
|
55
|
-
@"ANN.ComponentWillAppear",
|
|
56
|
-
@"ANN.HingeChanged",
|
|
57
|
-
@"ANN.KeyCommandPressed",
|
|
58
|
-
@"ANN.ModalAttemptedToDismiss",
|
|
59
|
-
@"ANN.ModalDismissed",
|
|
60
|
-
@"ANN.NativeScreenCall",
|
|
61
|
-
@"ANN.NativeScreenReleased",
|
|
62
|
-
@"ANN.NavigationButtonPressed",
|
|
63
|
-
@"ANN.NavigationStateChanged",
|
|
64
|
-
@"ANN.PreviewCompleted",
|
|
65
|
-
@"ANN.ScreenInsetsChanged",
|
|
66
|
-
@"ANN.ScreenPopped",
|
|
67
|
-
@"ANN.ScreenRegionsChanged",
|
|
68
|
-
@"ANN.SearchBarCancelPressed",
|
|
69
|
-
@"ANN.SearchBarSubmitted",
|
|
70
|
-
@"ANN.SearchBarUpdated",
|
|
71
|
-
@"ANN.SearchSuggestionPicked",
|
|
72
|
-
@"ANN.SheetDetentChanged",
|
|
73
|
-
@"ANN.SlotDestroyed",
|
|
74
|
-
@"ANN.SplitViewColumnsStacked",
|
|
75
|
-
@"ANN.SplitViewDisplayModeChanged",
|
|
76
|
-
@"ANN.TitleRenamed",
|
|
77
|
-
];
|
|
46
|
+
return ANNEventContractNames();
|
|
78
47
|
}
|
|
79
48
|
|
|
80
49
|
#pragma mark - Listeners
|
|
@@ -99,7 +68,7 @@ RCT_EXPORT_MODULE(ANNTurboEventEmitter)
|
|
|
99
68
|
|
|
100
69
|
- (void)addListener:(NSString *)eventName {
|
|
101
70
|
[super addListener:eventName];
|
|
102
|
-
if ([eventName isEqualToString
|
|
71
|
+
if ([eventName isEqualToString:ANNEventContract.AppLaunched.event] && !_listensToAppLaunched) {
|
|
103
72
|
_listensToAppLaunched = YES;
|
|
104
73
|
[ANNEventEmitter eventEmitterListensToAppLaunched:self];
|
|
105
74
|
}
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
#import "ANNComponentViewController.h"
|
|
6
6
|
#import "ANNDeepLinkQueue.h"
|
|
7
7
|
#import "ANNDefaultOptions.h"
|
|
8
|
+
#import "ANNErrorHandler.h"
|
|
8
9
|
#import "ANNErrorTexts.h"
|
|
10
|
+
#import "ANNEventContract.h"
|
|
9
11
|
#import "ANNExternalViewController.h"
|
|
10
12
|
#import "ANNHinge.h"
|
|
11
13
|
#import "ANNLayoutReader.h"
|
|
@@ -248,7 +250,7 @@ RCT_EXPORT_MODULE(ANNTurboModule)
|
|
|
248
250
|
layout:(NSDictionary *)layout
|
|
249
251
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
250
252
|
reject:(RCTPromiseRejectBlock)reject {
|
|
251
|
-
resolve
|
|
253
|
+
[ANNErrorHandler resolve:resolve of:@"preparePush" value:nil];
|
|
252
254
|
}
|
|
253
255
|
|
|
254
256
|
- (void)cancelPreparedPush:(NSString *)componentId {
|
|
@@ -511,7 +513,8 @@ RCT_EXPORT_MODULE(ANNTurboModule)
|
|
|
511
513
|
|
|
512
514
|
- (NSDictionary *)getScreenRegions:(NSString *)componentId {
|
|
513
515
|
NSDictionary *regions = [ANNScreenRegions regionsForScreenId:componentId];
|
|
514
|
-
|
|
516
|
+
const auto &keys = ANNEventContract.ScreenRegionsChanged;
|
|
517
|
+
return regions ?: @{keys.division : @[], keys.occlusion : @[]};
|
|
515
518
|
}
|
|
516
519
|
|
|
517
520
|
// `setHingeUpdates`: JavaScript counts its `useHinge` hooks; the events go with the emitter of the JavaScript that runs
|
|
@@ -63,7 +63,8 @@ form of `src/api/events/navigationEvents.ts`. Everything in `src/engine` is inte
|
|
|
63
63
|
`LinkParams`, `PendingLink`, …). `linkPaths.ts`: a URL into its path and query (`parseLink`), the patterns ordered
|
|
64
64
|
(`compileRoutes`) and matched (`matchLink`). `linking.ts`: the links of the app — the launch link, the `url` events
|
|
65
65
|
of React Native's `Linking`, the routes run, the pending link opened after `setContext`. `pendingLinks.ts`: the one
|
|
66
|
-
waiting link and its listeners, which `navigation` and `usePendingLink` read.
|
|
66
|
+
waiting link and its listeners, which `navigation` and `usePendingLink` read. `dispatchedLinks.ts` (iOS): hands
|
|
67
|
+
`Linking` the links of `ANN.DeepLinkDispatched`.
|
|
67
68
|
- `events/` — `navigationEvents.ts`: the events by name, the native event behind each, `onNavigationEvent`,
|
|
68
69
|
`listeners`. `screenLifecycle.ts`: what goes when a screen unmounts, `whenScreenUnmounts`. `tabPresses.ts`: the
|
|
69
70
|
handlers of `useTabPress`.
|
|
@@ -268,7 +269,9 @@ its push, which the hook ignores.
|
|
|
268
269
|
given once; JS asks only with `linking`) and `getStartInfo` (synchronous: `coldStart`, true for the whole life of
|
|
269
270
|
the first JavaScript runtime of the process, and `splashLogo`, the size of the native splash's logo the CLI wrote,
|
|
270
271
|
or null; `arrangements`, whether it shows pairs). The links that come while the app runs reach JS through React Native's
|
|
271
|
-
`Linking`, not through `ANN.*` events.
|
|
272
|
+
`Linking`, not through `ANN.*` events. One exception, iOS only: a link the app dispatched (`dispatchDeepLinkURL`) that
|
|
273
|
+
`Linking` doesn't take from the native side (React Native 0.88 and newer, with a scene delegate) comes as
|
|
274
|
+
`ANN.DeepLinkDispatched`, and `src/api/linking/dispatchedLinks.ts` hands it to `Linking` as a `url` event.
|
|
272
275
|
- Events: `ANN.AppLaunched`, `ANN.ComponentWillAppear`, `ANN.ComponentDidAppear`, `ANN.ComponentDidDisappear`,
|
|
273
276
|
`ANN.NavigationButtonPressed`, `ANN.BottomTabSelected`, `ANN.BottomTabPressed`, `ANN.BottomTabLongPressed`,
|
|
274
277
|
`ANN.ModalDismissed`, `ANN.ModalAttemptedToDismiss`, `ANN.ScreenPopped`, `ANN.SearchBarUpdated`,
|
|
@@ -276,8 +279,8 @@ its push, which the hook ignores.
|
|
|
276
279
|
`ANN.NavigationStateChanged`, `ANN.SlotDestroyed`, `ANN.ScreenInsetsChanged`, `ANN.TitleRenamed`,
|
|
277
280
|
`ANN.BottomAccessoryPlacementChanged`, `ANN.SheetDetentChanged`, `ANN.SplitViewDisplayModeChanged`,
|
|
278
281
|
`ANN.KeyCommandPressed`, `ANN.NativeScreenCall`, `ANN.NativeScreenReleased`, `ANN.ScreenRegionsChanged`,
|
|
279
|
-
`ANN.ArrangementChanged`, `ANN.HingeChanged`, `ANN.SplitViewColumnsStacked
|
|
280
|
-
`src/interfaces/ComponentEvents.ts` and `Events.ts`. Both platforms also send `ANN.CommandCompleted`
|
|
282
|
+
`ANN.ArrangementChanged`, `ANN.HingeChanged`, `ANN.SplitViewColumnsStacked`, `ANN.DeepLinkDispatched` (iOS). Their
|
|
283
|
+
payloads are typed in `src/interfaces/ComponentEvents.ts` and `Events.ts`. Both platforms also send `ANN.CommandCompleted`
|
|
281
284
|
(`CommandCompletedEvent`), which nothing in JS listens to.
|
|
282
285
|
- Native components: `ANNSlot` (`src/api/slots`) and `ANNSafeAreaView` (`src/api/safeArea`), with C++ of their own in
|
|
283
286
|
`ios/cpp`, which Android builds too (their states hold a size and a padding; the first one comes from the props
|