mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-08 07:41:51 +08:00
refactor(modal): update API for modal to match other overlays
This commit is contained in:
@ -8,11 +8,11 @@ import { Modal, ModalEvent, ModalOptions } from '../../index';
|
|||||||
export class ModalController {
|
export class ModalController {
|
||||||
private ids = 0;
|
private ids = 0;
|
||||||
private modalResolves: {[modalId: string]: Function} = {};
|
private modalResolves: {[modalId: string]: Function} = {};
|
||||||
private modals: Modal[] = [];
|
private modals: HTMLIonModalElement[] = [];
|
||||||
|
|
||||||
|
|
||||||
@Method()
|
@Method()
|
||||||
create(opts?: ModalOptions) {
|
create(opts?: ModalOptions): Promise<HTMLIonModalElement> {
|
||||||
// create ionic's wrapping ion-modal component
|
// create ionic's wrapping ion-modal component
|
||||||
const modal = document.createElement('ion-modal');
|
const modal = document.createElement('ion-modal');
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ export class ModalController {
|
|||||||
appRoot.appendChild(modal as any);
|
appRoot.appendChild(modal as any);
|
||||||
|
|
||||||
// store the resolve function to be called later up when the modal loads
|
// store the resolve function to be called later up when the modal loads
|
||||||
return new Promise<Modal>(resolve => {
|
return new Promise<HTMLIonModalElement>(resolve => {
|
||||||
this.modalResolves[modal.modalId] = resolve;
|
this.modalResolves[modal.modalId] = resolve;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@ export class ModalController {
|
|||||||
|
|
||||||
@Listen('body:ionModalDidLoad')
|
@Listen('body:ionModalDidLoad')
|
||||||
protected modalDidLoad(ev: ModalEvent) {
|
protected modalDidLoad(ev: ModalEvent) {
|
||||||
const modal = ev.detail.modal;
|
const modal = ev.target as HTMLIonModalElement;
|
||||||
const modalResolve = this.modalResolves[modal.modalId];
|
const modalResolve = this.modalResolves[modal.modalId];
|
||||||
if (modalResolve) {
|
if (modalResolve) {
|
||||||
modalResolve(modal);
|
modalResolve(modal);
|
||||||
@ -50,13 +50,13 @@ export class ModalController {
|
|||||||
|
|
||||||
@Listen('body:ionModalWillPresent')
|
@Listen('body:ionModalWillPresent')
|
||||||
protected modalWillPresent(ev: ModalEvent) {
|
protected modalWillPresent(ev: ModalEvent) {
|
||||||
this.modals.push(ev.detail.modal);
|
this.modals.push(ev.target as HTMLIonModalElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Listen('body:ionModalWillDismiss, body:ionModalDidUnload')
|
@Listen('body:ionModalWillDismiss, body:ionModalDidUnload')
|
||||||
protected modalWillDismiss(ev: ModalEvent) {
|
protected modalWillDismiss(ev: ModalEvent) {
|
||||||
const index = this.modals.indexOf(ev.detail.modal);
|
const index = this.modals.indexOf(ev.target as HTMLIonModalElement);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this.modals.splice(index, 1);
|
this.modals.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,13 @@
|
|||||||
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 } from '../../index';
|
import {
|
||||||
|
Animation,
|
||||||
|
AnimationBuilder,
|
||||||
|
AnimationController,
|
||||||
|
Config,
|
||||||
|
OverlayDismissEvent,
|
||||||
|
OverlayDismissEventDetail
|
||||||
|
} from '../../index';
|
||||||
|
import { domControllerAsync, playAnimationAsync } from '../../utils/helpers';
|
||||||
import { createThemedClasses } from '../../utils/theme';
|
import { createThemedClasses } from '../../utils/theme';
|
||||||
|
|
||||||
import iosEnterAnimation from './animations/ios.enter';
|
import iosEnterAnimation from './animations/ios.enter';
|
||||||
@ -23,32 +31,32 @@ export class Modal {
|
|||||||
/**
|
/**
|
||||||
* @output {ModalEvent} Emitted after the modal has loaded.
|
* @output {ModalEvent} Emitted after the modal has loaded.
|
||||||
*/
|
*/
|
||||||
@Event() ionModalDidLoad: EventEmitter;
|
@Event() ionModalDidLoad: EventEmitter<ModalEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {ModalEvent} Emitted after the modal has presented.
|
* @output {ModalEvent} Emitted after the modal has presented.
|
||||||
*/
|
*/
|
||||||
@Event() ionModalDidPresent: EventEmitter;
|
@Event() ionModalDidPresent: EventEmitter<ModalEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {ModalEvent} Emitted before the modal has presented.
|
* @output {ModalEvent} Emitted before the modal has presented.
|
||||||
*/
|
*/
|
||||||
@Event() ionModalWillPresent: EventEmitter;
|
@Event() ionModalWillPresent: EventEmitter<ModalEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {ModalEvent} Emitted before the modal has dismissed.
|
* @output {ModalEvent} Emitted before the modal has dismissed.
|
||||||
*/
|
*/
|
||||||
@Event() ionModalWillDismiss: EventEmitter;
|
@Event() ionModalWillDismiss: EventEmitter<ModalDismissEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {ModalEvent} Emitted after the modal has dismissed.
|
* @output {ModalEvent} Emitted after the modal has dismissed.
|
||||||
*/
|
*/
|
||||||
@Event() ionModalDidDismiss: EventEmitter;
|
@Event() ionModalDidDismiss: EventEmitter<ModalDismissEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {ModalEvent} Emitted after the modal has unloaded.
|
* @output {ModalEvent} Emitted after the modal has unloaded.
|
||||||
*/
|
*/
|
||||||
@Event() ionModalDidUnload: EventEmitter;
|
@Event() ionModalDidUnload: EventEmitter<ModalEventDetail>;
|
||||||
|
|
||||||
@Prop({ connect: 'ion-animation-controller' }) animationCtrl: AnimationController;
|
@Prop({ connect: 'ion-animation-controller' }) animationCtrl: AnimationController;
|
||||||
@Prop({ context: 'config' }) config: Config;
|
@Prop({ context: 'config' }) config: Config;
|
||||||
@ -64,64 +72,65 @@ export class Modal {
|
|||||||
|
|
||||||
@Prop() enterAnimation: AnimationBuilder;
|
@Prop() enterAnimation: AnimationBuilder;
|
||||||
@Prop() leaveAnimation: AnimationBuilder;
|
@Prop() leaveAnimation: AnimationBuilder;
|
||||||
|
@Prop() animate: boolean;
|
||||||
|
|
||||||
private animation: Animation;
|
private animation: Animation;
|
||||||
|
|
||||||
|
|
||||||
|
@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.ionModalWillPresent.emit({ modal: this });
|
this.ionModalWillPresent.emit({ loading: this });
|
||||||
|
|
||||||
// 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('modalEnter', this.mode === 'ios' ? iosEnterAnimation : mdEnterAnimation);
|
const animationBuilder = this.enterAnimation || this.config.get('modalEnter', 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).then(animation => {
|
// build the animation and kick it off
|
||||||
|
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.ionModalDidPresent.emit({ modal: this });
|
this.animation = animation.duration(0);
|
||||||
resolve();
|
}
|
||||||
}).play();
|
return playAnimationAsync(animation);
|
||||||
|
}).then((animation) => {
|
||||||
|
animation.destroy();
|
||||||
|
this.ionModalDidPresent.emit();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
this.ionModalWillDismiss.emit({
|
||||||
|
data,
|
||||||
|
role
|
||||||
|
});
|
||||||
|
|
||||||
return new Promise<void>(resolve => {
|
// get the user's animation fn if one was provided
|
||||||
this.ionModalWillDismiss.emit({ modal: this });
|
const animationBuilder = this.leaveAnimation || this.config.get('modalLeave', this.mode === 'ios' ? iosLeaveAnimation : mdLeaveAnimation);
|
||||||
|
|
||||||
// get the user's animation fn if one was provided
|
return this.animationCtrl.create(animationBuilder, this.el).then(animation => {
|
||||||
const animationBuilder = this.leaveAnimation || this.config.get('modalLeave', this.mode === 'ios' ? iosLeaveAnimation : mdLeaveAnimation);
|
this.animation = animation;
|
||||||
|
return playAnimationAsync(animation);
|
||||||
// build the animation and kick it off
|
}).then((animation) => {
|
||||||
this.animationCtrl.create(animationBuilder, this.el).then(animation => {
|
animation.destroy();
|
||||||
this.animation = animation;
|
return domControllerAsync(Context.dom.write, () => {
|
||||||
|
this.el.parentNode.removeChild(this.el);
|
||||||
animation.onFinish((a: any) => {
|
});
|
||||||
a.destroy();
|
}).then(() => {
|
||||||
this.ionModalDidDismiss.emit({ modal: this });
|
this.ionModalDidDismiss.emit({
|
||||||
|
data,
|
||||||
Context.dom.write(() => {
|
role
|
||||||
this.el.parentNode.removeChild(this.el);
|
|
||||||
});
|
|
||||||
resolve();
|
|
||||||
}).play();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -195,10 +204,20 @@ export interface ModalOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface ModalEvent extends Event {
|
export interface ModalEvent extends CustomEvent {
|
||||||
detail: {
|
detail: ModalEventDetail;
|
||||||
modal: Modal;
|
}
|
||||||
};
|
|
||||||
|
export interface ModalEventDetail {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ModalDismissEventDetail extends OverlayDismissEventDetail {
|
||||||
|
// keep this just for the sake of static types and potential future extensions
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ModalDismissEvent extends OverlayDismissEvent {
|
||||||
|
// keep this just for the sake of static types and potential future extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@ -27,15 +27,13 @@
|
|||||||
</ion-app>
|
</ion-app>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const controller = document.querySelector('ion-modal-controller');
|
async function presentModal() {
|
||||||
function presentModal() {
|
const modalController = document.querySelector('ion-modal-controller');
|
||||||
controller
|
await modalController.componentOnReady();
|
||||||
.create({
|
const modalElement = await modalController.create({
|
||||||
component: 'page-one'
|
component: 'page-one'
|
||||||
})
|
});
|
||||||
.then(modal => {
|
modalElement.present();
|
||||||
modal.present();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user