diff --git a/packages/vue/src/vue-component-lib/overlays.ts b/packages/vue/src/vue-component-lib/overlays.ts index 12c661c9cf..c058edb06e 100644 --- a/packages/vue/src/vue-component-lib/overlays.ts +++ b/packages/vue/src/vue-component-lib/overlays.ts @@ -1,4 +1,4 @@ -import { defineComponent, h, ref } from 'vue'; +import { defineComponent, h, ref, VNode } from 'vue'; export interface OverlayProps { isOpen?: boolean; @@ -21,28 +21,61 @@ export const defineOverlayContainer = (name: string, compo isOpen && (await present(props)) } - const onVnodeUpdated = async () => { - const isOpen = props.isOpen; + const onVnodeUpdated = async (node: VNode, prevNode: VNode) => { + const isOpen = node.props!.isOpen; + const prevIsOpen = prevNode.props!.isOpen; + + /** + * Do not do anything if this prop + * did not change. + */ + if (isOpen === prevIsOpen) return; + if (isOpen) { - await overlay.value?.present() || present(props); + await present(props); } else { - await overlay.value?.dismiss(); - overlay.value = undefined; + await dismiss(); } } const onVnodeBeforeUnmount = async () => { - await overlay.value?.dismiss(); + await dismiss(); + } + + const dismiss = async () => { + if (!overlay.value) return; + + await overlay.value; + + overlay.value = overlay.value.dismiss(); + + await overlay.value; + overlay.value = undefined; } const present = async (props: Readonly) => { + /** + * Do not open another instance + * if one is already opened. + */ + if (overlay.value) { + await overlay.value; + } + + if (overlay.value?.present) { + await overlay.value.present(); + return; + } + const component = slots.default && slots.default()[0]; - overlay.value = await controller.create({ + overlay.value = controller.create({ ...props, component }); + overlay.value = await overlay.value; + eventListeners.forEach(eventListener => { overlay.value.addEventListener(eventListener.componentEv, () => { emit(eventListener.frameworkEv); @@ -59,7 +92,8 @@ export const defineOverlayContainer = (name: string, compo style: { display: 'none' }, onVnodeMounted, onVnodeUpdated, - onVnodeBeforeUnmount + onVnodeBeforeUnmount, + isOpen: props.isOpen } ); } diff --git a/packages/vue/test-app/src/views/Overlays.vue b/packages/vue/test-app/src/views/Overlays.vue index b79df4df88..cdf5c0a445 100644 --- a/packages/vue/test-app/src/views/Overlays.vue +++ b/packages/vue/test-app/src/views/Overlays.vue @@ -62,7 +62,9 @@
- Present Overlay + Present Overlay + + Quickly Change Loading Props { + setLoadingRef(true); + setTimeout(() => { + setLoadingRef(false); + setTimeout(() => { + setLoadingRef(true); + }, 10); + }, 10); + } + return { + changeLoadingProps, overlayProps, present, componentType, diff --git a/packages/vue/test-app/tests/e2e/specs/overlays.js b/packages/vue/test-app/tests/e2e/specs/overlays.js index c0e7f0a058..e23186fd48 100644 --- a/packages/vue/test-app/tests/e2e/specs/overlays.js +++ b/packages/vue/test-app/tests/e2e/specs/overlays.js @@ -59,7 +59,7 @@ describe('Overlays', () => { cy.get('ion-toast').should('not.exist'); }); - it('it should pass props to modal via controller', () => { + it('should pass props to modal via controller', () => { cy.get('ion-radio#ion-modal').click(); cy.get('ion-radio#controller').click(); @@ -69,7 +69,7 @@ describe('Overlays', () => { cy.get('ion-modal ion-content').should('have.text', 'Custom Title'); }); - it('it should pass props to modal via component', () => { + it('should pass props to modal via component', () => { cy.get('ion-radio#ion-modal').click(); cy.get('ion-radio#component').click(); @@ -79,7 +79,7 @@ describe('Overlays', () => { cy.get('ion-modal ion-content').should('have.text', 'Custom Title'); }); - it('it should pass props to popover via controller', () => { + it('should pass props to popover via controller', () => { cy.get('ion-radio#ion-popover').click(); cy.get('ion-radio#controller').click(); @@ -89,7 +89,7 @@ describe('Overlays', () => { cy.get('ion-popover ion-content').should('have.text', 'Custom Title'); }); - it('it should pass props to popover via component', () => { + it('should pass props to popover via component', () => { cy.get('ion-radio#ion-popover').click(); cy.get('ion-radio#component').click(); @@ -98,4 +98,10 @@ describe('Overlays', () => { cy.get('ion-popover ion-content').should('have.text', 'Custom Title'); }); + + it('should only open one instance at a time when props change quickly on component', () => { + cy.get('#change-loading-props').click(); + + cy.get('ion-loading').should('have.length', 1); + }); })