@ionic/core
Version:
Base components for Ionic
587 lines (586 loc) • 17.6 kB
JavaScript
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));
};