UNPKG

@ionic/core

Version:

Base components for Ionic

587 lines (586 loc) • 17.6 kB
import { Component, Element, Event, Host, Method, Prop, State, h } from '@stencil/core'; import { getIonMode } from '../../global/ionic-global'; import { BACKDROP, dismiss, eventMethod, isCancel, prepareOverlay, present, safeCall } from '../../utils/overlays'; import { getClassMap } from '../../utils/theme'; import { iosEnterAnimation } from './animations/ios.enter'; import { iosLeaveAnimation } from './animations/ios.leave'; /** * @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use. */ export class Picker { constructor() { this.presented = false; /** * If `true`, the keyboard will be automatically dismissed when the overlay is presented. */ this.keyboardClose = true; /** * Array of buttons to be displayed at the top of the picker. */ this.buttons = []; /** * Array of columns to be displayed in the picker. */ this.columns = []; /** * Number of milliseconds to wait before dismissing the picker. */ this.duration = 0; /** * If `true`, a backdrop will be displayed behind the picker. */ this.showBackdrop = true; /** * If `true`, the picker will be dismissed when the backdrop is clicked. */ this.backdropDismiss = true; /** * If `true`, the picker will animate. */ this.animated = true; this.onBackdropTap = () => { this.dismiss(undefined, BACKDROP); }; this.dispatchCancelHandler = (ev) => { const role = ev.detail.role; if (isCancel(role)) { const cancelButton = this.buttons.find(b => b.role === 'cancel'); this.callButtonHandler(cancelButton); } }; } connectedCallback() { prepareOverlay(this.el); } /** * Present the picker overlay after it has been created. */ async present() { await present(this, 'pickerEnter', iosEnterAnimation, iosEnterAnimation, undefined); if (this.duration > 0) { this.durationTimeout = setTimeout(() => this.dismiss(), this.duration); } } /** * Dismiss the picker 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 picker. * This can be useful in a button handler for determining which button was * clicked to dismiss the picker. * Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`. */ dismiss(data, role) { if (this.durationTimeout) { clearTimeout(this.durationTimeout); } return dismiss(this, data, role, 'pickerLeave', iosLeaveAnimation, iosLeaveAnimation); } /** * Returns a promise that resolves when the picker did dismiss. */ onDidDismiss() { return eventMethod(this.el, 'ionPickerDidDismiss'); } /** * Returns a promise that resolves when the picker will dismiss. */ onWillDismiss() { return eventMethod(this.el, 'ionPickerWillDismiss'); } /** * Get the column that matches the specified name. * * @param name The name of the column. */ getColumn(name) { return Promise.resolve(this.columns.find(column => column.name === name)); } async buttonClick(button) { const role = button.role; if (isCancel(role)) { return this.dismiss(undefined, role); } const shouldDismiss = await this.callButtonHandler(button); if (shouldDismiss) { return this.dismiss(this.getSelected(), button.role); } return Promise.resolve(); } async callButtonHandler(button) { if (button) { // a handler has been provided, execute it // pass the handler the values from the inputs const rtn = await safeCall(button.handler, this.getSelected()); if (rtn === false) { // if the return value of the handler is false then do not dismiss return false; } } return true; } getSelected() { const selected = {}; this.columns.forEach((col, index) => { const selectedColumn = col.selectedIndex !== undefined ? col.options[col.selectedIndex] : undefined; selected[col.name] = { text: selectedColumn ? selectedColumn.text : undefined, value: selectedColumn ? selectedColumn.value : undefined, columnIndex: index }; }); return selected; } render() { const mode = getIonMode(this); return (h(Host, { "aria-modal": "true", tabindex: "-1", class: Object.assign({ [mode]: true, // Used internally for styling [`picker-${mode}`]: true }, getClassMap(this.cssClass)), style: { zIndex: `${20000 + this.overlayIndex}` }, onIonBackdropTap: this.onBackdropTap, onIonPickerWillDismiss: this.dispatchCancelHandler }, h("ion-backdrop", { visible: this.showBackdrop, tappable: this.backdropDismiss }), h("div", { tabindex: "0" }), h("div", { class: "picker-wrapper ion-overlay-wrapper", role: "dialog" }, h("div", { class: "picker-toolbar" }, this.buttons.map(b => (h("div", { class: buttonWrapperClass(b) }, h("button", { type: "button", onClick: () => this.buttonClick(b), class: buttonClass(b) }, b.text))))), h("div", { class: "picker-columns" }, h("div", { class: "picker-above-highlight" }), this.presented && this.columns.map(c => h("ion-picker-column", { col: c })), h("div", { class: "picker-below-highlight" }))), h("div", { tabindex: "0" }))); } static get is() { return "ion-picker"; } static get encapsulation() { return "scoped"; } static get originalStyleUrls() { return { "ios": ["picker.ios.scss"], "md": ["picker.md.scss"] }; } static get styleUrls() { return { "ios": ["picker.ios.css"], "md": ["picker.md.css"] }; } static get properties() { return { "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 }, "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" }, "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 picker 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 picker is dismissed." } }, "buttons": { "type": "unknown", "mutable": false, "complexType": { "original": "PickerButton[]", "resolved": "PickerButton[]", "references": { "PickerButton": { "location": "import", "path": "../../interface" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Array of buttons to be displayed at the top of the picker." }, "defaultValue": "[]" }, "columns": { "type": "unknown", "mutable": false, "complexType": { "original": "PickerColumn[]", "resolved": "PickerColumn[]", "references": { "PickerColumn": { "location": "import", "path": "../../interface" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Array of columns to be displayed in the picker." }, "defaultValue": "[]" }, "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 }, "duration": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Number of milliseconds to wait before dismissing the picker." }, "attribute": "duration", "reflect": false, "defaultValue": "0" }, "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 picker." }, "attribute": "show-backdrop", "reflect": false, "defaultValue": "true" }, "backdropDismiss": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "If `true`, the picker will be dismissed when the backdrop is clicked." }, "attribute": "backdrop-dismiss", "reflect": false, "defaultValue": "true" }, "animated": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "If `true`, the picker will animate." }, "attribute": "animated", "reflect": false, "defaultValue": "true" } }; } static get states() { return { "presented": {} }; } static get events() { return [{ "method": "didPresent", "name": "ionPickerDidPresent", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted after the picker has presented." }, "complexType": { "original": "void", "resolved": "void", "references": {} } }, { "method": "willPresent", "name": "ionPickerWillPresent", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted before the picker has presented." }, "complexType": { "original": "void", "resolved": "void", "references": {} } }, { "method": "willDismiss", "name": "ionPickerWillDismiss", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted before the picker has dismissed." }, "complexType": { "original": "OverlayEventDetail", "resolved": "OverlayEventDetail<any>", "references": { "OverlayEventDetail": { "location": "import", "path": "../../interface" } } } }, { "method": "didDismiss", "name": "ionPickerDidDismiss", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted after the picker 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 picker 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 picker.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the picker.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`.", "name": "param" }], "text": "The role of the element that is dismissing the picker.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the picker.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`." }], "references": { "Promise": { "location": "global" } }, "return": "Promise<boolean>" }, "docs": { "text": "Dismiss the picker 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 picker.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the picker.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"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 picker 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 picker will dismiss.", "tags": [] } }, "getColumn": { "complexType": { "signature": "(name: string) => Promise<PickerColumn | undefined>", "parameters": [{ "tags": [{ "text": "name The name of the column.", "name": "param" }], "text": "The name of the column." }], "references": { "Promise": { "location": "global" }, "PickerColumn": { "location": "import", "path": "../../interface" } }, "return": "Promise<PickerColumn | undefined>" }, "docs": { "text": "Get the column that matches the specified name.", "tags": [{ "name": "param", "text": "name The name of the column." }] } } }; } static get elementRef() { return "el"; } } const buttonWrapperClass = (button) => { return { [`picker-toolbar-${button.role}`]: button.role !== undefined, 'picker-toolbar-button': true }; }; const buttonClass = (button) => { return Object.assign({ 'picker-button': true, 'ion-activatable': true }, getClassMap(button.cssClass)); };