UNPKG

7.16 kBJavaScriptView Raw
1/*!
2 * (C) Ionic http://ionicframework.com - MIT License
3 */
4import { writeTask, Build } from '@stencil/core/internal/client';
5import { c as componentOnReady, r as raf } from './helpers.js';
6
7const LIFECYCLE_WILL_ENTER = 'ionViewWillEnter';
8const LIFECYCLE_DID_ENTER = 'ionViewDidEnter';
9const LIFECYCLE_WILL_LEAVE = 'ionViewWillLeave';
10const LIFECYCLE_DID_LEAVE = 'ionViewDidLeave';
11const LIFECYCLE_WILL_UNLOAD = 'ionViewWillUnload';
12
13const iosTransitionAnimation = () => import('./ios.transition.js');
14const mdTransitionAnimation = () => import('./md.transition.js');
15const transition = (opts) => {
16 return new Promise((resolve, reject) => {
17 writeTask(() => {
18 beforeTransition(opts);
19 runTransition(opts).then(result => {
20 if (result.animation) {
21 result.animation.destroy();
22 }
23 afterTransition(opts);
24 resolve(result);
25 }, error => {
26 afterTransition(opts);
27 reject(error);
28 });
29 });
30 });
31};
32const beforeTransition = (opts) => {
33 const enteringEl = opts.enteringEl;
34 const leavingEl = opts.leavingEl;
35 setZIndex(enteringEl, leavingEl, opts.direction);
36 if (opts.showGoBack) {
37 enteringEl.classList.add('can-go-back');
38 }
39 else {
40 enteringEl.classList.remove('can-go-back');
41 }
42 setPageHidden(enteringEl, false);
43 /**
44 * When transitioning, the page should not
45 * respond to click events. This resolves small
46 * issues like users double tapping the ion-back-button.
47 * These pointer events are removed in `afterTransition`.
48 */
49 enteringEl.style.setProperty('pointer-events', 'none');
50 if (leavingEl) {
51 setPageHidden(leavingEl, false);
52 leavingEl.style.setProperty('pointer-events', 'none');
53 }
54};
55const runTransition = async (opts) => {
56 const animationBuilder = await getAnimationBuilder(opts);
57 const ani = (animationBuilder && Build.isBrowser)
58 ? animation(animationBuilder, opts)
59 : noAnimation(opts); // fast path for no animation
60 return ani;
61};
62const afterTransition = (opts) => {
63 const enteringEl = opts.enteringEl;
64 const leavingEl = opts.leavingEl;
65 enteringEl.classList.remove('ion-page-invisible');
66 enteringEl.style.removeProperty('pointer-events');
67 if (leavingEl !== undefined) {
68 leavingEl.classList.remove('ion-page-invisible');
69 leavingEl.style.removeProperty('pointer-events');
70 }
71};
72const getAnimationBuilder = async (opts) => {
73 if (!opts.leavingEl || !opts.animated || opts.duration === 0) {
74 return undefined;
75 }
76 if (opts.animationBuilder) {
77 return opts.animationBuilder;
78 }
79 const getAnimation = (opts.mode === 'ios')
80 ? (await iosTransitionAnimation()).iosTransitionAnimation
81 : (await mdTransitionAnimation()).mdTransitionAnimation;
82 return getAnimation;
83};
84const animation = async (animationBuilder, opts) => {
85 await waitForReady(opts, true);
86 const trans = animationBuilder(opts.baseEl, opts);
87 fireWillEvents(opts.enteringEl, opts.leavingEl);
88 const didComplete = await playTransition(trans, opts);
89 if (opts.progressCallback) {
90 opts.progressCallback(undefined);
91 }
92 if (didComplete) {
93 fireDidEvents(opts.enteringEl, opts.leavingEl);
94 }
95 return {
96 hasCompleted: didComplete,
97 animation: trans
98 };
99};
100const noAnimation = async (opts) => {
101 const enteringEl = opts.enteringEl;
102 const leavingEl = opts.leavingEl;
103 await waitForReady(opts, false);
104 fireWillEvents(enteringEl, leavingEl);
105 fireDidEvents(enteringEl, leavingEl);
106 return {
107 hasCompleted: true
108 };
109};
110const waitForReady = async (opts, defaultDeep) => {
111 const deep = opts.deepWait !== undefined ? opts.deepWait : defaultDeep;
112 const promises = deep ? [
113 deepReady(opts.enteringEl),
114 deepReady(opts.leavingEl),
115 ] : [
116 shallowReady(opts.enteringEl),
117 shallowReady(opts.leavingEl),
118 ];
119 await Promise.all(promises);
120 await notifyViewReady(opts.viewIsReady, opts.enteringEl);
121};
122const notifyViewReady = async (viewIsReady, enteringEl) => {
123 if (viewIsReady) {
124 await viewIsReady(enteringEl);
125 }
126};
127const playTransition = (trans, opts) => {
128 const progressCallback = opts.progressCallback;
129 const promise = new Promise(resolve => {
130 trans.onFinish((currentStep) => resolve(currentStep === 1));
131 });
132 // cool, let's do this, start the transition
133 if (progressCallback) {
134 // this is a swipe to go back, just get the transition progress ready
135 // kick off the swipe animation start
136 trans.progressStart(true);
137 progressCallback(trans);
138 }
139 else {
140 // only the top level transition should actually start "play"
141 // kick it off and let it play through
142 // ******** DOM WRITE ****************
143 trans.play();
144 }
145 // create a callback for when the animation is done
146 return promise;
147};
148const fireWillEvents = (enteringEl, leavingEl) => {
149 lifecycle(leavingEl, LIFECYCLE_WILL_LEAVE);
150 lifecycle(enteringEl, LIFECYCLE_WILL_ENTER);
151};
152const fireDidEvents = (enteringEl, leavingEl) => {
153 lifecycle(enteringEl, LIFECYCLE_DID_ENTER);
154 lifecycle(leavingEl, LIFECYCLE_DID_LEAVE);
155};
156const lifecycle = (el, eventName) => {
157 if (el) {
158 const ev = new CustomEvent(eventName, {
159 bubbles: false,
160 cancelable: false,
161 });
162 el.dispatchEvent(ev);
163 }
164};
165const shallowReady = (el) => {
166 if (el) {
167 return new Promise(resolve => componentOnReady(el, resolve));
168 }
169 return Promise.resolve();
170};
171const deepReady = async (el) => {
172 const element = el;
173 if (element) {
174 if (element.componentOnReady != null) {
175 const stencilEl = await element.componentOnReady();
176 if (stencilEl != null) {
177 return;
178 }
179 /**
180 * Custom elements in Stencil will have __registerHost.
181 */
182 }
183 else if (element.__registerHost != null) {
184 /**
185 * Non-lazy loaded custom elements need to wait
186 * one frame for component to be loaded.
187 */
188 const waitForCustomElement = new Promise(resolve => raf(resolve));
189 await waitForCustomElement;
190 return;
191 }
192 await Promise.all(Array.from(element.children).map(deepReady));
193 }
194};
195const setPageHidden = (el, hidden) => {
196 if (hidden) {
197 el.setAttribute('aria-hidden', 'true');
198 el.classList.add('ion-page-hidden');
199 }
200 else {
201 el.hidden = false;
202 el.removeAttribute('aria-hidden');
203 el.classList.remove('ion-page-hidden');
204 }
205};
206const setZIndex = (enteringEl, leavingEl, direction) => {
207 if (enteringEl !== undefined) {
208 enteringEl.style.zIndex = (direction === 'back')
209 ? '99'
210 : '101';
211 }
212 if (leavingEl !== undefined) {
213 leavingEl.style.zIndex = '100';
214 }
215};
216const getIonPageElement = (element) => {
217 if (element.classList.contains('ion-page')) {
218 return element;
219 }
220 const ionPage = element.querySelector(':scope > .ion-page, :scope > ion-nav, :scope > ion-tabs');
221 if (ionPage) {
222 return ionPage;
223 }
224 // idk, return the original element so at least something animates and we don't have a null pointer
225 return element;
226};
227
228export { LIFECYCLE_WILL_ENTER as L, LIFECYCLE_DID_ENTER as a, LIFECYCLE_WILL_LEAVE as b, LIFECYCLE_DID_LEAVE as c, LIFECYCLE_WILL_UNLOAD as d, deepReady as e, getIonPageElement as g, lifecycle as l, setPageHidden as s, transition as t };