Merge remote-tracking branch 'origin/master' into sync-master

# Conflicts:
#	packages/vue/src/components/IonTabs.ts
#	packages/vue/test-app/src/router/index.ts
This commit is contained in:
Liam DeBeasi
2021-06-21 21:26:49 +00:00
3 changed files with 113 additions and 11 deletions

View File

@ -7,9 +7,22 @@ const DID_CHANGE = 'ionTabsDidChange';
export const IonTabs = /*@__PURE__*/ defineComponent({
name: 'IonTabs',
emits: [WILL_CHANGE, DID_CHANGE],
data() {
return { didWarn: false }
},
render() {
const { $slots: slots, $emit } = this;
const { $slots: slots, $emit, $data } = this;
const slottedContent = slots.default && slots.default();
let userProvidedRouterOutlet;
if (slottedContent && slottedContent.length > 0) {
/**
* If developer passed in their own ion-router-outlet
* instance, then we should not init a default one
*/
userProvidedRouterOutlet = slottedContent.find((child: VNode) => child.type && (child.type as any).name === 'IonRouterOutlet');
}
let childrenToRender = [
h('div', {
class: 'tabs-inner',
@ -18,18 +31,52 @@ export const IonTabs = /*@__PURE__*/ defineComponent({
'flex': '1',
'contain': 'layout size style'
}
}, [
h(IonRouterOutlet)
])
}, (userProvidedRouterOutlet) ? userProvidedRouterOutlet : [h(IonRouterOutlet)])
];
if (userProvidedRouterOutlet && !$data.didWarn) {
console.warn(`[@ionic/vue Deprecation] Starting in Ionic Vue v6.0, developers must add an 'ion-router-outlet' instance inside of 'ion-tabs'.
Before:
<ion-tabs>
<ion-tab-bar slot="bottom">
...
</ion-tab-bar>
</ion-tabs>
After:
<ion-tabs>
<ion-router-outlet></ion-router-outlet>
<ion-tab-bar slot="bottom">
...
</ion-tab-bar>
</ion-tabs>
Be sure to import 'IonRouterOutlet' from '@ionic/vue' and provide that import to your Vue component. See https://ionicframework.com/docs/vue/navigation#working-with-tabs for more information.
`);
$data.didWarn = true;
}
/**
* If ion-tab-bar has slot="top" it needs to be
* rendered before `.tabs-inner` otherwise it will
* not show above the tab content.
*/
if (slottedContent && slottedContent.length > 0) {
const slottedTabBar = slottedContent.find((child: VNode) => child.type && (child.type as any).name === 'IonTabBar');
/**
* Render all content except for router outlet
* since that needs to be inside of `.tabs-inner`.
*/
const filteredContent = slottedContent.filter((child: VNode) => (
!child.type ||
(child.type && (child.type as any).name !== 'IonRouterOutlet')
));
const slottedTabBar = filteredContent.find((child: VNode) => child.type && (child.type as any).name === 'IonTabBar');
const hasTopSlotTabBar = slottedTabBar && slottedTabBar.props?.slot === 'top';
if (slottedTabBar) {
@ -49,13 +96,13 @@ export const IonTabs = /*@__PURE__*/ defineComponent({
if (hasTopSlotTabBar) {
childrenToRender = [
...slottedContent,
...filteredContent,
...childrenToRender
];
} else {
childrenToRender = [
...childrenToRender,
...slottedContent
...filteredContent
]
}
}

View File

@ -18,11 +18,12 @@ import { IonToast as IonToastCmp } from '@ionic/core/components/ion-toast.js'
import { defineOverlayContainer } from '../vue-component-lib/overlays';
export const IonActionSheet = /*@__PURE__*/ defineOverlayContainer<JSX.IonActionSheet>('ion-action-sheet', IonActionSheetCmp, ['animated', 'backdropDismiss', 'buttons', 'cssClass', 'enterAnimation', 'header', 'keyboardClose', 'leaveAnimation', 'mode', 'subHeader', 'translucent'], actionSheetController);
export const IonAlert = /*@__PURE__*/ defineOverlayContainer<JSX.IonAlert>('ion-alert', IonAlertCmp, ['animated', 'backdropDismiss', 'buttons', 'cssClass', 'enterAnimation', 'header', 'inputs', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'subHeader', 'translucent'], alertController);
export const IonLoading = /*@__PURE__*/ defineOverlayContainer<JSX.IonLoading>('ion-loading', IonLoadingCmp, ['animated', 'backdropDismiss', 'cssClass', 'duration', 'enterAnimation', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'showBackdrop', 'spinner', 'translucent'], loadingController);
export const IonPicker = /*@__PURE__*/ defineOverlayContainer<JSX.IonPicker>('ion-picker', IonPickerCmp, ['animated', 'backdropDismiss', 'buttons', 'columns', 'cssClass', 'duration', 'enterAnimation', 'keyboardClose', 'leaveAnimation', 'mode', 'showBackdrop'], pickerController);
export const IonToast = /*@__PURE__*/ defineOverlayContainer<JSX.IonToast>('ion-toast', IonToastCmp, ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'position', 'translucent'], toastController);

View File

@ -0,0 +1,54 @@
<template>
<ion-page data-pageid="tabs">
<ion-content>
<ion-tabs id="tabs">
<ion-router-outlet></ion-router-outlet>
<ion-tab-bar slot="bottom">
<ion-tab-button
v-for="tab in tabs"
:tab="'tab' + tab.id"
:href="'/tabs-new/tab' + tab.id"
:key="tab.id"
>
<ion-icon :icon="tab.icon" />
<ion-label>Tab {{ tab.id }}</ion-label>
</ion-tab-button>
<ion-button id="add-tab" @click="addTab()">Add Tab</ion-button>
</ion-tab-bar>
</ion-tabs>
</ion-content>
</ion-page>
</template>
<script lang="ts">
import { IonButton, IonTabBar, IonTabButton, IonTabs, IonContent, IonLabel, IonIcon, IonPage, IonRouterOutlet } from '@ionic/vue';
import { ellipse, square, triangle, shield } from 'ionicons/icons';
import { useRouter } from 'vue-router';
import { ref, defineComponent } from 'vue';
export default defineComponent({
name: 'Tabs',
components: { IonButton, IonContent, IonLabel, IonTabs, IonTabBar, IonTabButton, IonIcon, IonPage, IonRouterOutlet },
setup() {
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>