Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/stencil.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export const config: Config = {
'ion-popover',
'ion-toast',

'ion-app',
'ion-icon'
],
routerLinkComponents: [
Expand Down
38 changes: 38 additions & 0 deletions packages/vue/src/components/IonApp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { h, defineComponent, shallowRef, VNode } from 'vue';

const userComponents = shallowRef([]);
export const IonApp = defineComponent({
name: 'IonApp',
setup(_, { attrs, slots }) {
return () => {
return h(
'ion-app',
{
...attrs
},
[slots.default && slots.default(), ...userComponents.value]
)
}
}
});

/**
* When rendering user components inside of
* ion-modal, ion-popover, or ion-nav, the component
* needs to be created inside of the current application
* context otherwise libraries such as vue-i18n or vuex
* will not work properly.
*
* `userComponents` renders teleported components as children
* of `ion-app` within the current application context.
*/
export const addTeleportedUserComponent = (component: VNode) => {
userComponents.value = [
...userComponents.value,
component
]
}

export const removeTeleportedUserComponent = (component: VNode) => {
userComponents.value = userComponents.value.filter(cmp => cmp !== component);
}
21 changes: 13 additions & 8 deletions packages/vue/src/framework-delegate.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { createVNode, render } from 'vue';

import { h, Teleport, VNode } from 'vue';
import { addTeleportedUserComponent, removeTeleportedUserComponent } from './components/IonApp';
export const VueDelegate = () => {
const attachViewToDom = (parentElement: HTMLElement, component: any, componentProps: any, classes?: string[]) => {
let Component: VNode | undefined;
const attachViewToDom = (parentElement: HTMLElement, component: any, componentProps: any = {}, classes?: string[]) => {
/**
* Ionic Framework passes in modal and popover element
* refs as props, but if these are not defined
Expand All @@ -10,20 +11,24 @@ export const VueDelegate = () => {
*/
delete componentProps['modal'];
delete componentProps['popover'];
const vueInstance = createVNode(component, componentProps);

const div = document.createElement('div');
classes && div.classList.add(...classes);

parentElement.appendChild(div);

render(vueInstance, div);
Component = h(
Teleport,
{ to: div },
h(component, { ...componentProps })
);

addTeleportedUserComponent(Component);

return div;
}

const removeViewFromDom = (_: HTMLElement, childElement: any) => {
render(null, childElement);
const removeViewFromDom = () => {
Component && removeTeleportedUserComponent(Component);
return Promise.resolve();
}

Expand Down
2 changes: 2 additions & 0 deletions packages/vue/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export { IonTabs } from './components/IonTabs';
export { IonTabBar } from './components/IonTabBar';
export { IonNav } from './components/IonNav';
export { IonIcon } from './components/IonIcon';
export { IonApp } from './components/IonApp';

export * from './components/Overlays';

export { IonKeyboardRef, IonRouter, useBackButton, useIonRouter, useKeyboard } from './hooks';
Expand Down
3 changes: 0 additions & 3 deletions packages/vue/src/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import { JSX } from '@ionic/core';



export const IonApp = /*@__PURE__*/ defineContainer<JSX.IonApp>('ion-app');


export const IonAvatar = /*@__PURE__*/ defineContainer<JSX.IonAvatar>('ion-avatar');


Expand Down
4 changes: 1 addition & 3 deletions packages/vue/src/vue-component-lib/overlays.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ export const defineOverlayContainer = <Props extends object>(name: string, compo

const Container = defineComponent<Props & OverlayProps>((props, { slots, emit }) => {
const overlay = ref();
const content = ref();

const onVnodeMounted = async () => {
const isOpen = props.isOpen;
isOpen && (await present(props))
Expand All @@ -39,7 +37,7 @@ export const defineOverlayContainer = <Props extends object>(name: string, compo
}

const present = async (props: Readonly<Props>) => {
const component = (slots) ? h('div', { ref: content }, slots) : undefined;
const component = slots.default && slots.default()[0];
overlay.value = await controller.create({
...props,
component
Expand Down
20 changes: 10 additions & 10 deletions packages/vue/test-app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/vue/test-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
"sync": "sh ./scripts/sync.sh"
},
"dependencies": {
"@ionic/vue": "5.4.0-dev.202010091911.bfc0b25",
"@ionic/vue-router": "5.4.0-dev.202010091911.bfc0b25",
"@ionic/vue": "5.4.0-dev.202010081857.bfc0b25",
"@ionic/vue-router": "5.4.0-dev.202010081857.bfc0b25",
"core-js": "^3.6.5",
"vue": "^3.0.0-0",
"vue-router": "^4.0.0-0"
Expand Down
16 changes: 16 additions & 0 deletions packages/vue/test-app/src/components/Nav.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<ion-nav :root="NavRoot"></ion-nav>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import { IonNav } from '@ionic/vue';
import NavRoot from '@/components/NavRoot.vue';

export default defineComponent({
components: { IonNav },
setup() {
return { NavRoot }
}
});
</script>
39 changes: 39 additions & 0 deletions packages/vue/test-app/src/components/NavChild.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<template>
<ion-header>
<ion-toolbar>
<ion-buttons>
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>Nav - Child</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding" id="nav-child-content">
{{ title }}
</ion-content>
</template>

<script lang="ts">
import {
IonButtons,
IonBackButton,
IonContent,
IonHeader,
IonTitle,
IonToolbar
} from '@ionic/vue';
import { defineComponent } from 'vue';

export default defineComponent({
props: {
title: { type: String, default: 'Default Title' }
},
components: {
IonButtons,
IonBackButton,
IonContent,
IonHeader,
IonTitle,
IonToolbar
}
})
</script>
47 changes: 47 additions & 0 deletions packages/vue/test-app/src/components/NavRoot.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<template>
<ion-header>
<ion-toolbar>
<ion-buttons>
<ion-button @click="dismiss">Dismiss</ion-button>
</ion-buttons>
<ion-title>Nav - Root</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-button expand="block" @click="pushPage" id="push-nav-child">Go to Nav Child</ion-button>
</ion-content>
</template>

<script lang="ts">
import {
IonButtons,
IonButton,
IonContent,
IonHeader,
IonTitle,
IonToolbar,
modalController
} from '@ionic/vue';
import { defineComponent } from 'vue';
import NavChild from '@/components/NavChild.vue';

export default defineComponent({
components: {
IonButtons,
IonButton,
IonContent,
IonHeader,
IonTitle,
IonToolbar
},
methods: {
pushPage: function() {
const ionNav = document.querySelector('ion-nav') as any;
ionNav.push(NavChild, { title: 'Custom Title' });
},
dismiss: async function() {
await modalController.dismiss();
}
}
})
</script>
15 changes: 9 additions & 6 deletions packages/vue/test-app/src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ const routes: Array<RouteRecordRaw> = [
component: () => import('@/views/DefaultHref.vue')
},
{
path: '/navigation',
name: 'Navigation',
component: () => import('@/views/Navigation.vue')
path: '/routing',
component: () => import('@/views/Routing.vue')
},
{
path: '/navigation/child',
component: () => import('@/views/NavigationChild.vue')
path: '/routing/child',
component: () => import('@/views/RoutingChild.vue')
},
{
path: '/navigation',
component: () => import('@/views/Navigation.vue')
},
{
path: '/nested',
Expand Down Expand Up @@ -81,7 +84,7 @@ const routes: Array<RouteRecordRaw> = [
component: () => import('@/views/Tab3.vue')
}
]
}
},
]

const router = createRouter({
Expand Down
3 changes: 3 additions & 0 deletions packages/vue/test-app/src/views/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
<ion-item router-link="/navigation" id="navigation">
<ion-label>Navigation</ion-label>
</ion-item>
<ion-item router-link="/routing" id="routing">
<ion-label>Routing</ion-label>
</ion-item>
<ion-item router-link="/default-href" id="default-href">
<ion-label>Default Href</ion-label>
</ion-item>
Expand Down
37 changes: 14 additions & 23 deletions packages/vue/test-app/src/views/Navigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,56 +16,47 @@
</ion-toolbar>
</ion-header>

<ion-item button @click="setRouteParams" id="route-params">
<ion-label>Set Route Parameters</ion-label>
</ion-item>

<ion-item button router-link="/navigation/child" id="child">
<ion-label>Go to Child Page</ion-label>
</ion-item>
<div class="ion-padding">
<ion-button expand="block" @click="openModal" id="open-nav-modal">Open Modal</ion-button>
</div>
</ion-content>
</ion-page>
</template>

<script lang="ts">
import {
IonButton,
IonBackButton,
IonButtons,
IonContent,
IonHeader,
IonItem,
IonLabel,
IonPage,
IonTitle,
IonToolbar
IonToolbar,
modalController
} from '@ionic/vue';
import { defineComponent } from 'vue';
import { useRouter } from 'vue-router';

import Nav from '@/components/Nav.vue';
export default defineComponent({
name: 'Navigation',
components: {
IonButton,
IonBackButton,
IonButtons,
IonContent,
IonHeader,
IonItem,
IonLabel,
IonPage,
IonTitle,
IonToolbar
},
setup() {
const router = useRouter();
const setRouteParams = () => {
router.push({
query: {
search: 'liamwashere'
}
const openModal = async () => {
const modal = await modalController.create({
component: Nav
});
}

return { setRouteParams }
await modal.present();
}
return { openModal }
}
});
</script>
Loading