From af86cd46ae82d5989d6139734289c13f9a953386 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Fri, 12 Feb 2021 11:44:10 -0500 Subject: [PATCH 1/2] remove old tabs setup --- packages/vue-router/src/viewStacks.ts | 22 +++++------- .../vue/src/components/IonRouterOutlet.ts | 35 ++++++------------- packages/vue/src/components/IonTabs.ts | 2 +- packages/vue/test-app/src/router/index.ts | 35 ------------------- packages/vue/test-app/tests/e2e/specs/tabs.js | 17 --------- .../vue/test-app/tests/unit/tab-bar.spec.ts | 6 ++-- 6 files changed, 21 insertions(+), 96 deletions(-) diff --git a/packages/vue-router/src/viewStacks.ts b/packages/vue-router/src/viewStacks.ts index 45bd6d31a06..bd34caa0273 100644 --- a/packages/vue-router/src/viewStacks.ts +++ b/packages/vue-router/src/viewStacks.ts @@ -22,16 +22,16 @@ export const createViewStacks = (router: Router) => { viewItem.ionRoute = true; } - const findViewItemByRouteInfo = (routeInfo: RouteInfo, outletId?: number, useDeprecatedRouteSetup: boolean = false) => { - return findViewItemByPath(routeInfo.pathname, outletId, false, useDeprecatedRouteSetup); + const findViewItemByRouteInfo = (routeInfo: RouteInfo, outletId?: number) => { + return findViewItemByPath(routeInfo.pathname, outletId, false); } - const findLeavingViewItemByRouteInfo = (routeInfo: RouteInfo, outletId?: number, mustBeIonRoute: boolean = true, useDeprecatedRouteSetup: boolean = false) => { - return findViewItemByPath(routeInfo.lastPathname, outletId, mustBeIonRoute, useDeprecatedRouteSetup); + const findLeavingViewItemByRouteInfo = (routeInfo: RouteInfo, outletId?: number, mustBeIonRoute: boolean = true) => { + return findViewItemByPath(routeInfo.lastPathname, outletId, mustBeIonRoute); } - const findViewItemByPathname = (pathname: string, outletId?: number, useDeprecatedRouteSetup: boolean = false) => { - return findViewItemByPath(pathname, outletId, false, useDeprecatedRouteSetup); + const findViewItemByPathname = (pathname: string, outletId?: number) => { + return findViewItemByPath(pathname, outletId, false); } const findViewItemInStack = (path: string, stack: ViewItem[]): ViewItem | undefined => { @@ -44,7 +44,7 @@ export const createViewStacks = (router: Router) => { }) } - const findViewItemByPath = (path: string, outletId?: number, mustBeIonRoute: boolean = false, useDeprecatedRouteSetup: boolean = false): ViewItem | undefined => { + const findViewItemByPath = (path: string, outletId?: number, mustBeIonRoute: boolean = false): ViewItem | undefined => { const matchView = (viewItem: ViewItem) => { if ( (mustBeIonRoute && !viewItem.ionRoute) || @@ -54,13 +54,7 @@ export const createViewStacks = (router: Router) => { } const resolvedPath = router.resolve(path); - let findMatchedRoute; - // TODO: Remove in Ionic Vue v6.0 - if (useDeprecatedRouteSetup) { - findMatchedRoute = resolvedPath.matched.find((matchedRoute: RouteLocationMatched) => matchedRoute === viewItem.matchedRoute && (path === viewItem.pathname || matchedRoute.path.includes(':'))); - } else { - findMatchedRoute = resolvedPath.matched.find((matchedRoute: RouteLocationMatched) => matchedRoute === viewItem.matchedRoute); - } + const findMatchedRoute = resolvedPath.matched.find((matchedRoute: RouteLocationMatched) => matchedRoute === viewItem.matchedRoute); if (findMatchedRoute) { return viewItem; diff --git a/packages/vue/src/components/IonRouterOutlet.ts b/packages/vue/src/components/IonRouterOutlet.ts index 7fdbb2bd9b6..36627bcb7c2 100644 --- a/packages/vue/src/components/IonRouterOutlet.ts +++ b/packages/vue/src/components/IonRouterOutlet.ts @@ -17,26 +17,11 @@ import { fireLifecycle, generateId, getConfig } from '../utils'; let viewDepthKey: InjectionKey<0> = Symbol(0); export const IonRouterOutlet = defineComponent({ name: 'IonRouterOutlet', - setup(_, { attrs }) { + setup() { const injectedRoute = inject(routeLocationKey)!; const route = useRoute(); const depth = inject(viewDepthKey, 0); - let usingDeprecatedRouteSetup = false; - - // TODO: Remove in Ionic Vue v6.0 - if (attrs.tabs && route.matched[depth]?.children?.length > 0) { - console.warn('[@ionic/vue Deprecation]: Your child routes are nested inside of each tab in your routing config. This format will not be supported in Ionic Vue v6.0. Instead, write your child routes as sibling routes. See https://ionicframework.com/docs/vue/navigation#child-routes-within-tabs for more information.'); - usingDeprecatedRouteSetup = true; - } - const matchedRouteRef: any = computed(() => { - const matchedRoute = route.matched[depth]; - - if (matchedRoute && attrs.tabs && route.matched[depth + 1] && usingDeprecatedRouteSetup) { - return route.matched[route.matched.length - 1]; - } - - return matchedRoute; - }); + const matchedRouteRef: any = computed(() => route.matched[depth]); provide(viewDepthKey, depth + 1) provide(matchedRouteKey, matchedRouteRef); @@ -83,15 +68,15 @@ export const IonRouterOutlet = defineComponent({ * to make sure the view is in the outlet we want. */ const routeInfo = ionRouter.getCurrentRouteInfo(); - const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id, usingDeprecatedRouteSetup); + const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id); return !!enteringViewItem; } const onStart = async () => { const routeInfo = ionRouter.getCurrentRouteInfo(); const { routerAnimation } = routeInfo; - const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id, usingDeprecatedRouteSetup); - const leavingViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id, usingDeprecatedRouteSetup); + const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id); + const leavingViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id); if (leavingViewItem) { let animationBuilder = routerAnimation; @@ -146,7 +131,7 @@ export const IonRouterOutlet = defineComponent({ * re-hide the page that was going to enter. */ const routeInfo = ionRouter.getCurrentRouteInfo(); - const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id, usingDeprecatedRouteSetup); + const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id); enteringViewItem.ionPageElement.setAttribute('aria-hidden', 'true'); enteringViewItem.ionPageElement.classList.add('ion-page-hidden'); } @@ -201,14 +186,14 @@ export const IonRouterOutlet = defineComponent({ const routeInfo = ionRouter.getCurrentRouteInfo(); const { routerDirection, routerAction, routerAnimation, prevRouteLastPathname } = routeInfo; - const enteringViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id, usingDeprecatedRouteSetup); - let leavingViewItem = viewStacks.findLeavingViewItemByRouteInfo(routeInfo, id, true, usingDeprecatedRouteSetup); + const enteringViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id); + let leavingViewItem = viewStacks.findLeavingViewItemByRouteInfo(routeInfo, id); const enteringEl = enteringViewItem.ionPageElement; if (enteringViewItem === leavingViewItem) return; if (!leavingViewItem && prevRouteLastPathname) { - leavingViewItem = viewStacks.findViewItemByPathname(prevRouteLastPathname, id, usingDeprecatedRouteSetup); + leavingViewItem = viewStacks.findViewItemByPathname(prevRouteLastPathname, id); } fireLifecycle(enteringViewItem.vueComponent, enteringViewItem.vueComponentRef, LIFECYCLE_WILL_ENTER); @@ -303,7 +288,7 @@ export const IonRouterOutlet = defineComponent({ } const currentRoute = ionRouter.getCurrentRouteInfo(); - let enteringViewItem = viewStacks.findViewItemByRouteInfo(currentRoute, id, usingDeprecatedRouteSetup); + let enteringViewItem = viewStacks.findViewItemByRouteInfo(currentRoute, id); if (!enteringViewItem) { enteringViewItem = viewStacks.createViewItem(id, matchedRouteRef.value.components.default, matchedRouteRef.value, currentRoute); diff --git a/packages/vue/src/components/IonTabs.ts b/packages/vue/src/components/IonTabs.ts index e292d530354..c3bf0d706bc 100644 --- a/packages/vue/src/components/IonTabs.ts +++ b/packages/vue/src/components/IonTabs.ts @@ -19,7 +19,7 @@ export const IonTabs = defineComponent({ 'contain': 'layout size style' } }, [ - h(IonRouterOutlet, { tabs: true }) + h(IonRouterOutlet) ]) ]; diff --git a/packages/vue/test-app/src/router/index.ts b/packages/vue/test-app/src/router/index.ts index 0ac97bdd765..cc80096b53a 100644 --- a/packages/vue/test-app/src/router/index.ts +++ b/packages/vue/test-app/src/router/index.ts @@ -83,41 +83,6 @@ const routes: Array = [ path: '', redirect: '/tabs/tab1' }, - { - path: 'tab1', - component: () => import('@/views/Tab1.vue'), - children: [ - { - path: 'child-one', - component: () => import('@/views/Tab1ChildOne.vue') - }, - { - path: 'child-two', - component: () => import('@/views/Tab1ChildTwo.vue') - } - ] - }, - { - path: 'tab2', - component: () => import('@/views/Tab2.vue') - }, - { - path: 'tab3', - beforeEnter: (to, from, next) => { - next({ path: '/tabs/tab1' }); - }, - component: () => import('@/views/Tab3.vue') - } - ] - }, - { - path: '/tabs-new/', - component: () => import('@/views/Tabs.vue'), - children: [ - { - path: '', - redirect: '/tabs-new/tab1' - }, { path: 'tab1', component: () => import('@/views/Tab1.vue'), diff --git a/packages/vue/test-app/tests/e2e/specs/tabs.js b/packages/vue/test-app/tests/e2e/specs/tabs.js index 020af3fa5ed..94e17af8ddd 100644 --- a/packages/vue/test-app/tests/e2e/specs/tabs.js +++ b/packages/vue/test-app/tests/e2e/specs/tabs.js @@ -190,23 +190,6 @@ describe('Tabs', () => { cy.ionPageVisible('tab2'); cy.ionPageVisible('tabs'); }); - - // Verifies 1 of 2 fixes for https://github.com/ionic-team/ionic-framework/issues/22519 - it('should not create a new tabs instance when switching between tabbed and non-tabbed contexts - new tabs setup', () => { - cy.visit('http://localhost:8080/tabs-new/tab1'); - - cy.routerPush('/'); - cy.ionPageHidden('tabs'); - cy.ionPageVisible('home'); - - cy.routerPush('/tabs-new/tab2'); - cy.ionPageHidden('tab1'); - - cy.ionPageHidden('home'); - - cy.ionPageVisible('tab2'); - cy.ionPageVisible('tabs'); - }); }) describe('Tabs - Swipe to Go Back', () => { diff --git a/packages/vue/test-app/tests/unit/tab-bar.spec.ts b/packages/vue/test-app/tests/unit/tab-bar.spec.ts index 38b99eef457..67a60a87c3c 100644 --- a/packages/vue/test-app/tests/unit/tab-bar.spec.ts +++ b/packages/vue/test-app/tests/unit/tab-bar.spec.ts @@ -68,8 +68,7 @@ describe('ion-tab-bar', () => { }); const innerHTML = wrapper.find('ion-tabs').html(); - // TODO: Remove tabs="true" in Ionic Vue v6.0 - expect(innerHTML).toContain(`
`); + expect(innerHTML).toContain(`
`); }); @@ -101,8 +100,7 @@ describe('ion-tab-bar', () => { }); const innerHTML = wrapper.find('ion-tabs').html(); - // TODO: Remove tabs="true" in Ionic Vue v6.0 - expect(innerHTML).toContain(`
`) + expect(innerHTML).toContain(`
`) }); // Verifies the fix for https://github.com/ionic-team/ionic-framework/issues/22642 From 577a3c8d7ffdfc59c26e2097a2303878626fd50b Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Fri, 12 Feb 2021 14:00:31 -0500 Subject: [PATCH 2/2] update breaking docs --- BREAKING.md | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/BREAKING.md b/BREAKING.md index 10fc6c9f5f1..b22070e3365 100644 --- a/BREAKING.md +++ b/BREAKING.md @@ -21,6 +21,8 @@ This is a comprehensive list of the breaking changes introduced in the major ver * [Transition Shadow](#transition-shadow) - [Angular](#angular) * [Config Provider](#config-provider) +- [Vue](#vue) + * [Tabs Config](#tabs-config) @@ -73,6 +75,88 @@ The `experimentalTransitionShadow` config option has been removed. The transitio The `Config.set()` method has been removed. See https://ionicframework.com/docs/angular/config for examples on how to set config globally, per-component, and per-platform. +### Vue + +#### Tabs Config + +Support for child routes nested inside of tabs has been removed to better conform to Vue Router's best practices. Additional routes should be written as sibling routes with the parent tab as the path prefix: + +**Old** +```typescript +const routes: Array = [ + { + path: '/', + redirect: '/tabs/tab1' + }, + { + path: '/tabs/', + component: Tabs, + children: [ + { + path: '', + redirect: 'tab1' + }, + { + path: 'tab1', + component: () => import('@/views/Tab1.vue'), + children: { + { + path: 'view', + component: () => import('@/views/Tab1View.vue') + } + } + }, + { + path: 'tab2', + component: () => import('@/views/Tab2.vue') + }, + { + path: 'tab3', + component: () => import('@/views/Tab3.vue') + } + ] + } +] +``` + +**New** +```typescript +const routes: Array = [ + { + path: '/', + redirect: '/tabs/tab1' + }, + { + path: '/tabs/', + component: Tabs, + children: [ + { + path: '', + redirect: 'tab1' + }, + { + path: 'tab1', + component: () => import('@/views/Tab1.vue') + }, + { + path: 'tab1/view', + component: () => import('@/views/Tab1View.vue') + }, + { + path: 'tab2', + component: () => import('@/views/Tab2.vue') + }, + { + path: 'tab3', + component: () => import('@/views/Tab3.vue') + } + ] + } +] +``` + +In the example above `tabs/tab1/view` has been rewritten has a sibling route to `tabs/tab1`. The `path` field now includes the `tab1` prefix. + ## Version 5.x