*/
import { RouterView } from '../src/RouterView'
import { components, RouteLocationNormalizedLoose } from './utils'
-import { START_LOCATION_NORMALIZED } from '../src/types'
+import {
+ START_LOCATION_NORMALIZED,
+ RouteLocationNormalized,
+} from '../src/types'
import { markRaw } from 'vue'
import { mount, createMockedRoute } from './mount'
import { mockWarn } from 'jest-mock-warn'
return nonReactiveRoutes
}
+const props = { default: false }
+
const routes = createRoutes({
root: {
fullPath: '/',
hash: '',
meta: {},
matched: [
- { components: { default: components.Home }, instances: {}, path: '/' },
+ {
+ components: { default: components.Home },
+ instances: {},
+ path: '/',
+ props,
+ },
],
},
foo: {
hash: '',
meta: {},
matched: [
- { components: { default: components.Foo }, instances: {}, path: '/foo' },
+ {
+ components: { default: components.Foo },
+ instances: {},
+ path: '/foo',
+ props,
+ },
],
},
nested: {
hash: '',
meta: {},
matched: [
- { components: { default: components.Nested }, instances: {}, path: '/' },
- { components: { default: components.Foo }, instances: {}, path: 'a' },
+ {
+ components: { default: components.Nested },
+ instances: {},
+ path: '/',
+ props,
+ },
+ {
+ components: { default: components.Foo },
+ instances: {},
+ path: 'a',
+ props,
+ },
],
},
nestedNested: {
hash: '',
meta: {},
matched: [
- { components: { default: components.Nested }, instances: {}, path: '/' },
- { components: { default: components.Nested }, instances: {}, path: 'a' },
- { components: { default: components.Foo }, instances: {}, path: 'b' },
+ {
+ components: { default: components.Nested },
+ instances: {},
+ path: '/',
+ props,
+ },
+ {
+ components: { default: components.Nested },
+ instances: {},
+ path: 'a',
+ props,
+ },
+ {
+ components: { default: components.Foo },
+ instances: {},
+ path: 'b',
+ props,
+ },
],
},
named: {
hash: '',
meta: {},
matched: [
- { components: { foo: components.Foo }, instances: {}, path: '/' },
+ { components: { foo: components.Foo }, instances: {}, path: '/', props },
],
},
withParams: {
instances: {},
path: '/users/:id',
- props: true,
+ props: { default: true },
},
],
},
instances: {},
path: '/props/:id',
- props: { id: 'foo', other: 'fixed' },
+ props: { default: { id: 'foo', other: 'fixed' } },
},
],
},
instances: {},
path: '/props/:id',
- props: to => ({ id: Number(to.params.id) * 2, other: to.query.q }),
+ props: {
+ default: (to: RouteLocationNormalized) => ({
+ id: Number(to.params.id) * 2,
+ other: to.query.q,
+ }),
+ },
},
],
},
components: { default: components.User },
instances: {},
path: '/users/:id',
+ props,
},
],
}
meta: {},
name: undefined,
path: '/home',
- props: false,
+ props: { default: false },
})
})
meta: { foo: true },
name: 'name',
path: '/home',
- props: false,
+ props: { default: false },
})
})
meta: { foo: true },
name: 'name',
path: '/home',
- props: false,
+ props: { one: false },
})
})
})
RouteComponent,
RouteRecordRaw,
RouteRecordName,
+ _RouteRecordProps,
} from '../src/types'
import { h, ComponentOptions } from 'vue'
import {
> {
leaveGuards?: any
instances: Record<string, any>
- props?: _RouteRecordBase['props']
+ props: Record<string, _RouteRecordProps>
aliasOf: RouteRecordViewLoose | undefined
}
{
path: '/',
components: { default: Home, other: component },
- props: to => ({ waited: to.meta.waitedFor }),
+ props: { default: to => ({ waited: to.meta.waitedFor }) },
},
{
path: '/always-redirect',
{
path: '/children',
name: 'WithChildren',
- component,
+ component: Nested,
children: [
- { path: '', alias: 'alias', name: 'default-child', component },
- { path: 'a', name: 'a-child', component },
+ { path: '', alias: 'alias', name: 'default-child', component: Nested },
+ { path: 'a', name: 'a-child', component: Nested },
{
path: 'b',
name: 'b-child',
- component,
+ component: Nested,
children: [
- { path: '', component },
- { path: 'a2', component },
- { path: 'b2', component },
+ { path: '', component: Nested },
+ { path: 'a2', component: Nested },
+ { path: 'b2', component: Nested },
],
},
],
<template>
<div>
<p>Nested level {{ level }}</p>
- <ul v-if="level === 1">
+ <ul v-if="level === 1 && $route.name === 'Nested'">
<li>
<router-link to="/nested/nested">/nested/nested</router-link>
</li>
const propsData = computed(() => {
// propsData only gets called if ViewComponent.value exists and it depends
// on matchedRoute.value
- const { props } = matchedRoute.value!
- if (!props) return {}
- if (props === true) return route.value.params
+ const componentProps = matchedRoute.value!.props[props.name]
+ if (!componentProps) return {}
+ // TODO: only add props declared in the component. all if no props
+ if (componentProps === true) return route.value.params
- return typeof props === 'object' ? props : props(route.value)
+ return typeof componentProps === 'object'
+ ? componentProps
+ : componentProps(route.value)
})
provide(matchedRouteKey, matchedRoute)
MatcherLocation,
isRouteName,
RouteRecordName,
+ _RouteRecordProps,
+ RouteRecordSingleView,
+ RouteRecordMultipleViews,
} from '../types'
import { createRouterError, ErrorTypes, MatcherError } from '../errors'
import { createRouteRecordMatcher, RouteRecordMatcher } from './pathMatcher'
redirect: record.redirect,
}
} else {
+ const components =
+ 'components' in record ? record.components : { default: record.component }
return {
...commonInitialValues,
beforeEnter: record.beforeEnter,
- props: record.props || false,
+ props: normalizeRecordProps(record),
children: record.children || [],
instances: {},
leaveGuards: [],
updateGuards: [],
- components:
- 'components' in record
- ? record.components
- : { default: record.component },
+ components,
}
}
}
+/**
+ * Normalize the optional `props` in a record to always be an object similar to
+ * components. Also accept a boolean for components.
+ * @param record
+ */
+function normalizeRecordProps(
+ record: RouteRecordSingleView | RouteRecordMultipleViews
+): Record<string, _RouteRecordProps> {
+ const propsObject = {} as Record<string, _RouteRecordProps>
+ const props = record.props || false
+ if ('component' in record) {
+ propsObject.default = props
+ } else {
+ // NOTE: we could also allow a function to be applied to every component.
+ // Would need user feedback for use cases
+ for (let name in record.components)
+ propsObject[name] = typeof props === 'boolean' ? props : props[name]
+ }
+
+ return propsObject
+}
+
/**
* Checks if a record or any of its parent is an alias
* @param record
NavigationGuard,
_RouteRecordBase,
RouteRecordRedirectRaw,
+ _RouteRecordProps,
} from '../types'
import { ComponentPublicInstance } from 'vue'
components: RouteRecordMultipleViews['components']
children: Exclude<RouteRecordMultipleViews['children'], void>
meta: Exclude<RouteRecordMultipleViews['meta'], void>
- props: Exclude<_RouteRecordBase['props'], void>
+ /**
+ * Object of props options with the same keys as `components`
+ */
+ props: Record<string, _RouteRecordProps>
beforeEnter: RouteRecordMultipleViews['beforeEnter']
leaveGuards: NavigationGuard[]
updateGuards: NavigationGuard[]
export type RouteRecordName = string | symbol
+/**
+ * @internal
+ */
+export type _RouteRecordProps =
+ | boolean
+ | Record<string, any>
+ | ((to: RouteLocationNormalized) => Record<string, any>)
+
// TODO: could this be moved to matcher?
/**
* Common properties among all kind of {@link RouteRecordRaw}
* Name for the route record.
*/
name?: RouteRecordName
- /**
- * Allow passing down params as props to the component rendered by `router-view`.
- */
- props?:
- | boolean
- | Record<string, any>
- | ((to: RouteLocationNormalized) => Record<string, any>)
/**
* Before Enter guard specific to this record. Note `beforeEnter` has no
* effect if the record has a `redirect` property.
export interface RouteRecordSingleView extends _RouteRecordBase {
component: RawRouteComponent
children?: RouteRecordRaw[]
+ /**
+ * Allow passing down params as props to the component rendered by `router-view`.
+ */
+ props?: _RouteRecordProps
}
export interface RouteRecordMultipleViews extends _RouteRecordBase {
components: Record<string, RawRouteComponent>
children?: RouteRecordRaw[]
+ /**
+ * Allow passing down params as props to the component rendered by
+ * `router-view`. Should be an object with the same keys as `components` or a
+ * boolean to be applied to every component.
+ */
+ props?: Record<string, _RouteRecordProps> | boolean
}
export type RouteRecordRaw =