Skip to content

Commit

Permalink
feat(core): initial navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
rigor789 committed May 4, 2020
1 parent 44bef79 commit 18852c5
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 2 deletions.
18 changes: 17 additions & 1 deletion apps/demo/app/Comp.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import PageComp from '~/PageComp'
import { ref } from 'nativescript-vue'
export default {
template: `<ScrollView><StackLayout>
<ContentView borderWidth="2" borderColor="red">
<Frame id="testFrame" ref="testFrame" height="200">
</Frame>
</ContentView>
<SearchBar v-model="model" />
<Label :text="counter + ' ' + progress" />
<Label :text="time" />
Expand Down Expand Up @@ -33,9 +39,19 @@ export default {
watch: {
model(value) {
console.log('model change...!', value)
if (this.foo) {
this.foo.value = value
}
},
},
created() {
mounted() {
this.foo = ref(this.model)
this.$navigateTo(PageComp, {
frame: this.$refs.testFrame,
props: {
foo: this.foo,
},
})
// setInterval(() => this.counter++, 1000)
},
}
33 changes: 33 additions & 0 deletions apps/demo/app/PageComp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export default {
props: ['foo'],
template: `<Page><ActionBar title="SECOND PAGE"/><StackLayout>
<Label text="Hello World!"/>
<Label :text="foo.value"/>
<Label text="Hello World!"/>
<Label text="Hello World!"/>
</StackLayout></Page>`,
data() {
return {
key: 1,
counter: 0,
time: new Date(),
model: 'This is model 1',
progress: 50,
toggle: true,
}
},
watch: {
model(value) {
console.log('model change...!', value)
},
},
created() {
// this.$navigateTo(this, {
// clearHistory: true,
// props: {
// foo: 'bar'
// }
// })
// setInterval(() => this.counter++, 1000)
},
}
2 changes: 1 addition & 1 deletion apps/demo/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ function useInterval(cb, ms) {

const app = createApp({
render() {
return h('frame', h('page', h(Comp)))
return h({
template: `<Label verticalAlignment="middle" textAlignment="center"><FormattedString>
<Span text="Cool" />
Expand All @@ -79,7 +80,6 @@ const app = createApp({
</FormattedString></Label>`,
})
return h('GridLayout', h(ListViewComp))
return h(Comp)

const labelAt = (row, col) =>
h('Label', {
Expand Down
7 changes: 7 additions & 0 deletions packages/runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { debug } from '@nativescript-vue/shared'
import { nodeOps } from './nodeOps'
import { patchProp } from './patchProp'
import { INSVElement, NSVRoot } from './nodes'
import { install as NavigationPlugin } from './plugins/navigation'
import './registry'

const rendererOptions = {
Expand Down Expand Up @@ -56,6 +57,9 @@ export const createApp = ((...args) => {
return runApp(mount(nodeOps.createRoot()))
}

// Built-in plugins
app.use(NavigationPlugin)

return app
}) as CreateAppFunction<INSVElement>

Expand All @@ -65,6 +69,9 @@ export * from './runtimeHelpers'
export * from './registry'
export { resolveComponent } from './resolveAssets'

// Plugins
export { $navigateTo } from './plugins/navigation'

// runtime directive helpers
export { vModel } from './directives/vModel'
export { vShow } from './directives/vShow'
Expand Down
96 changes: 96 additions & 0 deletions packages/runtime/src/plugins/navigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { App, Component, h, isRef, nextTick, Ref } from '@vue/runtime-core'
import { Frame, NavigationEntry, Page } from '@nativescript/core'
import { nodeOps, NSVElement, render } from '@nativescript-vue/runtime'

declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
/**
* todo: update docblock
* Navigate to {target} component.
*
* The frame to navigate defaults to the topmost frame
* @param target
* @param options
*/
$navigateTo: (target: Component, options: any) => Promise<any>
}
}

export interface NavigateToOptions extends NavigationEntry {
props?: Record<string, any>
frame?: string | Ref | NSVElement | Frame
}

/**
* @internal
*/
export function install(app: App) {
app.config.globalProperties.$navigateTo = $navigateTo
}

function resolveFrame(frame: NavigateToOptions['frame']): Frame {
if (!frame) {
return Frame.topmost()
}

if (frame instanceof Frame) {
return frame
}

// todo: check if refs work this way or not
if (isRef(frame)) {
return frame.value
}

if (frame instanceof NSVElement) {
return frame.nativeView
}

// todo: either change core Frame to add frames to the stack when they are created
// or do as we did in 2.x - handle a Map of frames.
// right now, empty frames can't be navigated as they are not recognized by `getFrameById`
return Frame.getFrameById(frame)
}

async function waitForFrame(
frame: NavigateToOptions['frame'],
retries: number = 5
) {
let _frame = resolveFrame(frame)
while (!_frame && --retries > 0) {
await nextTick()
_frame = resolveFrame(frame)
}
return _frame
}

export async function $navigateTo(
target: Component,
options: NavigateToOptions
): Promise<Page> {
options = Object.assign({}, options)
console.log('$navigateTo')

try {
const frame = await waitForFrame(options.frame)

if (!frame) {
throw new Error('Failed to resolve frame. Make sure your frame exists.')
}

const root = nodeOps.createRoot()
render(h(target, options.props), root)

frame.navigate({
...options,
create() {
return (root.el!.nativeView as unknown) as Page
},
})
return (root.el!.nativeView as unknown) as Page
} catch (e) {
console.log('[$navigateTo] Failed to navigate:\n\n')
console.log(e)
throw e
}
}

0 comments on commit 18852c5

Please sign in to comment.