mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-23 22:17:40 +08:00
refactor(toast): make api and events match other overlays
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
import { Component, Listen, Method } from '@stencil/core';
|
import { Component, Listen, Method } from '@stencil/core';
|
||||||
import { Toast, ToastEvent, ToastOptions } from '../../index';
|
import { ToastEvent, ToastOptions } from '../../index';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-toast-controller'
|
tag: 'ion-toast-controller'
|
||||||
@ -7,10 +7,10 @@ import { Toast, ToastEvent, ToastOptions } from '../../index';
|
|||||||
export class ToastController {
|
export class ToastController {
|
||||||
private ids = 0;
|
private ids = 0;
|
||||||
private toastResolves: { [toastId: string]: Function } = {};
|
private toastResolves: { [toastId: string]: Function } = {};
|
||||||
private toasts: Toast[] = [];
|
private toasts: HTMLIonToastElement[] = [];
|
||||||
|
|
||||||
@Method()
|
@Method()
|
||||||
create(opts?: ToastOptions) {
|
create(opts?: ToastOptions): Promise<HTMLIonToastElement> {
|
||||||
// create ionic's wrapping ion-toast component
|
// create ionic's wrapping ion-toast component
|
||||||
const toast = document.createElement('ion-toast');
|
const toast = document.createElement('ion-toast');
|
||||||
const id = this.ids++;
|
const id = this.ids++;
|
||||||
@ -28,14 +28,14 @@ export class ToastController {
|
|||||||
appRoot.appendChild(toast as any);
|
appRoot.appendChild(toast as any);
|
||||||
|
|
||||||
// store the resolve function to be called later up when the toast loads
|
// store the resolve function to be called later up when the toast loads
|
||||||
return new Promise<Toast>(resolve => {
|
return new Promise<HTMLIonToastElement>(resolve => {
|
||||||
this.toastResolves[toast.toastId] = resolve;
|
this.toastResolves[toast.toastId] = resolve;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Listen('body:ionToastDidLoad')
|
@Listen('body:ionToastDidLoad')
|
||||||
protected didLoad(ev: ToastEvent) {
|
protected didLoad(ev: ToastEvent) {
|
||||||
const toast = ev.detail.toast;
|
const toast = ev.target as HTMLIonToastElement;
|
||||||
const toastResolve = this.toastResolves[toast.toastId];
|
const toastResolve = this.toastResolves[toast.toastId];
|
||||||
if (toastResolve) {
|
if (toastResolve) {
|
||||||
toastResolve(toast);
|
toastResolve(toast);
|
||||||
@ -45,12 +45,12 @@ export class ToastController {
|
|||||||
|
|
||||||
@Listen('body:ionToastWillPresent')
|
@Listen('body:ionToastWillPresent')
|
||||||
protected willPresent(ev: ToastEvent) {
|
protected willPresent(ev: ToastEvent) {
|
||||||
this.toasts.push(ev.detail.toast);
|
this.toasts.push(ev.target as HTMLIonToastElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Listen('body:ionToastWillDismiss, body:ionToastDidUnload')
|
@Listen('body:ionToastWillDismiss, body:ionToastDidUnload')
|
||||||
protected willDismiss(ev: ToastEvent) {
|
protected willDismiss(ev: ToastEvent) {
|
||||||
const index = this.toasts.indexOf(ev.detail.toast);
|
const index = this.toasts.indexOf(ev.target as HTMLIonToastElement);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this.toasts.splice(index, 1);
|
this.toasts.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
@ -59,22 +59,22 @@
|
|||||||
</ion-page>
|
</ion-page>
|
||||||
</ion-app>
|
</ion-app>
|
||||||
<script>
|
<script>
|
||||||
function presentToast(position) {
|
async function presentToast(position) {
|
||||||
var toastController = document.querySelector('ion-toast-controller');
|
const toastController = document.querySelector('ion-toast-controller');
|
||||||
toastController.create({
|
await toastController.componentOnReady();
|
||||||
|
const toastElement = await toastController.create({
|
||||||
message: 'Hellooo',
|
message: 'Hellooo',
|
||||||
position,
|
position,
|
||||||
duration: 2000
|
duration: 2000
|
||||||
}).then(toast => {
|
|
||||||
toast.present();
|
|
||||||
});
|
});
|
||||||
|
return await toastElement.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
function presentToastWithOptions(opts) {
|
async function presentToastWithOptions(opts) {
|
||||||
var toastController = document.querySelector('ion-toast-controller');
|
const toastController = document.querySelector('ion-toast-controller');
|
||||||
toastController.create(opts).then(toast => {
|
await toastController.componentOnReady();
|
||||||
toast.present();
|
const toastElement = await toastController.create(opts);
|
||||||
});
|
return await toastElement.present();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
import { Component, Element, Event, EventEmitter, Listen, Prop } from '@stencil/core';
|
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
|
||||||
import { Animation, AnimationBuilder, AnimationController, Config, CssClassMap } from '../../index';
|
import {
|
||||||
|
Animation,
|
||||||
|
AnimationBuilder,
|
||||||
|
AnimationController,
|
||||||
|
Config,
|
||||||
|
CssClassMap,
|
||||||
|
OverlayDismissEvent,
|
||||||
|
OverlayDismissEventDetail
|
||||||
|
} from '../../index';
|
||||||
|
import { domControllerAsync, playAnimationAsync } from '../../utils/helpers';
|
||||||
|
|
||||||
import { createThemedClasses } from '../../utils/theme';
|
import { createThemedClasses } from '../../utils/theme';
|
||||||
|
|
||||||
@ -30,32 +39,32 @@ export class Toast {
|
|||||||
/**
|
/**
|
||||||
* @output {ToastEvent} Emitted after the toast has loaded.
|
* @output {ToastEvent} Emitted after the toast has loaded.
|
||||||
*/
|
*/
|
||||||
@Event() ionToastDidLoad: EventEmitter;
|
@Event() ionToastDidLoad: EventEmitter<ToastEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {ToastEvent} Emitted after the toast has presented.
|
* @output {ToastEvent} Emitted after the toast has presented.
|
||||||
*/
|
*/
|
||||||
@Event() ionToastDidPresent: EventEmitter;
|
@Event() ionToastDidPresent: EventEmitter<ToastEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {ToastEvent} Emitted before the toast has presented.
|
* @output {ToastEvent} Emitted before the toast has presented.
|
||||||
*/
|
*/
|
||||||
@Event() ionToastWillPresent: EventEmitter;
|
@Event() ionToastWillPresent: EventEmitter<ToastEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {ToastEvent} Emitted before the toast has dismissed.
|
* @output {ToastEvent} Emitted before the toast has dismissed.
|
||||||
*/
|
*/
|
||||||
@Event() ionToastWillDismiss: EventEmitter;
|
@Event() ionToastWillDismiss: EventEmitter<ToastDismissEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {ToastEvent} Emitted after the toast has dismissed.
|
* @output {ToastEvent} Emitted after the toast has dismissed.
|
||||||
*/
|
*/
|
||||||
@Event() ionToastDidDismiss: EventEmitter;
|
@Event() ionToastDidDismiss: EventEmitter<ToastDismissEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {ToastEvent} Emitted after the toast has unloaded.
|
* @output {ToastEvent} Emitted after the toast has unloaded.
|
||||||
*/
|
*/
|
||||||
@Event() ionToastDidUnload: EventEmitter;
|
@Event() ionToastDidUnload: EventEmitter<ToastEventDetail>;
|
||||||
|
|
||||||
@Prop({ connect: 'ion-animation-controller' }) animationCtrl: AnimationController;
|
@Prop({ connect: 'ion-animation-controller' }) animationCtrl: AnimationController;
|
||||||
@Prop({ context: 'config' }) config: Config;
|
@Prop({ context: 'config' }) config: Config;
|
||||||
@ -69,73 +78,73 @@ export class Toast {
|
|||||||
@Prop() position: string;
|
@Prop() position: string;
|
||||||
@Prop() translucent: boolean = false;
|
@Prop() translucent: boolean = false;
|
||||||
@Prop() toastId: string;
|
@Prop() toastId: string;
|
||||||
|
@Prop() animate: boolean;
|
||||||
|
|
||||||
@Prop() enterAnimation: AnimationBuilder;
|
@Prop() enterAnimation: AnimationBuilder;
|
||||||
@Prop() leaveAnimation: AnimationBuilder;
|
@Prop() leaveAnimation: AnimationBuilder;
|
||||||
|
|
||||||
|
@Method()
|
||||||
present() {
|
present() {
|
||||||
return new Promise<void>(resolve => {
|
|
||||||
this._present(resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _present(resolve: Function) {
|
|
||||||
if (this.animation) {
|
if (this.animation) {
|
||||||
this.animation.destroy();
|
this.animation.destroy();
|
||||||
this.animation = null;
|
this.animation = null;
|
||||||
}
|
}
|
||||||
this.ionToastWillPresent.emit({ toast: this });
|
this.ionToastWillPresent.emit();
|
||||||
|
|
||||||
// get the user's animation fn if one was provided
|
// get the user's animation fn if one was provided
|
||||||
const animationBuilder = this.enterAnimation || this.config.get('toastEnter', this.mode === 'ios' ? iosEnterAnimation : mdEnterAnimation);
|
const animationBuilder = this.enterAnimation || this.config.get('toastEnter', this.mode === 'ios' ? iosEnterAnimation : mdEnterAnimation);
|
||||||
|
|
||||||
// build the animation and kick it off
|
// build the animation and kick it off
|
||||||
this.animationCtrl.create(animationBuilder, this.el, this.position).then(animation => {
|
return this.animationCtrl.create(animationBuilder, this.el).then(animation => {
|
||||||
this.animation = animation;
|
this.animation = animation;
|
||||||
|
if (!this.animate) {
|
||||||
animation.onFinish((a: any) => {
|
// if the duration is 0, it won't actually animate I don't think
|
||||||
a.destroy();
|
// TODO - validate this
|
||||||
this.componentDidEnter();
|
this.animation = animation.duration(0);
|
||||||
resolve();
|
}
|
||||||
}).play();
|
return playAnimationAsync(animation);
|
||||||
|
}).then((animation) => {
|
||||||
|
animation.destroy();
|
||||||
|
this.componentDidEnter();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
dismiss() {
|
@Method()
|
||||||
|
dismiss(data?: any, role?: string) {
|
||||||
if (this.animation) {
|
if (this.animation) {
|
||||||
this.animation.destroy();
|
this.animation.destroy();
|
||||||
this.animation = null;
|
this.animation = null;
|
||||||
}
|
}
|
||||||
return new Promise(resolve => {
|
|
||||||
this.ionToastWillDismiss.emit({ toast: this });
|
|
||||||
|
|
||||||
// get the user's animation fn if one was provided
|
this.ionToastWillDismiss.emit({
|
||||||
const animationBuilder = this.leaveAnimation || this.config.get('toastLeave', this.mode === 'ios' ? iosLeaveAnimation : mdLeaveAnimation);
|
data,
|
||||||
|
role
|
||||||
|
});
|
||||||
|
|
||||||
// build the animation and kick it off
|
const animationBuilder = this.leaveAnimation || this.config.get('toastLeave', this.mode === 'ios' ? iosLeaveAnimation : mdLeaveAnimation);
|
||||||
this.animationCtrl.create(animationBuilder, this.el, this.position).then(animation => {
|
|
||||||
this.animation = animation;
|
|
||||||
|
|
||||||
animation.onFinish((a: any) => {
|
return this.animationCtrl.create(animationBuilder, this.el).then(animation => {
|
||||||
a.destroy();
|
this.animation = animation;
|
||||||
this.ionToastDidDismiss.emit({ toast: this });
|
return playAnimationAsync(animation);
|
||||||
|
}).then((animation) => {
|
||||||
Context.dom.write(() => {
|
animation.destroy();
|
||||||
this.el.parentNode.removeChild(this.el);
|
return domControllerAsync(Context.dom.write, () => {
|
||||||
});
|
this.el.parentNode.removeChild(this.el);
|
||||||
|
});
|
||||||
resolve();
|
}).then(() => {
|
||||||
}).play();
|
this.ionToastDidDismiss.emit({
|
||||||
|
data,
|
||||||
|
role
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidLoad() {
|
componentDidLoad() {
|
||||||
this.ionToastDidLoad.emit({ toast: this });
|
this.ionToastDidLoad.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidEnter() {
|
componentDidEnter() {
|
||||||
this.ionToastDidPresent.emit({ toast: this });
|
this.ionToastDidPresent.emit();
|
||||||
if (this.duration) {
|
if (this.duration) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.dismiss();
|
this.dismiss();
|
||||||
@ -144,7 +153,7 @@ export class Toast {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidUnload() {
|
componentDidUnload() {
|
||||||
this.ionToastDidUnload.emit({ toast: this });
|
this.ionToastDidUnload.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Listen('ionDismiss')
|
@Listen('ionDismiss')
|
||||||
@ -190,7 +199,7 @@ export class Toast {
|
|||||||
? <div class='toast-message'>{this.message}</div>
|
? <div class='toast-message'>{this.message}</div>
|
||||||
: null}
|
: null}
|
||||||
{this.showCloseButton
|
{this.showCloseButton
|
||||||
? <ion-button fill="clear" color='light' class='toast-button' onClick={() => this.dismiss()}>
|
? <ion-button fill='clear' color='light' class='toast-button' onClick={() => this.dismiss()}>
|
||||||
{this.closeButtonText || 'Close'}
|
{this.closeButtonText || 'Close'}
|
||||||
</ion-button>
|
</ion-button>
|
||||||
: null}
|
: null}
|
||||||
@ -214,10 +223,20 @@ export interface ToastOptions {
|
|||||||
exitAnimation?: AnimationBuilder;
|
exitAnimation?: AnimationBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ToastEvent {
|
export interface ToastEvent extends CustomEvent {
|
||||||
detail: {
|
detail: ToastEventDetail;
|
||||||
toast: Toast;
|
}
|
||||||
};
|
|
||||||
|
export interface ToastEventDetail {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ToastDismissEventDetail extends OverlayDismissEventDetail {
|
||||||
|
// keep this just for the sake of static types and potential future extensions
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ToastDismissEvent extends OverlayDismissEvent {
|
||||||
|
// keep this just for the sake of static types and potential future extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
Reference in New Issue
Block a user