UNPKG

@ionic/core

Version:

Base components for Ionic

555 lines (554 loc) • 16.4 kB
import { Component, Element, Event, Host, Method, Prop, h } from '@stencil/core'; import { getIonMode } from '../../global/ionic-global'; import { attachComponent, detachComponent } from '../../utils/framework-delegate'; import { BACKDROP, dismiss, eventMethod, prepareOverlay, present } from '../../utils/overlays'; import { getClassMap } from '../../utils/theme'; import { deepReady } from '../../utils/transition'; import { iosEnterAnimation } from './animations/ios.enter'; import { iosLeaveAnimation } from './animations/ios.leave'; import { mdEnterAnimation } from './animations/md.enter'; import { mdLeaveAnimation } from './animations/md.leave'; /** * @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use. */ export class Popover { constructor() { this.presented = false; /** * If `true`, the keyboard will be automatically dismissed when the overlay is presented. */ this.keyboardClose = true; /** * If `true`, the popover will be dismissed when the backdrop is clicked. */ this.backdropDismiss = true; /** * If `true`, a backdrop will be displayed behind the popover. */ this.showBackdrop = true; /** * If `true`, the popover will be translucent. * Only applies when the mode is `"ios"` and the device supports * [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility). */ this.translucent = false; /** * If `true`, the popover will animate. */ this.animated = true; this.onDismiss = (ev) => { ev.stopPropagation(); ev.preventDefault(); this.dismiss(); }; this.onBackdropTap = () => { this.dismiss(undefined, BACKDROP); }; this.onLifecycle = (modalEvent) => { const el = this.usersElement; const name = LIFECYCLE_MAP[modalEvent.type]; if (el && name) { const event = new CustomEvent(name, { bubbles: false, cancelable: false, detail: modalEvent.detail }); el.dispatchEvent(event); } }; } connectedCallback() { prepareOverlay(this.el); } /** * Present the popover overlay after it has been created. */ async present() { if (this.presented) { return; } const container = this.el.querySelector('.popover-content'); if (!container) { throw new Error('container is undefined'); } const data = Object.assign(Object.assign({}, this.componentProps), { popover: this.el }); this.usersElement = await attachComponent(this.delegate, container, this.component, ['popover-viewport', this.el['s-sc']], data); await deepReady(this.usersElement); return present(this, 'popoverEnter', iosEnterAnimation, mdEnterAnimation, this.event); } /** * Dismiss the popover overlay after it has been presented. * * @param data Any data to emit in the dismiss events. * @param role The role of the element that is dismissing the popover. For example, 'cancel' or 'backdrop'. */ async dismiss(data, role) { const shouldDismiss = await dismiss(this, data, role, 'popoverLeave', iosLeaveAnimation, mdLeaveAnimation, this.event); if (shouldDismiss) { await detachComponent(this.delegate, this.usersElement); } return shouldDismiss; } /** * Returns a promise that resolves when the popover did dismiss. */ onDidDismiss() { return eventMethod(this.el, 'ionPopoverDidDismiss'); } /** * Returns a promise that resolves when the popover will dismiss. */ onWillDismiss() { return eventMethod(this.el, 'ionPopoverWillDismiss'); } render() { const mode = getIonMode(this); const { onLifecycle } = this; return (h(Host, { "aria-modal": "true", "no-router": true, tabindex: "-1", style: { zIndex: `${20000 + this.overlayIndex}`, }, class: Object.assign(Object.assign({}, getClassMap(this.cssClass)), { [mode]: true, 'popover-translucent': this.translucent }), onIonPopoverDidPresent: onLifecycle, onIonPopoverWillPresent: onLifecycle, onIonPopoverWillDismiss: onLifecycle, onIonPopoverDidDismiss: onLifecycle, onIonDismiss: this.onDismiss, onIonBackdropTap: this.onBackdropTap }, h("ion-backdrop", { tappable: this.backdropDismiss, visible: this.showBackdrop }), h("div", { tabindex: "0" }), h("div", { class: "popover-wrapper ion-overlay-wrapper" }, h("div", { class: "popover-arrow" }), h("div", { class: "popover-content" })), h("div", { tabindex: "0" }))); } static get is() { return "ion-popover"; } static get encapsulation() { return "scoped"; } static get originalStyleUrls() { return { "ios": ["popover.ios.scss"], "md": ["popover.md.scss"] }; } static get styleUrls() { return { "ios": ["popover.ios.css"], "md": ["popover.md.css"] }; } static get properties() { return { "delegate": { "type": "unknown", "mutable": false, "complexType": { "original": "FrameworkDelegate", "resolved": "FrameworkDelegate | undefined", "references": { "FrameworkDelegate": { "location": "import", "path": "../../interface" } } }, "required": false, "optional": true, "docs": { "tags": [{ "text": undefined, "name": "internal" }], "text": "" } }, "overlayIndex": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": true, "optional": false, "docs": { "tags": [{ "text": undefined, "name": "internal" }], "text": "" }, "attribute": "overlay-index", "reflect": false }, "enterAnimation": { "type": "unknown", "mutable": false, "complexType": { "original": "AnimationBuilder", "resolved": "((baseEl: any, opts?: any) => Animation) | undefined", "references": { "AnimationBuilder": { "location": "import", "path": "../../interface" } } }, "required": false, "optional": true, "docs": { "tags": [], "text": "Animation to use when the popover is presented." } }, "leaveAnimation": { "type": "unknown", "mutable": false, "complexType": { "original": "AnimationBuilder", "resolved": "((baseEl: any, opts?: any) => Animation) | undefined", "references": { "AnimationBuilder": { "location": "import", "path": "../../interface" } } }, "required": false, "optional": true, "docs": { "tags": [], "text": "Animation to use when the popover is dismissed." } }, "component": { "type": "string", "mutable": false, "complexType": { "original": "ComponentRef", "resolved": "Function | HTMLElement | null | string", "references": { "ComponentRef": { "location": "import", "path": "../../interface" } } }, "required": true, "optional": false, "docs": { "tags": [], "text": "The component to display inside of the popover." }, "attribute": "component", "reflect": false }, "componentProps": { "type": "unknown", "mutable": false, "complexType": { "original": "ComponentProps", "resolved": "undefined | { [key: string]: any; }", "references": { "ComponentProps": { "location": "import", "path": "../../interface" } } }, "required": false, "optional": true, "docs": { "tags": [], "text": "The data to pass to the popover component." } }, "keyboardClose": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "If `true`, the keyboard will be automatically dismissed when the overlay is presented." }, "attribute": "keyboard-close", "reflect": false, "defaultValue": "true" }, "cssClass": { "type": "string", "mutable": false, "complexType": { "original": "string | string[]", "resolved": "string | string[] | undefined", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Additional classes to apply for custom CSS. If multiple classes are\nprovided they should be separated by spaces." }, "attribute": "css-class", "reflect": false }, "backdropDismiss": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "If `true`, the popover will be dismissed when the backdrop is clicked." }, "attribute": "backdrop-dismiss", "reflect": false, "defaultValue": "true" }, "event": { "type": "any", "mutable": false, "complexType": { "original": "any", "resolved": "any", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The event to pass to the popover animation." }, "attribute": "event", "reflect": false }, "showBackdrop": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "If `true`, a backdrop will be displayed behind the popover." }, "attribute": "show-backdrop", "reflect": false, "defaultValue": "true" }, "translucent": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "If `true`, the popover will be translucent.\nOnly applies when the mode is `\"ios\"` and the device supports\n[`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility)." }, "attribute": "translucent", "reflect": false, "defaultValue": "false" }, "animated": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "If `true`, the popover will animate." }, "attribute": "animated", "reflect": false, "defaultValue": "true" } }; } static get events() { return [{ "method": "didPresent", "name": "ionPopoverDidPresent", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted after the popover has presented." }, "complexType": { "original": "void", "resolved": "void", "references": {} } }, { "method": "willPresent", "name": "ionPopoverWillPresent", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted before the popover has presented." }, "complexType": { "original": "void", "resolved": "void", "references": {} } }, { "method": "willDismiss", "name": "ionPopoverWillDismiss", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted before the popover has dismissed." }, "complexType": { "original": "OverlayEventDetail", "resolved": "OverlayEventDetail<any>", "references": { "OverlayEventDetail": { "location": "import", "path": "../../interface" } } } }, { "method": "didDismiss", "name": "ionPopoverDidDismiss", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted after the popover has dismissed." }, "complexType": { "original": "OverlayEventDetail", "resolved": "OverlayEventDetail<any>", "references": { "OverlayEventDetail": { "location": "import", "path": "../../interface" } } } }]; } static get methods() { return { "present": { "complexType": { "signature": "() => Promise<void>", "parameters": [], "references": { "Promise": { "location": "global" } }, "return": "Promise<void>" }, "docs": { "text": "Present the popover overlay after it has been created.", "tags": [] } }, "dismiss": { "complexType": { "signature": "(data?: any, role?: string | undefined) => Promise<boolean>", "parameters": [{ "tags": [{ "text": "data Any data to emit in the dismiss events.", "name": "param" }], "text": "Any data to emit in the dismiss events." }, { "tags": [{ "text": "role The role of the element that is dismissing the popover. For example, 'cancel' or 'backdrop'.", "name": "param" }], "text": "The role of the element that is dismissing the popover. For example, 'cancel' or 'backdrop'." }], "references": { "Promise": { "location": "global" } }, "return": "Promise<boolean>" }, "docs": { "text": "Dismiss the popover overlay after it has been presented.", "tags": [{ "name": "param", "text": "data Any data to emit in the dismiss events." }, { "name": "param", "text": "role The role of the element that is dismissing the popover. For example, 'cancel' or 'backdrop'." }] } }, "onDidDismiss": { "complexType": { "signature": "<T = any>() => Promise<OverlayEventDetail<T>>", "parameters": [], "references": { "Promise": { "location": "global" }, "OverlayEventDetail": { "location": "import", "path": "../../interface" }, "T": { "location": "global" } }, "return": "Promise<OverlayEventDetail<T>>" }, "docs": { "text": "Returns a promise that resolves when the popover did dismiss.", "tags": [] } }, "onWillDismiss": { "complexType": { "signature": "<T = any>() => Promise<OverlayEventDetail<T>>", "parameters": [], "references": { "Promise": { "location": "global" }, "OverlayEventDetail": { "location": "import", "path": "../../interface" }, "T": { "location": "global" } }, "return": "Promise<OverlayEventDetail<T>>" }, "docs": { "text": "Returns a promise that resolves when the popover will dismiss.", "tags": [] } } }; } static get elementRef() { return "el"; } } const LIFECYCLE_MAP = { 'ionPopoverDidPresent': 'ionViewDidEnter', 'ionPopoverWillPresent': 'ionViewWillEnter', 'ionPopoverWillDismiss': 'ionViewWillLeave', 'ionPopoverDidDismiss': 'ionViewDidLeave', };