Skip to content

Commit 27318cf

Browse files
authoredMar 29, 2021
fix(vue): account for event name changes in vue 3.0.6+ for overlay components (#23100)
1 parent ba51daf commit 27318cf

File tree

6 files changed

+108
-12
lines changed

6 files changed

+108
-12
lines changed
 

‎packages/vue/src/ionic-vue.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { App, Plugin } from 'vue';
22
import { IonicConfig, setupConfig } from '@ionic/core';
33
import { applyPolyfills, defineCustomElements } from '@ionic/core/loader';
4-
5-
const needsKebabCase = (version: string) => !['3.0.0', '3.0.1', '3.0.2', '3.0.3', '3.0.4', '3.0.5'].includes(version);
4+
import { needsKebabCase } from './utils';
65

76
/**
87
* We need to make sure that the web component fires an event

‎packages/vue/src/utils.ts

+2
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,5 @@ export const getConfig = (): CoreConfig | null => {
5757
}
5858
return null;
5959
};
60+
61+
export const needsKebabCase = (version: string) => !['3.0.0', '3.0.1', '3.0.2', '3.0.3', '3.0.4', '3.0.5'].includes(version);

‎packages/vue/src/vue-component-lib/overlays.ts

+22-5
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,37 @@
1-
import { defineComponent, h, ref, VNode } from 'vue';
1+
import { defineComponent, h, ref, VNode, getCurrentInstance } from 'vue';
2+
import { needsKebabCase } from '../utils';
23

34
export interface OverlayProps {
45
isOpen?: boolean;
56
}
67

78
export const defineOverlayContainer = <Props extends object>(name: string, componentProps: string[] = [], controller: any) => {
8-
// TODO
9+
/**
10+
* Vue 3.0.6 fixed a bug where events on custom elements
11+
* were always converted to lower case, so "ionRefresh"
12+
* became "ionRefresh". We need to account for the old
13+
* issue as well as the new behavior where "ionRefresh"
14+
* is converted to "ion-refresh".
15+
* See https://github.com/vuejs/vue-next/pull/2847
16+
*/
917
const eventPrefix = name.toLowerCase().split('-').join('');
10-
const eventListeners = [
18+
const lowerCaseListeners = [
1119
{ componentEv: `${eventPrefix}willpresent`, frameworkEv: 'onWillPresent' },
1220
{ componentEv: `${eventPrefix}didpresent`, frameworkEv: 'onDidPresent' },
1321
{ componentEv: `${eventPrefix}willdismiss`, frameworkEv: 'onWillDismiss' },
1422
{ componentEv: `${eventPrefix}diddismiss`, frameworkEv: 'onDidDismiss' },
1523
];
24+
const kebabCaseListeners = [
25+
{ componentEv: `${name}-will-present`, frameworkEv: 'onWillPresent' },
26+
{ componentEv: `${name}-did-present`, frameworkEv: 'onDidPresent' },
27+
{ componentEv: `${name}-will-dismiss`, frameworkEv: 'onWillDismiss' },
28+
{ componentEv: `${name}-did-dismiss`, frameworkEv: 'onDidDismiss' },
29+
];
1630

1731
const Container = defineComponent<Props & OverlayProps>((props, { slots, emit }) => {
32+
const instance = getCurrentInstance();
33+
const adjustedEventListeners = needsKebabCase(instance.appContext.app.version) ? kebabCaseListeners : lowerCaseListeners;
34+
1835
const overlay = ref();
1936
const onVnodeMounted = async () => {
2037
const isOpen = props.isOpen;
@@ -76,7 +93,7 @@ export const defineOverlayContainer = <Props extends object>(name: string, compo
7693

7794
overlay.value = await overlay.value;
7895

79-
eventListeners.forEach(eventListener => {
96+
adjustedEventListeners.forEach(eventListener => {
8097
overlay.value.addEventListener(eventListener.componentEv, () => {
8198
emit(eventListener.frameworkEv);
8299
});
@@ -101,7 +118,7 @@ export const defineOverlayContainer = <Props extends object>(name: string, compo
101118

102119
Container.displayName = name;
103120
Container.props = [...componentProps, 'isOpen'];
104-
Container.emits = eventListeners.map(ev => ev.frameworkEv);
121+
Container.emits = [...lowerCaseListeners.map(ev => ev.frameworkEv), ...kebabCaseListeners.map(ev => ev.frameworkEv)];
105122

106123
return Container;
107124
}

‎packages/vue/test-app/src/components/ModalContent.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<ion-header>
44
<ion-toolbar>
55
<ion-buttons>
6-
<ion-button @click="dismiss">Dismiss</ion-button>
6+
<ion-button @click="dismiss" id="dismiss">Dismiss</ion-button>
77
</ion-buttons>
88
<ion-title>Modal</ion-title>
99
</ion-toolbar>

‎packages/vue/test-app/src/views/Overlays.vue

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<ion-page>
2+
<ion-page data-pageid="overlays">
33
<ion-header :translucent="true">
44
<ion-toolbar>
55
<ion-buttons>
@@ -66,6 +66,13 @@
6666

6767
<ion-button @click="changeLoadingProps()" id="change-loading-props">Quickly Change Loading Props</ion-button>
6868

69+
<br /><br />
70+
71+
Modal onWillPresent: <div id="willPresent">{{ willPresent }}</div><br />
72+
Modal onDidPresent: <div id="didPresent">{{ didPresent }}</div><br />
73+
Modal onWillDismiss: <div id="willDismiss">{{ willDismiss }}</div><br />
74+
Modal onDidDismiss: <div id="didDismiss">{{ didDismiss }}</div><br />
75+
6976
<ion-action-sheet
7077
:is-open="isActionSheetOpen"
7178
:buttons="actionSheetButtons"
@@ -93,7 +100,10 @@
93100
<ion-modal
94101
:is-open="isModalOpen"
95102
:componentProps="overlayProps"
96-
@onDidDismiss="setModalRef(false)"
103+
@onWillPresent="onModalWillPresent"
104+
@onDidPresent="onModalDidPresent"
105+
@onWillDismiss="onModalWillDismiss"
106+
@onDidDismiss="onModalDidDismiss"
97107
>
98108
<ModalContent></ModalContent>
99109
</ion-modal>
@@ -326,7 +336,25 @@ export default defineComponent({
326336
}, 10);
327337
}
328338
339+
const willPresent = ref(0);
340+
const didPresent = ref(0);
341+
const willDismiss = ref(0);
342+
const didDismiss = ref(0);
343+
344+
const onModalWillPresent = () => willPresent.value += 1;
345+
const onModalDidPresent = () => { didPresent.value += 1; setModalRef(true); }
346+
const onModalWillDismiss = () => willDismiss.value += 1;
347+
const onModalDidDismiss = () => { didDismiss.value += 1; setModalRef(false); }
348+
329349
return {
350+
onModalWillPresent,
351+
onModalDidPresent,
352+
onModalWillDismiss,
353+
onModalDidDismiss,
354+
willPresent,
355+
didPresent,
356+
willDismiss,
357+
didDismiss,
330358
changeLoadingProps,
331359
overlayProps,
332360
present,

‎packages/vue/test-app/tests/e2e/specs/overlays.js

+52-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
describe('Overlays', () => {
22
beforeEach(() => {
3+
cy.viewport(1000, 900);
34
cy.visit('http://localhost:8080/overlays')
45
})
56

67
const overlays = ['ion-alert', 'ion-action-sheet', 'ion-loading', 'ion-modal', 'ion-popover'];
78

89
for (let overlay of overlays) {
910
it(`should open and close ${overlay} via controller`, () => {
10-
console.log(overlay)
1111
cy.get(`ion-radio#${overlay}`).click();
1212
cy.get('ion-radio#controller').click();
1313

@@ -34,7 +34,6 @@ describe('Overlays', () => {
3434

3535
for (let overlay of overlays) {
3636
it(`should open and close ${overlay} via component`, () => {
37-
console.log(overlay)
3837
cy.get(`ion-radio#${overlay}`).click();
3938
cy.get('ion-radio#component').click();
4039

@@ -104,4 +103,55 @@ describe('Overlays', () => {
104103

105104
cy.get('ion-loading').should('have.length', 1);
106105
});
106+
107+
it('should fire lifecycle events on overlays', () => {
108+
cy.get('ion-radio#ion-modal').click();
109+
cy.get('ion-radio#component').click();
110+
111+
cy.get('ion-button#present-overlay').click();
112+
cy.get('ion-modal').should('exist');
113+
114+
testLifecycle('overlays', {
115+
willPresent: 1,
116+
didPresent: 1,
117+
willDismiss: 0,
118+
didDismiss: 0
119+
});
120+
121+
cy.get('ion-modal #dismiss').click();
122+
123+
testLifecycle('overlays', {
124+
willPresent: 1,
125+
didPresent: 1,
126+
willDismiss: 1,
127+
didDismiss: 1
128+
});
129+
130+
cy.get('ion-button#present-overlay').click();
131+
cy.get('ion-modal').should('exist');
132+
133+
testLifecycle('overlays', {
134+
willPresent: 2,
135+
didPresent: 2,
136+
willDismiss: 1,
137+
didDismiss: 1
138+
});
139+
140+
cy.get('ion-modal #dismiss').click();
141+
142+
testLifecycle('overlays', {
143+
willPresent: 2,
144+
didPresent: 2,
145+
willDismiss: 2,
146+
didDismiss: 2
147+
});
148+
});
107149
})
150+
151+
const testLifecycle = (selector, expected = {}) => {
152+
cy.get(`[data-pageid=${selector}] #willPresent`).should('have.text', expected.willPresent);
153+
cy.get(`[data-pageid=${selector}] #didPresent`).should('have.text', expected.didPresent);
154+
cy.get(`[data-pageid=${selector}] #willDismiss`).should('have.text', expected.willDismiss);
155+
cy.get(`[data-pageid=${selector}] #didDismiss`).should('have.text', expected.didDismiss);
156+
}
157+

0 commit comments

Comments
 (0)
Please sign in to comment.