{ to: locations.basic.string },
locations.basic.normalized
)
- expect(el.innerHTML).toBe('<a href="/home">a link</a>')
+ expect(el.innerHTML).toBe('<a class="" href="/home">a link</a>')
})
it('displays a link with an object with path prop', () => {
{ to: { path: locations.basic.string } },
locations.basic.normalized
)
- expect(el.innerHTML).toBe('<a href="/home">a link</a>')
+ expect(el.innerHTML).toBe('<a class="" href="/home">a link</a>')
+ })
+
+ it('can be active', () => {
+ const { el } = factory(
+ locations.basic.normalized,
+ { to: locations.basic.string },
+ locations.basic.normalized
+ )
+ expect(el.innerHTML).toBe(
+ '<a class="router-link-active" href="/home">a link</a>'
+ )
})
it('calls ensureLocation', () => {
expect(router.push).toHaveBeenCalledTimes(1)
expect(router.push).toHaveBeenCalledWith(locations.basic.normalized)
})
+
+ describe('v-slot', () => {
+ function factory(
+ currentLocation: RouteLocationNormalized,
+ propsData: any,
+ resolvedLocation: RouteLocationNormalized
+ ) {
+ const router = {
+ history: createMemoryHistory(),
+ createHref(to: RouteLocationNormalized): string {
+ return this.history.base + to.fullPath
+ },
+ resolve: jest.fn(),
+ push: jest.fn().mockResolvedValue(resolvedLocation),
+ currentRoute: ref(markNonReactive(currentLocation)),
+ setActiveApp: jest.fn(),
+ }
+
+ router.resolve.mockReturnValueOnce(resolvedLocation)
+ const { app, el } = mount(router as any, {
+ template: `<RouterLink :to="to" v-slot="data">
+ route: {{ JSON.stringify(data.route) }}
+ href: "{{ data.href }}"
+ isActive: "{{ data.isActive }}"
+ </RouterLink>`,
+ components: { RouterLink } as any,
+ setup() {
+ const to = ref(propsData.to)
+
+ return { to }
+ },
+ })
+
+ return { app, router, el }
+ }
+
+ it('provides information on v-slot', () => {
+ const { el } = factory(
+ locations.basic.normalized,
+ { to: locations.basic.string },
+ locations.basic.normalized
+ )
+
+ expect(el.innerHTML).toMatchSnapshot()
+ })
+ })
})
import { defineComponent, h, PropType, inject } from '@vue/runtime-core'
-import { computed } from '@vue/reactivity'
-import { Router } from '../router'
+import { computed, reactive, isRef, Ref } from '@vue/reactivity'
import { RouteLocation } from '../types'
+export function useLink(to: Ref<RouteLocation> | RouteLocation) {
+ const router = inject('router')
+
+ const route = computed(() => router.resolve(isRef(to) ? to.value : to))
+ const href = computed(() => router.createHref(route.value))
+ const isActive = computed<boolean>(
+ () => router.currentRoute.value.path.indexOf(route.value.path) === 0
+ )
+
+ // TODO: handle replace prop
+
+ function navigate(e: MouseEvent) {
+ // TODO: handle navigate with empty parameters for scoped slot and composition api
+ if (guardEvent(e)) router.push(route.value)
+ }
+
+ return {
+ route,
+ href,
+ isActive,
+ navigate,
+ }
+}
+
const Link = defineComponent({
name: 'RouterLink',
props: {
},
},
- setup(props, context) {
- const router = inject<Router>('router')!
+ setup(props, { slots, attrs }) {
+ const { route, isActive, href, navigate } = useLink(props.to)
- const route = computed(() => router.resolve(props.to))
+ const elClass = computed(() => ({
+ 'router-link-active': isActive.value,
+ }))
- // TODO: active classes
+ // TODO: exact active classes
// TODO: handle replace prop
- const onClick = (e: MouseEvent) => {
- // TODO: handle navigate with empty parameters for scoped slot and composition api
- if (guardEvent(e)) {
- router.push(route.value)
- }
- }
-
- return () =>
- h(
+ return () => {
+ return h(
'a',
{
- onClick,
- href: router.createHref(route.value),
+ class: elClass.value,
+ onClick: navigate,
+ href: href.value,
+ ...attrs,
},
- context.slots.default()
+ slots.default(reactive({ route, href, isActive }))
)
+ }
},
})