Skip to content

Commit f2045ab

Browse files
committed
feat: improved types for createNativeView, $showModal and $navigateTo
1 parent 9c26e6f commit f2045ab

File tree

8 files changed

+101
-56
lines changed

8 files changed

+101
-56
lines changed

demo/src/app.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ StackLayout {
55
Label {
66
/* background-color: rgb(0, 255, 0, 0.2); */
77
}
8+
9+
.modal {
10+
background-color: rgb(0, 0, 255, 0.2);
11+
}

demo/src/components/Home.vue

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@ import { ListItem, onMounted, onUnmounted } from 'nativescript-vue';
33
import { goHome } from '../composables/goHome';
44
import Test from './Test.vue';
55
6-
defineProps({
7-
depth: {
8-
type: Number,
9-
default: 0,
6+
withDefaults(
7+
defineProps<{
8+
depth?: number;
9+
title?: string;
10+
items?: (string | number)[];
11+
enabled?: boolean;
12+
}>(),
13+
{
14+
depth: 0,
1015
},
11-
});
16+
);
1217
1318
const message = 'Hello World!!';
1419
@@ -46,7 +51,10 @@ onUnmounted(() => {
4651
<Label class="info" :text="message + ' ' + depth" />
4752
<Button text="Go home" @tap="goHome(depth + 1)" />
4853
<Button text="Go home Modal" @tap="goHome(depth + 1, true)" />
49-
<Button text="Close Modal" @tap="$modal?.close({ depth, foo: 'bar' })" />
54+
<Button
55+
text="Close Modal"
56+
@tap="$modal?.close({ depth, foo: 'bar' }, 'arg1', 'arg2')"
57+
/>
5058

5159
<Test />
5260

@@ -62,6 +70,7 @@ onUnmounted(() => {
6270
)}\n\nindex: ${index} even: ${even} odd: ${odd}`"
6371
textWrap="true"
6472
padding="16"
73+
@tap="$emit('customEvent', { item, index, even, odd })"
6574
/>
6675
</template>
6776

@@ -73,6 +82,7 @@ onUnmounted(() => {
7382
)}\n\nindex: ${index} even: ${even} odd: ${odd}`"
7483
textWrap="true"
7584
padding="16"
85+
@tap="$emit('customEvent', { item, index, even, odd })"
7686
/>
7787
</template>
7888
</ListView>

demo/src/composables/goHome.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,35 @@
1-
import { $navigateTo, $showModal } from 'nativescript-vue';
1+
import { $navigateTo, $showModal, createNativeView, h } from 'nativescript-vue';
22
import Home from '../components/Home.vue';
33

4+
function test() {
5+
const home: typeof Home = Home;
6+
7+
createNativeView(Home, {});
8+
}
9+
410
export function goHome(depth = 0, modal = false) {
511
if (modal) {
6-
return $showModal(Home, {
12+
return $showModal<{
13+
strongTypeReturn: string;
14+
}>(Home, {
715
props: {
16+
onVnodeMounted(vnode) {
17+
// console.log('MODAL VNODE MOUNTED', vnode);
18+
},
19+
onCustomEvent(e) {
20+
console.log('MODAL CUSTOM EVENT', e);
21+
},
22+
class: 'modal',
823
depth,
924
},
10-
}).then((res) => {
11-
console.log('MODAL CLOSED', res);
25+
closeCallback(data, ...args) {
26+
console.log('MODAL CLOSE CALLBACK', data, ...args);
27+
},
28+
}).then((data) => {
29+
console.log('MODAL CLOSED DATA', data);
1230
});
1331
}
14-
$navigateTo(Home, {
32+
return $navigateTo(Home, {
1533
// clearHistory: true,
1634
props: {
1735
depth,

demo/types/shims.vue.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
declare module '*.vue' {
22
import type { DefineComponent } from 'nativescript-vue';
3-
const component: DefineComponent<{}, {}, any>;
3+
const component: DefineComponent;
44
export default component;
55
}

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export const createApp = ((...args) => {
7878

7979
app.registerElement = registerElement;
8080

81-
app.mount = (...args) => {
81+
app.mount = (...args: Parameters<typeof mount>) => {
8282
if (!args.length) {
8383
return mount(new NSVRoot(), false, false);
8484
}

src/plugins/modals.ts

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { Application, ShowModalOptions, View } from '@nativescript/core';
1+
import {
2+
Application,
3+
ShowModalOptions as CoreShowModalOptions,
4+
View,
5+
} from '@nativescript/core';
26
import {
37
App,
48
Component,
@@ -7,32 +11,32 @@ import {
711
unref,
812
warn,
913
} from '@vue/runtime-core';
10-
import { NSVElement, NSVRoot } from '../dom';
11-
import { createNativeView } from '../runtimeHelpers';
1214
import { isObject } from '@vue/shared';
15+
import { NSVElement, NSVRoot } from '../dom';
16+
import { CreateNativeViewProps, createNativeView } from '../runtimeHelpers';
1317

1418
declare module '@vue/runtime-core' {
1519
export interface ComponentCustomProperties {
16-
/**
17-
* todo: update docblock
18-
*/
19-
$showModal: <T = any>(
20-
component: Component,
21-
options?: ModalOptions,
20+
$showModal: <T = any, P = any>(
21+
component: Component<P>,
22+
options?: ShowModalOptions<P, T>,
2223
) => Promise<T | false | undefined>;
23-
$closeModal: (arg: any) => void;
24+
$closeModal: <T = any>(data: T, ...args: any[]) => void;
2425
$modal: {
25-
close: (arg: any) => void;
26+
close: <T = any>(data: T, ...args: any[]) => void;
2627
};
2728
}
2829
}
2930

3031
type ResolvableModalTarget = ComponentPublicInstance | NSVElement | View;
3132

32-
export interface ModalOptions extends Partial<ShowModalOptions> {
33-
props?: Record<string, any>;
33+
export type ShowModalOptions<P = any, T = any> = Partial<
34+
Omit<CoreShowModalOptions, 'closeCallback'>
35+
> & {
36+
closeCallback?: (data?: T, ...args: any[]) => void;
37+
props?: CreateNativeViewProps<P>;
3438
target?: ResolvableModalTarget;
35-
}
39+
};
3640

3741
/**
3842
* @internal
@@ -57,9 +61,9 @@ function resolveModalTarget(
5761
return false;
5862
}
5963

60-
export async function $showModal<T = any>(
61-
component: Component,
62-
options: ModalOptions = {},
64+
export async function $showModal<T = any, P = any>(
65+
component: Component<P>,
66+
options: ShowModalOptions<P, T> = {},
6367
): Promise<T | false | undefined> {
6468
const modalTarget = resolveModalTarget(
6569
options.target ?? Application.getRootView(),
@@ -87,7 +91,7 @@ export async function $showModal<T = any>(
8791
reload: reloadModal,
8892
});
8993

90-
const closeCallback = (data?: T) => {
94+
const closeCallback = (data?: T, ...args: any) => {
9195
if (isResolved) return;
9296

9397
if (isReloading) {
@@ -107,6 +111,10 @@ export async function $showModal<T = any>(
107111
view.unmount();
108112
view = null;
109113

114+
// call the closeCallback if it exists with all arguments
115+
options.closeCallback?.(data, ...args);
116+
117+
// resolve the promise with the first argument, since Promise.resolve() expects only one argument
110118
resolve(data);
111119
};
112120

@@ -118,7 +126,9 @@ export async function $showModal<T = any>(
118126
...additionalOptions,
119127
});
120128
};
121-
const closeModal = (...args: any[]) => view.nativeView?.closeModal(...args);
129+
const closeModal = (...args: any[]) => {
130+
view.nativeView?.closeModal(...args);
131+
};
122132

123133
view.context.config.globalProperties.$closeModal = closeModal;
124134
view.context.config.globalProperties.$modal = { close: closeModal };

src/plugins/navigation.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Frame, NavigationEntry, Page } from '@nativescript/core';
22
import { App, Component, Ref, nextTick, unref } from '@vue/runtime-core';
33
import { NSVElement, NSVRoot } from '../dom';
4-
import { createNativeView } from '../runtimeHelpers';
4+
import { CreateNativeViewProps, createNativeView } from '../runtimeHelpers';
55

66
declare module '@vue/runtime-core' {
77
export interface ComponentCustomProperties {
@@ -13,21 +13,24 @@ declare module '@vue/runtime-core' {
1313
* @param target
1414
* @param options
1515
*/
16-
$navigateTo: (target: Component, options?: NavigationOptions) => Page;
17-
$navigateBack: (options?: NavigationOptions) => void;
16+
$navigateTo: <P = any>(
17+
target: Component<P>,
18+
options?: NavigateToOptions<P>,
19+
) => Page;
20+
$navigateBack: (options?: NavigateBackOptions) => void;
1821
}
1922
}
2023

2124
type ResolvableFrame = string | Ref | NSVElement | Frame | undefined;
2225

23-
export interface NavigationOptions extends NavigationEntry {
24-
props?: Record<string, any>;
26+
export type NavigateToOptions<P = any> = NavigationEntry & {
27+
props?: CreateNativeViewProps<P>;
2528
frame?: ResolvableFrame;
26-
}
29+
};
2730

28-
export interface BackNavigationOptions {
31+
export type NavigateBackOptions = {
2932
frame?: ResolvableFrame;
30-
}
33+
};
3134

3235
/**
3336
* @internal
@@ -58,9 +61,9 @@ function resolveFrame(frame?: ResolvableFrame): Frame {
5861
return Frame.getFrameById(ob);
5962
}
6063

61-
export function $navigateTo(
62-
target: Component,
63-
options?: NavigationOptions,
64+
export function $navigateTo<P = any>(
65+
target: Component<P>,
66+
options?: NavigateToOptions<P>,
6467
): Page {
6568
try {
6669
const frame = resolveFrame(options?.frame);
@@ -145,7 +148,7 @@ export function $navigateTo(
145148
}
146149
}
147150

148-
export async function $navigateBack(options?: BackNavigationOptions) {
151+
export async function $navigateBack(options?: NavigateBackOptions) {
149152
const frame = resolveFrame(options?.frame);
150153

151154
if (!frame) {

src/runtimeHelpers.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,26 @@ import {
66
RendererElement,
77
RendererNode,
88
VNode,
9+
VNodeProps,
910
} from '@vue/runtime-core';
1011
import { NSVNode, NSVRoot } from './dom';
1112
import { renderer } from './renderer';
1213

13-
type Props = Record<string, unknown>;
14-
15-
const __DEV__ = true;
16-
1714
let rootApp: App = null;
18-
1915
export const setRootApp = (app: App) => {
2016
rootApp = app;
2117
};
2218

23-
export const createNativeView = <T = View>(
24-
component: Component,
25-
props?: Props,
26-
contextOverrides?: { reload?(): void },
27-
) => {
19+
export type ContextOverrides = { reload?(): void };
20+
export type CreateNativeViewProps<P> = Partial<
21+
P & VNodeProps & Record<string, any>
22+
>;
23+
24+
export function createNativeView<T = View, P = any>(
25+
component: Component<P>,
26+
props?: CreateNativeViewProps<P>,
27+
contextOverrides?: ContextOverrides,
28+
) {
2829
let isMounted = false;
2930
let vm: ComponentPublicInstance | null;
3031
const newApp = renderer.createApp(component, props);
@@ -33,7 +34,6 @@ export const createNativeView = <T = View>(
3334
const context = { ...rootContext, ...contextOverrides };
3435

3536
type M = VNode<RendererNode, RendererElement, { nativeView: T }>;
36-
3737
return {
3838
context,
3939
get vnode() {
@@ -66,7 +66,7 @@ export const createNativeView = <T = View>(
6666
isMounted = false;
6767
},
6868
};
69-
};
69+
}
7070

7171
export const ELEMENT_REF = Symbol(__DEV__ ? `elementRef` : ``);
7272

0 commit comments

Comments
 (0)