From 3d6ac1382e23663a3d010fd253d3c6017d3923e4 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 7 Jan 2021 15:52:06 -0500 Subject: [PATCH 01/14] fix(vue): all ionic vue components can now use router link (#22743) --- core/package-lock.json | 19 ++++--- core/package.json | 2 +- core/stencil.config.ts | 7 --- packages/vue/src/proxies.ts | 25 ++------ packages/vue/src/vue-component-lib/utils.ts | 63 ++++++++++----------- 5 files changed, 46 insertions(+), 70 deletions(-) diff --git a/core/package-lock.json b/core/package-lock.json index 88e9f6a13b..30acf9ecaf 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -17,7 +17,7 @@ "@rollup/plugin-virtual": "^2.0.3", "@stencil/core": "2.1.2", "@stencil/sass": "1.3.2", - "@stencil/vue-output-target": "0.2.2", + "@stencil/vue-output-target": "0.2.3", "@types/jest": "^26.0.10", "@types/node": "^14.6.0", "@types/puppeteer": "3.0.1", @@ -1657,10 +1657,13 @@ "dev": true }, "node_modules/@stencil/vue-output-target": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.2.2.tgz", - "integrity": "sha512-WBnN/8ggIVYgKbJOML1DVzjFnKv7RaQpTa+XNeY0r/EG6MbXlUjUC/4Cpkg5wQ94WNuPpphAR4oRWGsmiQDxPQ==", - "dev": true + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.2.3.tgz", + "integrity": "sha512-jxFElPUVp56DHxLvYTvlnHMFnVQ0ITAUCLYfHvV8TY49PUbV5Gw1nYhhJQfpi5gJU2PPoWtIJjUGMsof8lmh6Q==", + "dev": true, + "peerDependencies": { + "@stencil/core": ">=1.8.0" + } }, "node_modules/@stylelint/postcss-css-in-js": { "version": "0.37.2", @@ -16387,9 +16390,9 @@ "dev": true }, "@stencil/vue-output-target": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.2.2.tgz", - "integrity": "sha512-WBnN/8ggIVYgKbJOML1DVzjFnKv7RaQpTa+XNeY0r/EG6MbXlUjUC/4Cpkg5wQ94WNuPpphAR4oRWGsmiQDxPQ==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.2.3.tgz", + "integrity": "sha512-jxFElPUVp56DHxLvYTvlnHMFnVQ0ITAUCLYfHvV8TY49PUbV5Gw1nYhhJQfpi5gJU2PPoWtIJjUGMsof8lmh6Q==", "dev": true }, "@stylelint/postcss-css-in-js": { diff --git a/core/package.json b/core/package.json index 7d925aa3f7..f5f1ed8e1e 100644 --- a/core/package.json +++ b/core/package.json @@ -38,7 +38,7 @@ "@rollup/plugin-virtual": "^2.0.3", "@stencil/core": "2.1.2", "@stencil/sass": "1.3.2", - "@stencil/vue-output-target": "0.2.2", + "@stencil/vue-output-target": "0.2.3", "@types/jest": "^26.0.10", "@types/node": "^14.6.0", "@types/puppeteer": "3.0.1", diff --git a/core/stencil.config.ts b/core/stencil.config.ts index 26c92213d8..bd1db3cddd 100644 --- a/core/stencil.config.ts +++ b/core/stencil.config.ts @@ -87,13 +87,6 @@ export const config: Config = { 'ion-app', 'ion-icon' ], - routerLinkComponents: [ - 'ion-card', - 'ion-item', - 'ion-button', - 'ion-fab-button', - - ], componentModels: [ { elements: ['ion-checkbox', 'ion-toggle'], diff --git a/packages/vue/src/proxies.ts b/packages/vue/src/proxies.ts index 42eaaa52d9..2b1e03b932 100644 --- a/packages/vue/src/proxies.ts +++ b/packages/vue/src/proxies.ts @@ -42,10 +42,7 @@ export const IonButton = /*@__PURE__*/ defineContainer('ion-butto 'type', 'ionFocus', 'ionBlur' -], -{ - "routerLinkComponent": true -}); +]); export const IonButtons = /*@__PURE__*/ defineContainer('ion-buttons', [ @@ -64,10 +61,7 @@ export const IonCard = /*@__PURE__*/ defineContainer('ion-card', [ 'routerDirection', 'routerAnimation', 'target' -], -{ - "routerLinkComponent": true -}); +]); export const IonCardContent = /*@__PURE__*/ defineContainer('ion-card-content'); @@ -195,10 +189,7 @@ export const IonFab = /*@__PURE__*/ defineContainer('ion-fab', [ 'vertical', 'edge', 'activated' -], -{ - "routerLinkComponent": true -}); +]); export const IonFabButton = /*@__PURE__*/ defineContainer('ion-fab-button', [ @@ -218,10 +209,7 @@ export const IonFabButton = /*@__PURE__*/ defineContainer('ion 'closeIcon', 'ionFocus', 'ionBlur' -], -{ - "routerLinkComponent": true -}); +]); export const IonFabList = /*@__PURE__*/ defineContainer('ion-fab-list', [ @@ -324,10 +312,7 @@ export const IonItem = /*@__PURE__*/ defineContainer('ion-item', [ 'routerDirection', 'target', 'type' -], -{ - "routerLinkComponent": true -}); +]); export const IonItemDivider = /*@__PURE__*/ defineContainer('ion-item-divider', [ diff --git a/packages/vue/src/vue-component-lib/utils.ts b/packages/vue/src/vue-component-lib/utils.ts index 5a8687251b..2a8e74b3b0 100644 --- a/packages/vue/src/vue-component-lib/utils.ts +++ b/packages/vue/src/vue-component-lib/utils.ts @@ -17,7 +17,6 @@ interface NavManager { interface ComponentOptions { modelProp?: string; modelUpdateEvent?: string; - routerLinkComponent?: boolean; } const getComponentClasses = (classes: unknown) => { @@ -41,7 +40,7 @@ const getElementClasses = (ref: Ref, componentClasses: * integrations. */ export const defineContainer = (name: string, componentProps: string[] = [], componentOptions: ComponentOptions = {}) => { - const { modelProp, modelUpdateEvent, routerLinkComponent } = componentOptions; + const { modelProp, modelUpdateEvent } = componentOptions; /** * Create a Vue component wrapper around a Web Component. @@ -60,24 +59,23 @@ export const defineContainer = (name: string, componentProps: string[] = } }; - let handleClick: (ev: Event) => void; - if (routerLinkComponent) { - const currentInstance = getCurrentInstance(); - const hasRouter = currentInstance?.appContext?.provides[NAV_MANAGER]; - const navManager: NavManager | undefined = hasRouter ? inject(NAV_MANAGER) : undefined; - handleClick = (ev: Event) => { - const routerProps = Object.keys(props).filter(p => p.startsWith(ROUTER_PROP_REFIX)); - if (routerProps.length === 0) return; + const currentInstance = getCurrentInstance(); + const hasRouter = currentInstance?.appContext?.provides[NAV_MANAGER]; + const navManager: NavManager | undefined = hasRouter ? inject(NAV_MANAGER) : undefined; + const handleRouterLink = (ev: Event) => { + const { routerLink } = props as any; + if (!routerLink) return; - if (navManager !== undefined) { - let navigationPayload: any = { event: ev }; - routerProps.forEach(prop => { - navigationPayload[prop] = (props as any)[prop]; - }); - navManager.navigate(navigationPayload); - } else { - console.warn('Tried to navigate, but no router was found. Make sure you have mounted Vue Router.'); - } + const routerProps = Object.keys(props).filter(p => p.startsWith(ROUTER_PROP_REFIX)); + + if (navManager !== undefined) { + let navigationPayload: any = { event: ev }; + routerProps.forEach(prop => { + navigationPayload[prop] = (props as any)[prop]; + }); + navManager.navigate(navigationPayload); + } else { + console.warn('Tried to navigate, but no router was found. Make sure you have mounted Vue Router.'); } } @@ -86,24 +84,24 @@ export const defineContainer = (name: string, componentProps: string[] = classes.add(value); }); + const oldClick = (props as any).onClick; + const handleClick = (ev: Event) => { + if (oldClick !== undefined) { + oldClick(ev); + } + if (!ev.defaultPrevented) { + handleRouterLink(ev); + } + } + let propsToAdd = { ...props, ref: containerRef, class: getElementClasses(containerRef, classes), - onClick: (routerLinkComponent) ? handleClick : (props as any).onClick, + onClick: handleClick, onVnodeBeforeMount: (modelUpdateEvent) ? onVnodeBeforeMount : undefined }; - if ((props as any).onClick) { - const oldClick = (props as any).onClick; - propsToAdd.onClick = (ev: Event) => { - oldClick(ev); - if (!ev.defaultPrevented) { - handleClick(ev); - } - }; - } - if (modelProp) { propsToAdd = { ...propsToAdd, @@ -116,14 +114,11 @@ export const defineContainer = (name: string, componentProps: string[] = }); Container.displayName = name; - Container.props = componentProps; + Container.props = [...componentProps, ROUTER_LINK_VALUE]; if (modelProp) { Container.props.push(MODEL_VALUE); Container.emits = [UPDATE_VALUE_EVENT]; } - if (routerLinkComponent) { - Container.props.push(ROUTER_LINK_VALUE); - } return Container; }; From 64719f49f979c0296a01827d3c02599a48ba93a6 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Fri, 8 Jan 2021 12:06:45 -0500 Subject: [PATCH 02/14] fix(vue): improve v-model binding sync between vue wrappers and web components (#22745) resolves #22731 --- core/package-lock.json | 14 +++++++------- core/package.json | 2 +- packages/vue/src/vue-component-lib/utils.ts | 6 ++++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/core/package-lock.json b/core/package-lock.json index 30acf9ecaf..9f78c88cee 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -17,7 +17,7 @@ "@rollup/plugin-virtual": "^2.0.3", "@stencil/core": "2.1.2", "@stencil/sass": "1.3.2", - "@stencil/vue-output-target": "0.2.3", + "@stencil/vue-output-target": "^0.2.4", "@types/jest": "^26.0.10", "@types/node": "^14.6.0", "@types/puppeteer": "3.0.1", @@ -1657,9 +1657,9 @@ "dev": true }, "node_modules/@stencil/vue-output-target": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.2.3.tgz", - "integrity": "sha512-jxFElPUVp56DHxLvYTvlnHMFnVQ0ITAUCLYfHvV8TY49PUbV5Gw1nYhhJQfpi5gJU2PPoWtIJjUGMsof8lmh6Q==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.2.4.tgz", + "integrity": "sha512-wtDIYXrOI3bVLfsTFg0uigcwlu+XI20gHy4lpA9C54jP7JOw9LDtczR+LaCAKNSTWczBBEgehRYREpDFvpS1qw==", "dev": true, "peerDependencies": { "@stencil/core": ">=1.8.0" @@ -16390,9 +16390,9 @@ "dev": true }, "@stencil/vue-output-target": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.2.3.tgz", - "integrity": "sha512-jxFElPUVp56DHxLvYTvlnHMFnVQ0ITAUCLYfHvV8TY49PUbV5Gw1nYhhJQfpi5gJU2PPoWtIJjUGMsof8lmh6Q==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.2.4.tgz", + "integrity": "sha512-wtDIYXrOI3bVLfsTFg0uigcwlu+XI20gHy4lpA9C54jP7JOw9LDtczR+LaCAKNSTWczBBEgehRYREpDFvpS1qw==", "dev": true }, "@stylelint/postcss-css-in-js": { diff --git a/core/package.json b/core/package.json index f5f1ed8e1e..1e315f0338 100644 --- a/core/package.json +++ b/core/package.json @@ -38,7 +38,7 @@ "@rollup/plugin-virtual": "^2.0.3", "@stencil/core": "2.1.2", "@stencil/sass": "1.3.2", - "@stencil/vue-output-target": "0.2.3", + "@stencil/vue-output-target": "^0.2.4", "@types/jest": "^26.0.10", "@types/node": "^14.6.0", "@types/puppeteer": "3.0.1", diff --git a/packages/vue/src/vue-component-lib/utils.ts b/packages/vue/src/vue-component-lib/utils.ts index 2a8e74b3b0..130f36a028 100644 --- a/packages/vue/src/vue-component-lib/utils.ts +++ b/packages/vue/src/vue-component-lib/utils.ts @@ -48,13 +48,15 @@ export const defineContainer = (name: string, componentProps: string[] = * They refer to whatever properties are set on an instance of a component. */ const Container = defineComponent((props, { attrs, slots, emit }) => { + let modelPropValue = (props as any)[modelProp]; const containerRef = ref(); const classes = new Set(getComponentClasses(attrs.class)); const onVnodeBeforeMount = (vnode: VNode) => { // Add a listener to tell Vue to update the v-model if (vnode.el) { vnode.el.addEventListener(modelUpdateEvent.toLowerCase(), (e: Event) => { - emit(UPDATE_VALUE_EVENT, (e?.target as any)[modelProp]); + modelPropValue = (e?.target as any)[modelProp]; + emit(UPDATE_VALUE_EVENT, modelPropValue); }); } }; @@ -105,7 +107,7 @@ export const defineContainer = (name: string, componentProps: string[] = if (modelProp) { propsToAdd = { ...propsToAdd, - [modelProp]: props.hasOwnProperty('modelValue') ? props.modelValue : (props as any)[modelProp] + [modelProp]: props.hasOwnProperty('modelValue') ? props.modelValue : modelPropValue } } From 9e9a3724979e95f3df1a340be21d16d8664a013c Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Wed, 13 Jan 2021 10:10:44 -0500 Subject: [PATCH 03/14] fix(react, vue): do not show back button when replacing to root page (#22750) resolves #22528 --- .../react-router/src/ReactRouter/IonRouter.tsx | 11 ++++++++++- packages/vue-router/src/router.ts | 11 ++++++++++- packages/vue/test-app/src/views/Home.vue | 7 ++++++- packages/vue/test-app/tests/e2e/specs/routing.js | 15 +++++++++++++++ .../vue/test-app/tests/e2e/support/commands.js | 15 ++++++++++++++- 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/packages/react-router/src/ReactRouter/IonRouter.tsx b/packages/react-router/src/ReactRouter/IonRouter.tsx index 7f4023bedb..8be9490061 100644 --- a/packages/react-router/src/ReactRouter/IonRouter.tsx +++ b/packages/react-router/src/ReactRouter/IonRouter.tsx @@ -174,9 +174,18 @@ class IonRouterInner extends React.PureComponent { } else if (routeInfo.routeAction === 'replace') { // Make sure to set the lastPathname, etc.. to the current route so the page transitions out const currentRouteInfo = this.locationHistory.current(); + + /** + * If going from /home to /child, then replacing from + * /child to /home, we don't want the route info to + * say that /home was pushed by /home which is not correct. + */ + const currentPushedBy = currentRouteInfo?.pushedByRoute; + const pushedByRoute = (currentPushedBy !== undefined && currentPushedBy !== routeInfo.pathname) ? currentPushedBy : routeInfo.pushedByRoute; + routeInfo.lastPathname = currentRouteInfo?.pathname || routeInfo.lastPathname; routeInfo.prevRouteLastPathname = currentRouteInfo?.lastPathname; - routeInfo.pushedByRoute = currentRouteInfo?.pushedByRoute || routeInfo.pushedByRoute; + routeInfo.pushedByRoute = pushedByRoute; routeInfo.routeDirection = currentRouteInfo?.routeDirection || routeInfo.routeDirection; routeInfo.routeAnimation = currentRouteInfo?.routeAnimation || routeInfo.routeAnimation; } diff --git a/packages/vue-router/src/router.ts b/packages/vue-router/src/router.ts index 756fd95eba..a84ae558fe 100644 --- a/packages/vue-router/src/router.ts +++ b/packages/vue-router/src/router.ts @@ -202,8 +202,17 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => routeInfo.pushedByRoute = lastRoute?.pushedByRoute; } else if (routeInfo.routerAction === 'replace') { const currentRouteInfo = locationHistory.current(); + + /** + * If going from /home to /child, then replacing from + * /child to /home, we don't want the route info to + * say that /home was pushed by /home which is not correct. + */ + const currentPushedBy = currentRouteInfo?.pushedByRoute; + const pushedByRoute = (currentPushedBy !== undefined && currentPushedBy !== routeInfo.pathname) ? currentPushedBy : routeInfo.pushedByRoute; + routeInfo.lastPathname = currentRouteInfo?.pathname || routeInfo.lastPathname; - routeInfo.pushedByRoute = currentRouteInfo?.pushedByRoute || routeInfo.pushedByRoute; + routeInfo.pushedByRoute = pushedByRoute; routeInfo.routerDirection = currentRouteInfo?.routerDirection || routeInfo.routerDirection; routeInfo.routerAnimation = currentRouteInfo?.routerAnimation || routeInfo.routerAnimation; routeInfo.prevRouteLastPathname = currentRouteInfo?.lastPathname; diff --git a/packages/vue/test-app/src/views/Home.vue b/packages/vue/test-app/src/views/Home.vue index 3366c171d9..e09d0a3b96 100644 --- a/packages/vue/test-app/src/views/Home.vue +++ b/packages/vue/test-app/src/views/Home.vue @@ -2,6 +2,9 @@ + + + Test App @@ -54,12 +57,14 @@