import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core'; import { ActionSheetButton, Animation, AnimationBuilder, Config, CssClassMap, Mode, OverlayEventDetail, OverlayInterface } from '../../interface'; import { BACKDROP, dismiss, eventMethod, isCancel, present } from '../../utils/overlays'; import { getClassMap } from '../../utils/theme'; import { iosEnterAnimation } from './animations/ios.enter'; import { iosLeaveAnimation } from './animations/ios.leave'; import { mdEnterAnimation } from './animations/md.enter'; import { mdLeaveAnimation } from './animations/md.leave'; @Component({ tag: 'ion-action-sheet', styleUrls: { ios: 'action-sheet.ios.scss', md: 'action-sheet.md.scss' }, scoped: true }) export class ActionSheet implements OverlayInterface { presented = false; animation?: Animation; @Element() el!: HTMLElement; @Prop({ connect: 'ion-animation-controller' }) animationCtrl!: HTMLIonAnimationControllerElement; @Prop({ context: 'config' }) config!: Config; @Prop() overlayIndex!: number; /** * The mode determines which platform styles to use. * Possible values are: `"ios"` or `"md"`. */ @Prop() mode!: Mode; /** * If true, the keyboard will be automatically dismissed when the overlay is presented. */ @Prop() keyboardClose = true; /** * Animation to use when the action sheet is presented. */ @Prop() enterAnimation?: AnimationBuilder; /** * Animation to use when the action sheet is dismissed. */ @Prop() leaveAnimation?: AnimationBuilder; /** * An array of buttons for the action sheet. */ @Prop() buttons!: (ActionSheetButton | string)[]; /** * Additional classes to apply for custom CSS. If multiple classes are * provided they should be separated by spaces. */ @Prop() cssClass?: string | string[]; /** * If true, the action sheet will be dismissed when the backdrop is clicked. Defaults to `true`. */ @Prop() backdropDismiss = true; /** * Title for the action sheet. */ @Prop() header?: string; /** * Subtitle for the action sheet. */ @Prop() subHeader?: string; /** * If true, the action sheet will be translucent. Defaults to `false`. */ @Prop() translucent = false; /** * If true, the action sheet will animate. Defaults to `true`. */ @Prop() animated = true; /** * Emitted after the alert has loaded. */ @Event() ionActionSheetDidLoad!: EventEmitter; /** * Emitted after the alert has unloaded. */ @Event() ionActionSheetDidUnload!: EventEmitter; /** * Emitted after the alert has presented. */ @Event({ eventName: 'ionActionSheetDidPresent' }) didPresent!: EventEmitter; /** * Emitted before the alert has presented. */ @Event({ eventName: 'ionActionSheetWillPresent' }) willPresent!: EventEmitter; /** * Emitted before the alert has dismissed. */ @Event({ eventName: 'ionActionSheetWillDismiss' }) willDismiss!: EventEmitter; /** * Emitted after the alert has dismissed. */ @Event({ eventName: 'ionActionSheetDidDismiss' }) didDismiss!: EventEmitter; componentDidLoad() { this.ionActionSheetDidLoad.emit(); } componentDidUnload() { this.ionActionSheetDidUnload.emit(); } @Listen('ionBackdropTap') protected onBackdropTap() { return this.dismiss(undefined, BACKDROP); } @Listen('ionActionSheetWillDismiss') protected dispatchCancelHandler(ev: CustomEvent) { const role = ev.detail.role; if (isCancel(role)) { const cancelButton = this.getButtons().find(b => b.role === 'cancel'); this.callButtonHandler(cancelButton); } } /** * Present the action sheet overlay after it has been created. */ @Method() present(): Promise { return present(this, 'actionSheetEnter', iosEnterAnimation, mdEnterAnimation); } /** * Dismiss the action sheet overlay after it has been presented. */ @Method() dismiss(data?: any, role?: string): Promise { return dismiss(this, data, role, 'actionSheetLeave', iosLeaveAnimation, mdLeaveAnimation); } /** * Returns a promise that resolves when the action-sheet did dismiss. */ @Method() onDidDismiss(): Promise { return eventMethod(this.el, 'ionActionSheetDidDismiss'); } /** * Returns a promise that resolves when the action-sheet will dismiss. * */ @Method() onWillDismiss(): Promise { return eventMethod(this.el, 'ionActionSheetWillDismiss'); } private buttonClick(button: ActionSheetButton) { const role = button.role; if (isCancel(role)) { return this.dismiss(undefined, role); } const shouldDismiss = this.callButtonHandler(button); if (shouldDismiss) { return this.dismiss(undefined, button.role); } return Promise.resolve(); } private callButtonHandler(button: ActionSheetButton | undefined): boolean { if (button && button.handler) { // a handler has been provided, execute it // pass the handler the values from the inputs try { if (button.handler() === false) { // if the return value of the handler is false then do not dismiss return false; } } catch (e) { console.error(e); } } return true; } private getButtons(): ActionSheetButton[] { return this.buttons.map(b => { return (typeof b === 'string') ? { text: b } : b; }); } hostData() { return { style: { zIndex: 20000 + this.overlayIndex, }, class: { ...getClassMap(this.cssClass), 'action-sheet-translucent': this.translucent } }; } render() { const allButtons = this.getButtons(); const cancelButton = allButtons.find(b => b.role === 'cancel'); const buttons = allButtons.filter(b => b.role !== 'cancel'); return [ , ]; } } function buttonClass(button: ActionSheetButton): CssClassMap { return { 'action-sheet-button': true, [`action-sheet-${button.role}`]: button.role !== undefined, ...getClassMap(button.cssClass), }; }