From 1d2ee92ca01b77bcf87c7783b50d59efcf0a402a Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 26 Aug 2021 16:22:04 -0400 Subject: [PATCH] feat(popover): add ability to pass event to present method (#23827) resolves #23813 --- core/api.txt | 2 +- core/src/components.d.ts | 4 +- .../components/popover/popover-interface.ts | 6 ++- core/src/components/popover/popover.tsx | 16 +++---- core/src/components/popover/readme.md | 5 ++- .../src/components/popover/test/inline/e2e.ts | 42 +++++++++++++++++-- .../components/popover/test/inline/index.html | 7 +++- 7 files changed, 65 insertions(+), 17 deletions(-) diff --git a/core/api.txt b/core/api.txt index 8751f33c12..3715f0cebe 100644 --- a/core/api.txt +++ b/core/api.txt @@ -887,7 +887,7 @@ ion-popover,prop,triggerAction,"click" | "context-menu" | "hover",'click',false, ion-popover,method,dismiss,dismiss(data?: any, role?: string | undefined, dismissParentPopover?: boolean) => Promise ion-popover,method,onDidDismiss,onDidDismiss() => Promise> ion-popover,method,onWillDismiss,onWillDismiss() => Promise> -ion-popover,method,present,present() => Promise +ion-popover,method,present,present(event?: MouseEvent | TouchEvent | PointerEvent | undefined) => Promise ion-popover,event,didDismiss,OverlayEventDetail,true ion-popover,event,didPresent,void,true ion-popover,event,ionPopoverDidDismiss,OverlayEventDetail,true diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 5eeb4bd5f1..5b7ac19d42 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -1829,9 +1829,9 @@ export namespace Components { "onWillDismiss": () => Promise>; "overlayIndex": number; /** - * Present the popover overlay after it has been created. + * Present the popover overlay after it has been created. Developers can pass a mouse, touch, or pointer event to position the popover relative to where that event was dispatched. */ - "present": () => Promise; + "present": (event?: MouseEvent | TouchEvent | PointerEvent | undefined) => Promise; /** * When opening a popover from a trigger, we should not be modifying the `event` prop from inside the component. Additionally, when pressing the "Right" arrow key, we need to shift focus to the first descendant in the newly presented popover. */ diff --git a/core/src/components/popover/popover-interface.ts b/core/src/components/popover/popover-interface.ts index a5e31a4a56..2689f7217e 100644 --- a/core/src/components/popover/popover-interface.ts +++ b/core/src/components/popover/popover-interface.ts @@ -1,4 +1,8 @@ -import { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, Mode } from '../../interface'; +import { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, Mode, OverlayInterface } from '../../interface'; + +export interface PopoverInterface extends OverlayInterface { + present: (event?: MouseEvent | TouchEvent | PointerEvent) => Promise; +} export interface PopoverOptions { component: T; diff --git a/core/src/components/popover/popover.tsx b/core/src/components/popover/popover.tsx index f69a75652e..0446defc73 100644 --- a/core/src/components/popover/popover.tsx +++ b/core/src/components/popover/popover.tsx @@ -1,7 +1,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, State, Watch, h } from '@stencil/core'; import { getIonMode } from '../../global/ionic-global'; -import { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, OverlayEventDetail, OverlayInterface, PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAction } from '../../interface'; +import { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, OverlayEventDetail, PopoverInterface, PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAction } from '../../interface'; import { CoreDelegate, attachComponent, detachComponent } from '../../utils/framework-delegate'; import { addEventListener, raf } from '../../utils/helpers'; import { BACKDROP, dismiss, eventMethod, focusFirstDescendant, prepareOverlay, present } from '../../utils/overlays'; @@ -32,7 +32,7 @@ import { configureDismissInteraction, configureKeyboardInteraction, configureTri }, shadow: true }) -export class Popover implements ComponentInterface, OverlayInterface { +export class Popover implements ComponentInterface, PopoverInterface { private usersElement?: HTMLElement; private triggerEl?: HTMLElement | null; @@ -48,7 +48,6 @@ export class Popover implements ComponentInterface, OverlayInterface { private inline = false; private workingDelegate?: FrameworkDelegate; - private triggerEv?: Event; private focusDescendantOnPresent = false; lastFocus?: HTMLElement; @@ -305,12 +304,10 @@ export class Popover implements ComponentInterface, OverlayInterface { */ @Method() async presentFromTrigger(event?: any, focusDescendant = false) { - this.triggerEv = event; this.focusDescendantOnPresent = focusDescendant; - await this.present(); + await this.present(event); - this.triggerEv = undefined; this.focusDescendantOnPresent = false; } @@ -349,9 +346,12 @@ export class Popover implements ComponentInterface, OverlayInterface { /** * Present the popover overlay after it has been created. + * Developers can pass a mouse, touch, or pointer event + * to position the popover relative to where that event + * was dispatched. */ @Method() - async present(): Promise { + async present(event?: MouseEvent | TouchEvent | PointerEvent): Promise { if (this.presented) { return; } @@ -381,7 +381,7 @@ export class Popover implements ComponentInterface, OverlayInterface { this.configureDismissInteraction(); this.currentTransition = present(this, 'popoverEnter', iosEnterAnimation, mdEnterAnimation, { - event: this.event || this.triggerEv, + event: event || this.event, size: this.size, trigger: this.triggerEl, reference: this.reference, diff --git a/core/src/components/popover/readme.md b/core/src/components/popover/readme.md index 2bcc277146..02ec222caa 100644 --- a/core/src/components/popover/readme.md +++ b/core/src/components/popover/readme.md @@ -577,9 +577,12 @@ Type: `Promise>` -### `present() => Promise` +### `present(event?: MouseEvent | TouchEvent | PointerEvent | undefined) => Promise` Present the popover overlay after it has been created. +Developers can pass a mouse, touch, or pointer event +to position the popover relative to where that event +was dispatched. #### Returns diff --git a/core/src/components/popover/test/inline/e2e.ts b/core/src/components/popover/test/inline/e2e.ts index 0ba38679e3..69b5fc90d2 100644 --- a/core/src/components/popover/test/inline/e2e.ts +++ b/core/src/components/popover/test/inline/e2e.ts @@ -1,10 +1,10 @@ import { newE2EPage } from '@stencil/core/testing'; -test('popover: inline', async () => { +test('popover: inline, isOpen and event props', async () => { const page = await newE2EPage({ url: '/src/components/popover/test/inline?ionic:_testing=true' }); const screenshotCompares = []; - await page.click('ion-button'); + await page.click('ion-button#props'); await page.waitForSelector('ion-popover'); let popover = await page.find('ion-popover'); @@ -21,7 +21,43 @@ test('popover: inline', async () => { popover = await page.find('ion-popover'); - await page.click('ion-button'); + await page.click('ion-button#props'); + await page.waitForSelector('ion-popover'); + + let popoverAgain = await page.find('ion-popover'); + + expect(popoverAgain).not.toBe(null); + await popoverAgain.waitForVisible(); + + screenshotCompares.push(await page.compareScreenshot()); + + for (const screenshotCompare of screenshotCompares) { + expect(screenshotCompare).toMatchScreenshot(); + } +}); + +test('popover: inline, present method', async () => { + const page = await newE2EPage({ url: '/src/components/popover/test/inline?ionic:_testing=true' }); + const screenshotCompares = []; + + await page.click('ion-button#method'); + await page.waitForSelector('ion-popover'); + + let popover = await page.find('ion-popover'); + + expect(popover).not.toBe(null); + await popover.waitForVisible(); + + screenshotCompares.push(await page.compareScreenshot()); + + await popover.callMethod('dismiss'); + await popover.waitForNotVisible(); + + screenshotCompares.push(await page.compareScreenshot('dismiss')); + + popover = await page.find('ion-popover'); + + await page.click('ion-button#method'); await page.waitForSelector('ion-popover'); let popoverAgain = await page.find('ion-popover'); diff --git a/core/src/components/popover/test/inline/index.html b/core/src/components/popover/test/inline/index.html index 29b28290ce..b7c62b377f 100644 --- a/core/src/components/popover/test/inline/index.html +++ b/core/src/components/popover/test/inline/index.html @@ -18,7 +18,8 @@ - Open Popover + Open Popover via Props + Open Popover via Present Method @@ -35,6 +36,10 @@ popover.event = ev; } + const openPopoverMethod = (ev) => { + popover.present(ev); + } + popover.addEventListener('didDismiss', () => { popover.isOpen = false; popover.event = undefined;