feat(popover): add ability to pass event to present method (#23827)

resolves #23813
This commit is contained in:
Liam DeBeasi
2021-08-26 16:22:04 -04:00
committed by GitHub
parent 950350a948
commit 1d2ee92ca0
7 changed files with 65 additions and 17 deletions

View File

@ -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<boolean> ion-popover,method,dismiss,dismiss(data?: any, role?: string | undefined, dismissParentPopover?: boolean) => Promise<boolean>
ion-popover,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>> ion-popover,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-popover,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>> ion-popover,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-popover,method,present,present() => Promise<void> ion-popover,method,present,present(event?: MouseEvent | TouchEvent | PointerEvent | undefined) => Promise<void>
ion-popover,event,didDismiss,OverlayEventDetail<any>,true ion-popover,event,didDismiss,OverlayEventDetail<any>,true
ion-popover,event,didPresent,void,true ion-popover,event,didPresent,void,true
ion-popover,event,ionPopoverDidDismiss,OverlayEventDetail<any>,true ion-popover,event,ionPopoverDidDismiss,OverlayEventDetail<any>,true

View File

@ -1829,9 +1829,9 @@ export namespace Components {
"onWillDismiss": <T = any>() => Promise<OverlayEventDetail<T>>; "onWillDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
"overlayIndex": number; "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<void>; "present": (event?: MouseEvent | TouchEvent | PointerEvent | undefined) => Promise<void>;
/** /**
* 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. * 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.
*/ */

View File

@ -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<void>;
}
export interface PopoverOptions<T extends ComponentRef = ComponentRef> { export interface PopoverOptions<T extends ComponentRef = ComponentRef> {
component: T; component: T;

View File

@ -1,7 +1,7 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, State, Watch, h } from '@stencil/core'; import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, State, Watch, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global'; 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 { CoreDelegate, attachComponent, detachComponent } from '../../utils/framework-delegate';
import { addEventListener, raf } from '../../utils/helpers'; import { addEventListener, raf } from '../../utils/helpers';
import { BACKDROP, dismiss, eventMethod, focusFirstDescendant, prepareOverlay, present } from '../../utils/overlays'; import { BACKDROP, dismiss, eventMethod, focusFirstDescendant, prepareOverlay, present } from '../../utils/overlays';
@ -32,7 +32,7 @@ import { configureDismissInteraction, configureKeyboardInteraction, configureTri
}, },
shadow: true shadow: true
}) })
export class Popover implements ComponentInterface, OverlayInterface { export class Popover implements ComponentInterface, PopoverInterface {
private usersElement?: HTMLElement; private usersElement?: HTMLElement;
private triggerEl?: HTMLElement | null; private triggerEl?: HTMLElement | null;
@ -48,7 +48,6 @@ export class Popover implements ComponentInterface, OverlayInterface {
private inline = false; private inline = false;
private workingDelegate?: FrameworkDelegate; private workingDelegate?: FrameworkDelegate;
private triggerEv?: Event;
private focusDescendantOnPresent = false; private focusDescendantOnPresent = false;
lastFocus?: HTMLElement; lastFocus?: HTMLElement;
@ -305,12 +304,10 @@ export class Popover implements ComponentInterface, OverlayInterface {
*/ */
@Method() @Method()
async presentFromTrigger(event?: any, focusDescendant = false) { async presentFromTrigger(event?: any, focusDescendant = false) {
this.triggerEv = event;
this.focusDescendantOnPresent = focusDescendant; this.focusDescendantOnPresent = focusDescendant;
await this.present(); await this.present(event);
this.triggerEv = undefined;
this.focusDescendantOnPresent = false; this.focusDescendantOnPresent = false;
} }
@ -349,9 +346,12 @@ export class Popover implements ComponentInterface, OverlayInterface {
/** /**
* 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.
*/ */
@Method() @Method()
async present(): Promise<void> { async present(event?: MouseEvent | TouchEvent | PointerEvent): Promise<void> {
if (this.presented) { if (this.presented) {
return; return;
} }
@ -381,7 +381,7 @@ export class Popover implements ComponentInterface, OverlayInterface {
this.configureDismissInteraction(); this.configureDismissInteraction();
this.currentTransition = present(this, 'popoverEnter', iosEnterAnimation, mdEnterAnimation, { this.currentTransition = present(this, 'popoverEnter', iosEnterAnimation, mdEnterAnimation, {
event: this.event || this.triggerEv, event: event || this.event,
size: this.size, size: this.size,
trigger: this.triggerEl, trigger: this.triggerEl,
reference: this.reference, reference: this.reference,

View File

@ -577,9 +577,12 @@ Type: `Promise<OverlayEventDetail<T>>`
### `present() => Promise<void>` ### `present(event?: MouseEvent | TouchEvent | PointerEvent | undefined) => Promise<void>`
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.
#### Returns #### Returns

View File

@ -1,10 +1,10 @@
import { newE2EPage } from '@stencil/core/testing'; 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 page = await newE2EPage({ url: '/src/components/popover/test/inline?ionic:_testing=true' });
const screenshotCompares = []; const screenshotCompares = [];
await page.click('ion-button'); await page.click('ion-button#props');
await page.waitForSelector('ion-popover'); await page.waitForSelector('ion-popover');
let popover = await page.find('ion-popover'); let popover = await page.find('ion-popover');
@ -21,7 +21,43 @@ test('popover: inline', async () => {
popover = await page.find('ion-popover'); 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'); await page.waitForSelector('ion-popover');
let popoverAgain = await page.find('ion-popover'); let popoverAgain = await page.find('ion-popover');

View File

@ -18,7 +18,8 @@
</ion-header> </ion-header>
<ion-content class="ion-padding"> <ion-content class="ion-padding">
<ion-button onclick="openPopover(event)">Open Popover</ion-button> <ion-button id="props" onclick="openPopover(event)">Open Popover via Props</ion-button>
<ion-button id="method" onclick="openPopoverMethod(event)">Open Popover via Present Method</ion-button>
<ion-popover> <ion-popover>
<ion-content class="ion-padding"> <ion-content class="ion-padding">
@ -35,6 +36,10 @@
popover.event = ev; popover.event = ev;
} }
const openPopoverMethod = (ev) => {
popover.present(ev);
}
popover.addEventListener('didDismiss', () => { popover.addEventListener('didDismiss', () => {
popover.isOpen = false; popover.isOpen = false;
popover.event = undefined; popover.event = undefined;