Root()
import { Root } from '@apexnative/navigation';
Root wraps the layout of a root to add what only a root has: modals shown over it once it is in place, and the
transition it comes in with. Where a root is given, Root(…) goes in place of the layout: root and roots of
createNavigation, navigation.switchTo, and start of a link. A root that needs neither stays a plain layout.
Usage
A notification about an order opens the order in a modal. When it launches the app, the user should land in the app with the order over it, as if they had opened it themselves, so that closing it leaves them in the app:
import {
navigation,
Root,
Screen,
Stack,
Tab,
Tabs,
} from '@apexnative/navigation';
export function openOrder(orderId: string) {
return navigation.switchTo(
Root(Tabs(Tab('Home'), Tab('Inbox'))).modal(
Stack(Screen('Details', { orderId })),
),
);
}
The tabs take the window, then Details slides up over them. When the user closes it, Home is under it.
A root of roots with a transition of its own:
roots: {
login: 'Login',
main: Root(Tabs(Tab('Home'), Tab('Inbox'))).transition('fade'),
},
Every navigation.switchTo('main') fades the tabs in over Login.
Signature
function Root<const Content extends LayoutContent>(
root: Content
): RootElement<UsesOf<Content>>
It takes what a root takes, and returns a RootElement:
- A screen name,
Root('Home'): the screen in a stack. InsideRoota string is always a screen name, also inswitchTo, where a string alone is the name of a root ofroots. - A layout:
Stack(…),Tabs(…),SideMenu(…),SplitView(…), orScreen(…)for a screen without a stack.
The screens it shows, those of its modals too, are checked against screens by the types.
Over the root
modal()
modal<const Content extends LayoutContent>(modal: Content): RootElement<Uses | UsesOf<Content>>
A modal shown over the root once the root is in place: the screen a notification or a link opens at a cold start, a prompt that must come first. The modal takes what a place of a layout takes; a screen name alone becomes a stack with the screen, so it can push.
Root('Home')
.modal('Onboarding')
.modal(Stack(Screen('Details', { orderId })));
- Several modals go one over the other, in order. The last comes with its animation, as a modal the user opens; those under it come at once, so the user sees one modal come up, not a series.
switchToresolves once the root and all its modals are shown.- The options of
presentation.modaldon't apply here: these modals are part of the layout, notshowModalcommands. A modal gets its screens' own options; give it other ones on its layout, such asStack(…).options({ … }). - iOS When the new root dissolves in over the old one, the modals come once it is in, not over the picture of the old root.
How it comes in
transition()
transition(transition: RootTransition): RootElement<Uses>
How this root replaces the one before. The transition belongs to the root, so with a root of roots it plays at every
switch to it.
'platform': the platform's own transition, as withouttransition().'none': no animation. The new root shows at once, as soon as its content is drawn, so it never comes in empty. It turns off both sides, the new root's and the old one's, so a setRoot animation in the app'soptions(animations.setRoot) doesn't play either.- A preset, 250 ms:
'fade','slideUp'(up from the bottom edge),'slideFromEnd'(from the trailing edge, the left one right to left),'scale'(grows from 85% as it fades in). { enter, exit }, animations of their own:enterfor the new root,exitfor the old one, with the properties of the screen animations (alpha,translationX,scaleXand the others),waitForRenderandenabled.
Root('Home').transition({
enter: {
alpha: { from: 0, to: 1, duration: 400 },
waitForRender: true,
},
});
With waitForRender: true the new root waits for its content as long as it takes, so it never comes in empty.
enabled: false turns a side off on both platforms, even when it has an animation: one of its own, or one that comes
from animations.setRoot in the app's options. When neither side plays, the platform's transition plays, unless
enter has enabled: false: then the new root shows at once, as with 'none'.
Without a transition, or with 'platform', the platform's own plays when a root replaces another:
iOS a cross dissolve of 0.3 s, Android Material's fade through. For a root that takes the
window at once, 'none':
navigation.switchTo(
Root(Tabs(Tab('Home'), Tab('Inbox'))).transition('none'),
);
The first root at launch comes in place of the splash screen: at once with 'platform' and 'none' (on Android 'none' keeps the splash until the root is drawn, however long it takes), over the splash with a preset or { enter, exit }. After a splash of your own, a first root without a transition of its own comes in with transition of splash, 'fade' by default.
All the animations: Transitions.
Over time
- The root is built at each switch. A
Root(…)inrootsis a description: eachswitchTomakes new screens from it, with new ids and fresh state. - A switch replaces everything under the overlays: the old root's screens unmount, its modals close, the overlays stay. See What a switch does.
- Android A new activity brings back the last root, without the screens pushed or presented over it: see When Android brings the app back.
See also
- Switching roots: roots,
switchTo, a root with a modal, transitions. createNavigation:root,rootsandinitialRoot.- Notifications: a screen opened by a notification at a cold start.