mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-17 10:41:13 +08:00
chore(): resolve merge conflicts
This commit is contained in:
38
packages/vue/package-lock.json
generated
38
packages/vue/package-lock.json
generated
@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/vue",
|
||||
"version": "5.6.3",
|
||||
"version": "5.6.5",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/vue",
|
||||
"version": "5.6.3",
|
||||
"version": "5.6.5",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "5.6.2",
|
||||
"@ionic/core": "5.6.4",
|
||||
"ionicons": "^5.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -53,13 +53,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.6.2.tgz",
|
||||
"integrity": "sha512-hnwd6ln0IZUVfFu2ilZK03b6EdQFqEWiTkL5kayq2gjB3BK/u1IEtV3C9fdwc8NJKopGwdbdQnujj6VhYPzV3Q==",
|
||||
"version": "5.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.6.4.tgz",
|
||||
"integrity": "sha512-fxCV/+0ibiaiBn1dsrrOmlLGJlTkqiG6IVXdLpPKimGdFLjy56olDvB5trlz9J5C/nHc7vR5MIiYC0qdTyX7og==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^2.4.0",
|
||||
"ionicons": "^5.5.1",
|
||||
"tslib": "^1.10.0"
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/core/node_modules/@stencil/core": {
|
||||
@ -74,6 +74,11 @@
|
||||
"npm": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/core/node_modules/tslib": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
|
||||
},
|
||||
"node_modules/@stencil/core": {
|
||||
"version": "1.17.3",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-1.17.3.tgz",
|
||||
@ -536,7 +541,8 @@
|
||||
"node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.0.5",
|
||||
@ -627,19 +633,24 @@
|
||||
}
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.6.2.tgz",
|
||||
"integrity": "sha512-hnwd6ln0IZUVfFu2ilZK03b6EdQFqEWiTkL5kayq2gjB3BK/u1IEtV3C9fdwc8NJKopGwdbdQnujj6VhYPzV3Q==",
|
||||
"version": "5.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.6.4.tgz",
|
||||
"integrity": "sha512-fxCV/+0ibiaiBn1dsrrOmlLGJlTkqiG6IVXdLpPKimGdFLjy56olDvB5trlz9J5C/nHc7vR5MIiYC0qdTyX7og==",
|
||||
"requires": {
|
||||
"@stencil/core": "^2.4.0",
|
||||
"ionicons": "^5.5.1",
|
||||
"tslib": "^1.10.0"
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@stencil/core": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.4.0.tgz",
|
||||
"integrity": "sha512-gU6+Yyd6O0KrCSS/O6j8KKqmRo+/Dcs2fI0+APCpbAWK+nqhwDISpdnSEfGDCLMoAC08XOZCycBRk2K1VGnEcg=="
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1050,7 +1061,8 @@
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.0.5",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/vue",
|
||||
"version": "5.6.3",
|
||||
"version": "5.6.5",
|
||||
"description": "Vue specific wrapper for @ionic/core",
|
||||
"scripts": {
|
||||
"lint": "echo add linter",
|
||||
@ -57,7 +57,7 @@
|
||||
"vue-router": "^4.0.0-rc.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "5.6.3",
|
||||
"@ionic/core": "5.6.5",
|
||||
"ionicons": "^5.1.2"
|
||||
},
|
||||
"vetur": {
|
||||
|
@ -40,16 +40,31 @@ export const IonRouterOutlet = defineComponent({
|
||||
// The base url for this router outlet
|
||||
let parentOutletPath: string;
|
||||
|
||||
watch(matchedRouteRef, (currentValue, previousValue) => {
|
||||
/**
|
||||
* We need to watch the route object
|
||||
* to listen for navigation changes.
|
||||
* Previously we had watched matchedRouteRef,
|
||||
* but if you had a /page/:id route, going from
|
||||
* page/1 to page/2 would not cause this callback
|
||||
* to fire since the matchedRouteRef was the same.
|
||||
*/
|
||||
watch([route, matchedRouteRef], ([currentRoute, currentMatchedRouteRef], [_, previousMatchedRouteRef]) => {
|
||||
/**
|
||||
* We need to make sure that we are not re-rendering
|
||||
* the same view if navigation changes in a sub-outlet.
|
||||
* This is mainly for tabs when outlet 1 renders ion-tabs
|
||||
* and outlet 2 renders the individual tab view. We don't
|
||||
* want outlet 1 creating a new ion-tabs instance every time
|
||||
* we switch tabs.
|
||||
* If the matched route ref has changed,
|
||||
* then we need to set up a new view item.
|
||||
* If the matched route ref has not changed,
|
||||
* it is possible that this is a parameterized URL
|
||||
* change such as /page/1 to /page/2. In that case,
|
||||
* we can assume that the `route` object has changed,
|
||||
* but we should only set up a new view item in this outlet
|
||||
* if that last matched view item matches our current matched
|
||||
* view item otherwise if we had this in a nested outlet the
|
||||
* parent outlet would re-render as well as the child page.
|
||||
*/
|
||||
if (currentValue !== previousValue) {
|
||||
if (
|
||||
currentMatchedRouteRef !== previousMatchedRouteRef ||
|
||||
currentRoute.matched[currentRoute.matched.length - 1] === currentMatchedRouteRef
|
||||
) {
|
||||
setupViewItem(matchedRouteRef);
|
||||
}
|
||||
});
|
||||
|
@ -11,30 +11,53 @@ interface Tab {
|
||||
ref: VNode
|
||||
}
|
||||
|
||||
const isTabButton = (child: any) => child.type?.name === 'IonTabButton';
|
||||
|
||||
const getTabs = (nodes: VNode[]) => {
|
||||
let tabs: VNode[] = [];
|
||||
nodes.forEach((node: VNode) => {
|
||||
if (isTabButton(node)) {
|
||||
tabs.push(node);
|
||||
} else if (Array.isArray(node.children) && node.children.length > 1) {
|
||||
const childTabs = getTabs(node.children as VNode[]);
|
||||
tabs = [...tabs, ...childTabs];
|
||||
}
|
||||
});
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
export const IonTabBar = defineComponent({
|
||||
name: 'IonTabBar',
|
||||
props: {
|
||||
_tabsWillChange: { type: Function, default: () => {} },
|
||||
_tabsDidChange: { type: Function, default: () => {} }
|
||||
},
|
||||
mounted() {
|
||||
const ionRouter: any = inject('navManager');
|
||||
const tabState: TabState = {
|
||||
data() {
|
||||
return {
|
||||
tabState: {
|
||||
activeTab: undefined,
|
||||
tabs: {}
|
||||
};
|
||||
const currentInstance = getCurrentInstance();
|
||||
const isTabButton = (child: any) => child.type?.name === 'IonTabButton';
|
||||
/**
|
||||
* For each tab, we need to keep track of its
|
||||
* base href as well as any child page that
|
||||
* is active in its stack so that when we go back
|
||||
* to a tab from another tab, we can correctly
|
||||
* show any child pages if necessary.
|
||||
*/
|
||||
const children = (currentInstance.subTree.children || []) as VNode[];
|
||||
children.forEach((child: VNode) => {
|
||||
if (isTabButton(child)) {
|
||||
},
|
||||
tabVnodes: []
|
||||
}
|
||||
},
|
||||
updated() {
|
||||
this.setupTabState(inject('navManager'));
|
||||
},
|
||||
methods: {
|
||||
setupTabState(ionRouter: any) {
|
||||
/**
|
||||
* For each tab, we need to keep track of its
|
||||
* base href as well as any child page that
|
||||
* is active in its stack so that when we go back
|
||||
* to a tab from another tab, we can correctly
|
||||
* show any child pages if necessary.
|
||||
*/
|
||||
const tabState: TabState = this.$data.tabState;
|
||||
const currentInstance = getCurrentInstance();
|
||||
const tabs = this.$data.tabVnodes = getTabs((currentInstance.subTree.children || []) as VNode[]);
|
||||
tabs.forEach(child => {
|
||||
tabState.tabs[child.props.tab] = {
|
||||
originalHref: child.props.href,
|
||||
currentHref: child.props.href,
|
||||
@ -47,12 +70,15 @@ export const IonTabBar = defineComponent({
|
||||
* ion-tab-bar is managing for it.
|
||||
*/
|
||||
child.component.props._getTabState = () => tabState;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const checkActiveTab = (currentRoute: any) => {
|
||||
const childNodes = (currentInstance.subTree.children || []) as VNode[];
|
||||
const { tabs, activeTab: prevActiveTab } = tabState;
|
||||
this.checkActiveTab(ionRouter);
|
||||
},
|
||||
checkActiveTab(ionRouter: any) {
|
||||
const currentRoute = ionRouter.getCurrentRouteInfo();
|
||||
const childNodes = this.$data.tabVnodes;
|
||||
const { tabs, activeTab: prevActiveTab } = this.$data.tabState;
|
||||
const tabState = this.$data.tabState;
|
||||
const tabKeys = Object.keys(tabs);
|
||||
const activeTab = tabKeys
|
||||
.find(key => {
|
||||
@ -66,21 +92,19 @@ export const IonTabBar = defineComponent({
|
||||
* it in the tabs state.
|
||||
*/
|
||||
childNodes.forEach((child: VNode) => {
|
||||
if (isTabButton(child)) {
|
||||
const tab = tabs[child.props.tab];
|
||||
if (!tab || (tab.originalHref !== child.props.href)) {
|
||||
const tab = tabs[child.props.tab];
|
||||
if (!tab || (tab.originalHref !== child.props.href)) {
|
||||
|
||||
tabs[child.props.tab] = {
|
||||
originalHref: child.props.href,
|
||||
currentHref: child.props.href,
|
||||
ref: child
|
||||
}
|
||||
tabs[child.props.tab] = {
|
||||
originalHref: child.props.href,
|
||||
currentHref: child.props.href,
|
||||
ref: child
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (activeTab && prevActiveTab) {
|
||||
const prevHref = tabState.tabs[prevActiveTab].currentHref;
|
||||
const prevHref = this.$data.tabState.tabs[prevActiveTab].currentHref;
|
||||
/**
|
||||
* If the tabs change or the url changes,
|
||||
* update the currentHref for the active tab.
|
||||
@ -128,10 +152,14 @@ export const IonTabBar = defineComponent({
|
||||
tabBar.selectedTab = tabState.activeTab = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const ionRouter: any = inject('navManager');
|
||||
|
||||
ionRouter.registerHistoryChangeListener(checkActiveTab.bind(this));
|
||||
checkActiveTab(ionRouter.getCurrentRouteInfo());
|
||||
this.setupTabState(ionRouter);
|
||||
|
||||
ionRouter.registerHistoryChangeListener(() => this.checkActiveTab(ionRouter));
|
||||
},
|
||||
setup(_, { slots }) {
|
||||
return () => {
|
||||
|
@ -1,37 +1,72 @@
|
||||
import { defineComponent, h, ref, VNode, getCurrentInstance } from 'vue';
|
||||
import { defineComponent, h, ref, VNode, getCurrentInstance, ComponentInternalInstance } from 'vue';
|
||||
import { needsKebabCase } from '../utils';
|
||||
|
||||
export interface OverlayProps {
|
||||
isOpen?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure we only
|
||||
* warn user about each
|
||||
* event at most once.
|
||||
*/
|
||||
let willPresentWarn = false;
|
||||
let didPresentWarn = false;
|
||||
let willDismissWarn = false;
|
||||
let didDismissWarn = false;
|
||||
|
||||
const checkForDeprecatedListeners = (instance: ComponentInternalInstance) => {
|
||||
const props = instance.vnode.props;
|
||||
if (!willPresentWarn && props.onOnWillPresent !== undefined) {
|
||||
console.warn('[@ionic/vue Deprecation]: @onWillPresent has been deprecated in favor of @willPresent and will be removed in Ionic Vue v6.0.');
|
||||
willPresentWarn = true;
|
||||
}
|
||||
|
||||
if (!didPresentWarn && props.onOnDidPresent !== undefined) {
|
||||
console.warn('[@ionic/vue Deprecation]: @onDidPresent has been deprecated in favor of @didPresent and will be removed in Ionic Vue v6.0.');
|
||||
didPresentWarn = true;
|
||||
}
|
||||
|
||||
if (!willDismissWarn && props.onOnWillDismiss !== undefined) {
|
||||
console.warn('[@ionic/vue Deprecation]: @onWillDismiss has been deprecated in favor of @willDismiss and will be removed in Ionic Vue v6.0.');
|
||||
willDismissWarn = true;
|
||||
}
|
||||
|
||||
if (!didDismissWarn && props.onOnDidDismiss !== undefined) {
|
||||
console.warn('[@ionic/vue Deprecation]: @onDidDismiss has been deprecated in favor of @didDismiss and will be removed in Ionic Vue v6.0.');
|
||||
didDismissWarn = true;
|
||||
}
|
||||
}
|
||||
|
||||
export const defineOverlayContainer = <Props extends object>(name: string, componentProps: string[] = [], controller: any) => {
|
||||
/**
|
||||
* Vue 3.0.6 fixed a bug where events on custom elements
|
||||
* were always converted to lower case, so "ionRefresh"
|
||||
* became "ionRefresh". We need to account for the old
|
||||
* became "ionrefresh". We need to account for the old
|
||||
* issue as well as the new behavior where "ionRefresh"
|
||||
* is converted to "ion-refresh".
|
||||
* See https://github.com/vuejs/vue-next/pull/2847
|
||||
*/
|
||||
const eventPrefix = name.toLowerCase().split('-').join('');
|
||||
const lowerCaseListeners = [
|
||||
{ componentEv: `${eventPrefix}willpresent`, frameworkEv: 'onWillPresent' },
|
||||
{ componentEv: `${eventPrefix}didpresent`, frameworkEv: 'onDidPresent' },
|
||||
{ componentEv: `${eventPrefix}willdismiss`, frameworkEv: 'onWillDismiss' },
|
||||
{ componentEv: `${eventPrefix}diddismiss`, frameworkEv: 'onDidDismiss' },
|
||||
{ componentEv: `${eventPrefix}willpresent`, frameworkEv: 'willPresent', deprecatedEv: 'onWillPresent' },
|
||||
{ componentEv: `${eventPrefix}didpresent`, frameworkEv: 'didPresent', deprecatedEv: 'onDidPresent' },
|
||||
{ componentEv: `${eventPrefix}willdismiss`, frameworkEv: 'willDismiss', deprecatedEv: 'onWillDismiss' },
|
||||
{ componentEv: `${eventPrefix}diddismiss`, frameworkEv: 'didDismiss', deprecatedEv: 'onDidDismiss' },
|
||||
];
|
||||
const kebabCaseListeners = [
|
||||
{ componentEv: `${name}-will-present`, frameworkEv: 'onWillPresent' },
|
||||
{ componentEv: `${name}-did-present`, frameworkEv: 'onDidPresent' },
|
||||
{ componentEv: `${name}-will-dismiss`, frameworkEv: 'onWillDismiss' },
|
||||
{ componentEv: `${name}-did-dismiss`, frameworkEv: 'onDidDismiss' },
|
||||
{ componentEv: `${name}-will-present`, frameworkEv: 'willPresent', deprecatedEv: 'onWillPresent' },
|
||||
{ componentEv: `${name}-did-present`, frameworkEv: 'didPresent', deprecatedEv: 'onDidPresent' },
|
||||
{ componentEv: `${name}-will-dismiss`, frameworkEv: 'willDismiss', deprecatedEv: 'onWillDismiss' },
|
||||
{ componentEv: `${name}-did-dismiss`, frameworkEv: 'didDismiss', deprecatedEv: 'onDidDismiss' },
|
||||
];
|
||||
|
||||
const Container = defineComponent<Props & OverlayProps>((props, { slots, emit }) => {
|
||||
const instance = getCurrentInstance();
|
||||
const adjustedEventListeners = needsKebabCase(instance.appContext.app.version) ? kebabCaseListeners : lowerCaseListeners;
|
||||
|
||||
checkForDeprecatedListeners(instance);
|
||||
|
||||
const overlay = ref();
|
||||
const onVnodeMounted = async () => {
|
||||
const isOpen = props.isOpen;
|
||||
@ -85,9 +120,21 @@ export const defineOverlayContainer = <Props extends object>(name: string, compo
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* When supporting both the "on" prefixed and non-"on" prefixed
|
||||
* events, there seems to be an issue where the handlers are
|
||||
* getting passed as props. This should be resolved when we drop
|
||||
* support for the "on" prefixed listeners.
|
||||
*/
|
||||
const restOfProps = { ...(props as any) };
|
||||
delete restOfProps.onWillPresent;
|
||||
delete restOfProps.onDidPresent;
|
||||
delete restOfProps.onWillDismiss;
|
||||
delete restOfProps.onDidDismiss;
|
||||
|
||||
const component = slots.default && slots.default()[0];
|
||||
overlay.value = controller.create({
|
||||
...props,
|
||||
...restOfProps,
|
||||
component
|
||||
});
|
||||
|
||||
@ -96,6 +143,7 @@ export const defineOverlayContainer = <Props extends object>(name: string, compo
|
||||
adjustedEventListeners.forEach(eventListener => {
|
||||
overlay.value.addEventListener(eventListener.componentEv, () => {
|
||||
emit(eventListener.frameworkEv);
|
||||
emit(eventListener.deprecatedEv);
|
||||
});
|
||||
})
|
||||
|
||||
@ -118,7 +166,10 @@ export const defineOverlayContainer = <Props extends object>(name: string, compo
|
||||
|
||||
Container.displayName = name;
|
||||
Container.props = [...componentProps, 'isOpen'];
|
||||
Container.emits = [...lowerCaseListeners.map(ev => ev.frameworkEv), ...kebabCaseListeners.map(ev => ev.frameworkEv)];
|
||||
Container.emits = [
|
||||
'willPresent', 'didPresent', 'willDismiss', 'didDismiss',
|
||||
'onWillPresent', 'onDidPresent', 'onWillDismiss', 'onDidDismiss'
|
||||
];
|
||||
|
||||
return Container;
|
||||
}
|
||||
|
@ -2,5 +2,6 @@
|
||||
"pluginsFile": "tests/e2e/plugins/index.js",
|
||||
"includeShadowDom": true,
|
||||
"video": false,
|
||||
"screenshotOnRunFailure": false
|
||||
"screenshotOnRunFailure": false,
|
||||
"defaultCommandTimeout": 10000
|
||||
}
|
||||
|
@ -46,7 +46,8 @@ const routes: Array<RouteRecordRaw> = [
|
||||
},
|
||||
{
|
||||
path: '/routing/:id',
|
||||
component: () => import('@/views/RoutingParameter.vue')
|
||||
component: () => import('@/views/RoutingParameter.vue'),
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: '/routing/:id/view',
|
||||
@ -71,7 +72,8 @@ const routes: Array<RouteRecordRaw> = [
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
component: () => import('@/views/Folder.vue')
|
||||
component: () => import('@/views/Folder.vue'),
|
||||
props: true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -5,19 +5,19 @@
|
||||
<ion-buttons slot="start">
|
||||
<ion-menu-button></ion-menu-button>
|
||||
</ion-buttons>
|
||||
<ion-title>{{ folder }}</ion-title>
|
||||
<ion-title>{{ $props.id }}</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content :fullscreen="true">
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">{{ folder }}</ion-title>
|
||||
<ion-title size="large">{{ $props.id }}</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<div id="container">
|
||||
<strong class="capitalize">{{ folder }}</strong>
|
||||
<strong class="capitalize">{{ $props.id }}</strong>
|
||||
<p>Explore <a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/components">UI Components</a></p>
|
||||
</div>
|
||||
</ion-content>
|
||||
@ -26,8 +26,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { IonButtons, IonContent, IonHeader, IonMenuButton, IonPage, IonTitle, IonToolbar } from '@ionic/vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
|
||||
export default {
|
||||
name: 'Folder',
|
||||
@ -40,16 +38,8 @@ export default {
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
},
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const folder = ref(route.params.id || 'Inbox');
|
||||
const matchedFolder = computed(() => route.params.id);
|
||||
|
||||
watch(matchedFolder, () => {
|
||||
folder.value = matchedFolder.value as string;
|
||||
})
|
||||
|
||||
return { folder }
|
||||
props: {
|
||||
id: { type: String, default: 'Inbox' }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -76,7 +76,7 @@
|
||||
<ion-action-sheet
|
||||
:is-open="isActionSheetOpen"
|
||||
:buttons="actionSheetButtons"
|
||||
@onDidDismiss="setActionSheetRef(false)"
|
||||
@didDismiss="setActionSheetRef(false)"
|
||||
>
|
||||
</ion-action-sheet>
|
||||
|
||||
@ -84,7 +84,7 @@
|
||||
:is-open="isAlertOpen"
|
||||
header="Alert!"
|
||||
:buttons="alertButtons"
|
||||
@onDidDismiss="setAlertRef(false)"
|
||||
@didDismiss="setAlertRef(false)"
|
||||
>
|
||||
</ion-alert>
|
||||
|
||||
@ -93,17 +93,17 @@
|
||||
:duration="2000"
|
||||
message="Loading"
|
||||
:backdrop-dismiss="true"
|
||||
@onDidDismiss="setLoadingRef(false)"
|
||||
@didDismiss="setLoadingRef(false)"
|
||||
>
|
||||
</ion-loading>
|
||||
|
||||
<ion-modal
|
||||
:is-open="isModalOpen"
|
||||
:componentProps="overlayProps"
|
||||
@onWillPresent="onModalWillPresent"
|
||||
@onDidPresent="onModalDidPresent"
|
||||
@onWillDismiss="onModalWillDismiss"
|
||||
@onDidDismiss="onModalDidDismiss"
|
||||
@willPresent="onModalWillPresent"
|
||||
@didPresent="onModalDidPresent"
|
||||
@willDismiss="onModalWillDismiss"
|
||||
@didDismiss="onModalDidDismiss"
|
||||
>
|
||||
<ModalContent></ModalContent>
|
||||
</ion-modal>
|
||||
@ -112,7 +112,7 @@
|
||||
:is-open="isPopoverOpen"
|
||||
:componentProps="overlayProps"
|
||||
:event="popoverEvent"
|
||||
@onDidDismiss="setPopoverRef(false)"
|
||||
@didDismiss="setPopoverRef(false)"
|
||||
>
|
||||
<PopoverContent></PopoverContent>
|
||||
</ion-popover>
|
||||
@ -122,7 +122,7 @@
|
||||
:duration="2000"
|
||||
message="Toast"
|
||||
:buttons="toastButtons"
|
||||
@onDidDismiss="setToastRef(false)"
|
||||
@didDismiss="setToastRef(false)"
|
||||
>
|
||||
</ion-toast>
|
||||
</ion-content>
|
||||
|
@ -18,8 +18,11 @@
|
||||
|
||||
<ion-button id="parameter-view" :router-link="'/routing/' + $route.params.id + '/view'">Go to Single View</ion-button>
|
||||
|
||||
<ion-button router-link="/routing/abc">Go to Parameter Page ABC</ion-button>
|
||||
<ion-button router-link="/routing/xyz">Go to Parameter Page XYZ</ion-button>
|
||||
|
||||
<div class="ion-padding" id="parameter-value">
|
||||
{{ $route.params.id }}
|
||||
{{ $props.id }}
|
||||
</div>
|
||||
</ion-content>
|
||||
</ion-page>
|
||||
@ -39,6 +42,9 @@ import {
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
id: { type: String, default: 'my default' }
|
||||
},
|
||||
components: {
|
||||
IonButton,
|
||||
IonBackButton,
|
||||
|
@ -3,20 +3,17 @@
|
||||
<ion-content>
|
||||
<ion-tabs id="tabs">
|
||||
<ion-tab-bar slot="bottom">
|
||||
<ion-tab-button tab="tab1" href="/tabs/tab1">
|
||||
<ion-icon :icon="triangle" />
|
||||
<ion-label>Tab 1</ion-label>
|
||||
<ion-tab-button
|
||||
v-for="tab in tabs"
|
||||
:tab="'tab' + tab.id"
|
||||
:href="'/tabs/tab' + tab.id"
|
||||
:key="tab.id"
|
||||
>
|
||||
<ion-icon :icon="tab.icon" />
|
||||
<ion-label>Tab {{ tab.id }}</ion-label>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="tab2" href="/tabs/tab2">
|
||||
<ion-icon :icon="ellipse" />
|
||||
<ion-label>Tab 2</ion-label>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="tab3" href="/tabs/tab3">
|
||||
<ion-icon :icon="square" />
|
||||
<ion-label>Tab 3</ion-label>
|
||||
</ion-tab-button>
|
||||
<ion-button id="add-tab" @click="addTab()">Add Tab</ion-button>
|
||||
</ion-tab-bar>
|
||||
</ion-tabs>
|
||||
</ion-content>
|
||||
@ -24,18 +21,33 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { IonTabBar, IonTabButton, IonTabs, IonContent, IonLabel, IonIcon, IonPage } from '@ionic/vue';
|
||||
import { ellipse, square, triangle } from 'ionicons/icons';
|
||||
import { IonButton, IonTabBar, IonTabButton, IonTabs, IonContent, IonLabel, IonIcon, IonPage } from '@ionic/vue';
|
||||
import { ellipse, square, triangle, shield } from 'ionicons/icons';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ref, defineComponent } from 'vue';
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'Tabs',
|
||||
components: { IonContent, IonLabel, IonTabs, IonTabBar, IonTabButton, IonIcon, IonPage },
|
||||
components: { IonButton, IonContent, IonLabel, IonTabs, IonTabBar, IonTabButton, IonIcon, IonPage },
|
||||
setup() {
|
||||
return {
|
||||
ellipse,
|
||||
square,
|
||||
triangle,
|
||||
const tabs = ref([
|
||||
{ id: 1, icon: triangle },
|
||||
{ id: 2, icon: ellipse },
|
||||
{ id: 3, icon: square }
|
||||
])
|
||||
const router = useRouter();
|
||||
const addTab = () => {
|
||||
router.addRoute({ path: '/tabs/tab4', component: () => import('@/views/Tab4.vue') });
|
||||
tabs.value = [
|
||||
...tabs.value,
|
||||
{
|
||||
id: 4,
|
||||
icon: shield
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return { tabs, addTab }
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -1,6 +1,7 @@
|
||||
describe('Nested', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('http://localhost:8080/nested');
|
||||
cy.ionPageVisible('nestedchild');
|
||||
});
|
||||
|
||||
it('should show first page', () => {
|
||||
|
@ -203,6 +203,71 @@ describe('Tabs', () => {
|
||||
|
||||
cy.get('ion-tab-button#tab-button-tab1').should('not.have.class', 'tab-selected');
|
||||
});
|
||||
|
||||
// Verifies fix for https://github.com/ionic-team/ionic-framework/issues/23101
|
||||
it('should return to previous tab instance when using the ion-back-button', () => {
|
||||
cy.visit('http://localhost:8080/tabs/tab1');
|
||||
|
||||
cy.get('#tabs-secondary').click();
|
||||
cy.ionPageHidden('tabs');
|
||||
cy.ionPageVisible('tab1-secondary');
|
||||
|
||||
cy.get('ion-tab-button#tab-button-tab2-secondary').click();
|
||||
cy.ionPageHidden('tab1-secondary');
|
||||
cy.ionPageVisible('tab2-secondary');
|
||||
|
||||
cy.get('ion-tab-button#tab-button-tab1-secondary').click();
|
||||
cy.ionPageHidden('tab2-secondary');
|
||||
cy.ionPageVisible('tab1-secondary');
|
||||
|
||||
cy.ionBackClick('tab1-secondary');
|
||||
cy.ionPageDoesNotExist('tabs-secondary');
|
||||
cy.ionPageVisible('tab1');
|
||||
});
|
||||
|
||||
// Verifies fix for https://github.com/ionic-team/ionic-framework/issues/23087
|
||||
it('should return to correct view and url when going back from child page after switching tabs', () => {
|
||||
cy.visit('http://localhost:8080/tabs/tab1');
|
||||
|
||||
cy.get('#child-one').click();
|
||||
cy.ionPageHidden('tab1');
|
||||
cy.ionPageVisible('tab1childone');
|
||||
|
||||
cy.get('ion-tab-button#tab-button-tab2').click();
|
||||
cy.ionPageHidden('tab1childone');
|
||||
cy.ionPageVisible('tab2');
|
||||
|
||||
cy.get('ion-tab-button#tab-button-tab1').click();
|
||||
cy.ionPageHidden('tab2');
|
||||
cy.ionPageVisible('tab1childone');
|
||||
|
||||
cy.ionBackClick('tab1childone');
|
||||
cy.ionPageDoesNotExist('tab1childone');
|
||||
cy.ionPageVisible('tab1');
|
||||
|
||||
cy.url().should('include', '/tabs/tab1');
|
||||
});
|
||||
|
||||
// Verifies fix for https://github.com/ionic-team/ionic-framework/issues/22847
|
||||
it('should support dynamic tabs', () => {
|
||||
cy.visit('http://localhost:8080/tabs/tab1');
|
||||
|
||||
cy.ionPageVisible('tab1');
|
||||
|
||||
cy.get('ion-tab-button').its('length').should('equal', 3);
|
||||
cy.get('ion-tab-button#tab-button-tab1').should('have.class', 'tab-selected');
|
||||
|
||||
cy.get('#add-tab').click();
|
||||
|
||||
cy.get('ion-tab-button').its('length').should('equal', 4);
|
||||
|
||||
cy.get('ion-tab-button#tab-button-tab4').click();
|
||||
cy.ionPageVisible('tab4');
|
||||
cy.ionPageHidden('tab1');
|
||||
|
||||
cy.get('ion-tab-button#tab-button-tab1').should('not.have.class', 'tab-selected');
|
||||
cy.get('ion-tab-button#tab-button-tab4').should('have.class', 'tab-selected');
|
||||
});
|
||||
})
|
||||
|
||||
describe('Tabs - Swipe to Go Back', () => {
|
||||
@ -214,11 +279,15 @@ describe('Tabs - Swipe to Go Back', () => {
|
||||
cy.ionPageVisible('tab1')
|
||||
});
|
||||
|
||||
it('should swipe and abort', () => {
|
||||
// TODO: Flaky if test runner is slow
|
||||
// Delays between gesture movements
|
||||
// cause swipe back gesture to think
|
||||
// velocity is higher than it actually is
|
||||
/*it('should swipe and abort', () => {
|
||||
cy.ionSwipeToGoBack();
|
||||
cy.ionPageHidden('home');
|
||||
cy.ionPageVisible('tab1');
|
||||
});
|
||||
});*/
|
||||
|
||||
it('should swipe and go back to home', () => {
|
||||
cy.ionSwipeToGoBack(true);
|
||||
|
@ -47,12 +47,6 @@ Cypress.Commands.add('ionPageVisible', (pageId) => {
|
||||
.should('have.length', 1)
|
||||
})
|
||||
|
||||
Cypress.Commands.add('ionPageInvisible', (pageId) => {
|
||||
cy.get(`div.ion-page[data-pageid=${pageId}]`)
|
||||
.should('have.class', 'ion-page-invisible')
|
||||
.should('have.length', 1)
|
||||
})
|
||||
|
||||
Cypress.Commands.add('ionPageHidden', (pageId) => {
|
||||
cy.get(`div.ion-page[data-pageid=${pageId}]`)
|
||||
.should('have.class', 'ion-page-hidden')
|
||||
|
@ -358,4 +358,39 @@ describe('Routing', () => {
|
||||
const cmpAgain = wrapper.findComponent(Page1);
|
||||
expect(cmpAgain.props()).toEqual({ title: 'abc Title' });
|
||||
});
|
||||
|
||||
// Verifies fix for https://github.com/ionic-team/ionic-framework/pull/23189
|
||||
it('should update props on a parameterized url', async () => {
|
||||
const Page = {
|
||||
props: {
|
||||
id: { type: String, default: 'Default ID' }
|
||||
},
|
||||
components: { IonPage },
|
||||
template: `<ion-page>{{ $props.id }}</ion-page>`
|
||||
}
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(process.env.BASE_URL),
|
||||
routes: [
|
||||
{ path: '/page/:id', component: Page, props: true },
|
||||
{ path: '/', redirect: '/page/1' }
|
||||
]
|
||||
});
|
||||
|
||||
router.push('/');
|
||||
await router.isReady();
|
||||
const wrapper = mount(App, {
|
||||
global: {
|
||||
plugins: [router, IonicVue]
|
||||
}
|
||||
});
|
||||
|
||||
const page = wrapper.findComponent(Page);
|
||||
expect(page.props()).toEqual({ id: '1' });
|
||||
|
||||
router.push('/page/2');
|
||||
await waitForRouter();
|
||||
|
||||
expect(page.props()).toEqual({ id: '2' });
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user