Repository navigation
Expand file tree
/
Copy pathnavigation.ts
More file actions
139 lines (115 loc) · 4.77 KB
/
Copy pathnavigation.ts
File metadata and controls
139 lines (115 loc) · 4.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import { topmost, NavigationTransition, Frame, Page, BackstackEntry, ViewBase, NavigatedData, View } from "tns-core-modules/ui/frame";
import FrameElement from "./native/FrameElement";
import { createElement, logger as log } from "./basicdom";
import PageElement from "./native/PageElement";
import NativeViewElementNode from "./native/NativeViewElementNode";
export type FrameSpec = Frame | FrameElement | string
export type PageSpec = typeof SvelteComponent;
export interface NavigationOptions {
page: PageSpec;
props?: any;
frame?: FrameSpec;
animated?: boolean;
backstackVisible?: boolean;
clearHistory?: boolean;
transition?: NavigationTransition;
transitionAndroid?: NavigationTransition;
transitioniOS?: NavigationTransition;
}
function resolveFrame(frameSpec: FrameSpec): Frame {
let targetFrame: Frame;
if (!frameSpec) targetFrame = topmost();
if (frameSpec instanceof FrameElement) targetFrame = frameSpec.nativeView as Frame;
if (frameSpec instanceof Frame) targetFrame = frameSpec;
if (typeof frameSpec == "string") {
targetFrame = Frame.getFrameById(frameSpec)
if (!targetFrame) log.error(`Navigate could not find frame with id ${frameSpec}`)
}
return targetFrame;
}
interface ComponentInstanceInfo { element: NativeViewElementNode<View>, pageInstance: SvelteComponent }
function resolveComponentElement(pageSpec: PageSpec, props?: any): ComponentInstanceInfo {
let dummy = createElement('fragment');
let pageInstance = new pageSpec({ target: dummy, props: props });
let element = dummy.firstElement() as NativeViewElementNode<View>;
return { element, pageInstance }
}
export function navigate(options: NavigationOptions): SvelteComponent {
let { frame, page, props = {}, ...navOptions } = options;
let targetFrame = resolveFrame(frame);
if (!targetFrame) {
throw new Error("navigate requires frame option to be a native Frame, a FrameElement, a frame Id, or null")
}
if (!page) {
throw new Error("navigate requires page to be set to the svelte component class that implements the page or reference to a page element")
}
let { element, pageInstance } = resolveComponentElement(page, props);
if (!(element instanceof PageElement))
throw new Error("navigate requires a svelte component with a page element at the root")
let nativePage = element.nativeView;
const handler = (args: NavigatedData) => {
if (args.isBackNavigation) {
nativePage.off('navigatedFrom', handler)
pageInstance.$destroy()
}
}
nativePage.on('navigatedFrom', handler)
targetFrame.navigate({
...navOptions,
create: () => nativePage
});
return pageInstance;
}
export interface BackNavigationOptions {
frame?: FrameSpec;
to?: PageElement;
}
export function goBack(options: BackNavigationOptions = {}) {
let targetFrame = resolveFrame(options.frame);
if (!targetFrame) {
throw new Error("goback requires frame option to be a native Frame, a FrameElement, a frame Id, or null")
}
let backStackEntry: BackstackEntry = null;
if (options.to) {
backStackEntry = targetFrame.backStack.find(e => e.resolvedPage === options.to.nativeView);
if (!backStackEntry) {
throw new Error("Couldn't find the destination page in the frames backstack")
}
}
return targetFrame.goBack(backStackEntry);
}
export interface ShowModalOptions {
page: PageSpec
props?: any
android?: { cancelable: boolean }
ios?: { presentationStyle: any }
animated?: boolean
fullscreen?: boolean
stretched: boolean
}
const modalStack: ComponentInstanceInfo[] = []
export function showModal<T>(modalOptions: ShowModalOptions): Promise<T> {
let { page, props = {}, ...options } = modalOptions;
//Get this before any potential new frames are created by component below
let modalLauncher = topmost().currentPage;
let componentInstanceInfo = resolveComponentElement(page, props);
let modalView: ViewBase = componentInstanceInfo.element.nativeView;
return new Promise((resolve, reject) => {
let resolved = false;
const closeCallback = (result: T) => {
if (resolved) return;
resolved = true;
try {
componentInstanceInfo.pageInstance.$destroy(); //don't let an exception in destroy kill the promise callback
} finally {
resolve(result);
}
}
modalStack.push(componentInstanceInfo);
modalLauncher.showModal(modalView, { ...options, context: {}, closeCallback })
});
}
export function closeModal(result: any): void {
let modalPageInstanceInfo = modalStack.pop();
modalPageInstanceInfo.element.nativeView.closeModal(result);
}