UNPKG

59.5 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5const index = require('./index-a0a08b2a.js');
6const ionicGlobal = require('./ionic-global-06f21c1a.js');
7const theme = require('./theme-30b7a575.js');
8const helpers = require('./helpers-d381ec4d.js');
9const cubicBezier = require('./cubic-bezier-0b2ccc35.js');
10const frameworkDelegate = require('./framework-delegate-45524d8c.js');
11const index$1 = require('./index-222357e4.js');
12
13const appCss = "html.plt-mobile ion-app{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}html.plt-mobile ion-app [contenteditable]{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}ion-app.force-statusbar-padding{--ion-safe-area-top:20px}";
14
15const App = class {
16 constructor(hostRef) {
17 index.registerInstance(this, hostRef);
18 }
19 componentDidLoad() {
20 {
21 rIC(async () => {
22 const isHybrid = ionicGlobal.isPlatform(window, 'hybrid');
23 if (!ionicGlobal.config.getBoolean('_testing')) {
24 Promise.resolve().then(function () { return require('./tap-click-08c2217f.js'); }).then(module => module.startTapClick(ionicGlobal.config));
25 }
26 if (ionicGlobal.config.getBoolean('statusTap', isHybrid)) {
27 Promise.resolve().then(function () { return require('./status-tap-480ef38b.js'); }).then(module => module.startStatusTap());
28 }
29 if (ionicGlobal.config.getBoolean('inputShims', needInputShims())) {
30 Promise.resolve().then(function () { return require('./input-shims-23e0b8a3.js'); }).then(module => module.startInputShims(ionicGlobal.config));
31 }
32 const hardwareBackButtonModule = await Promise.resolve().then(function () { return require('./hardware-back-button-148ce546.js'); });
33 if (ionicGlobal.config.getBoolean('hardwareBackButton', isHybrid)) {
34 hardwareBackButtonModule.startHardwareBackButton();
35 }
36 else {
37 hardwareBackButtonModule.blockHardwareBackButton();
38 }
39 if (typeof window !== 'undefined') {
40 Promise.resolve().then(function () { return require('./keyboard-4704570e.js'); }).then(module => module.startKeyboardAssist(window));
41 }
42 Promise.resolve().then(function () { return require('./focus-visible-9efe58aa.js'); }).then(module => module.startFocusVisible());
43 });
44 }
45 }
46 render() {
47 const mode = ionicGlobal.getIonMode(this);
48 return (index.h(index.Host, { class: {
49 [mode]: true,
50 'ion-page': true,
51 'force-statusbar-padding': ionicGlobal.config.getBoolean('_forceStatusbarPadding'),
52 } }));
53 }
54 get el() { return index.getElement(this); }
55};
56const needInputShims = () => {
57 return ionicGlobal.isPlatform(window, 'ios') && ionicGlobal.isPlatform(window, 'mobile');
58};
59const rIC = (callback) => {
60 if ('requestIdleCallback' in window) {
61 window.requestIdleCallback(callback);
62 }
63 else {
64 setTimeout(callback, 32);
65 }
66};
67App.style = appCss;
68
69const buttonsIosCss = ".sc-ion-buttons-ios-h{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-transform:translateZ(0);transform:translateZ(0);z-index:99}.sc-ion-buttons-ios-s ion-button{--padding-top:0;--padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}.sc-ion-buttons-ios-s ion-button{--padding-start:5px;--padding-end:5px;margin-left:2px;margin-right:2px;height:32px;font-size:17px;font-weight:400}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.sc-ion-buttons-ios-s ion-button{margin-left:unset;margin-right:unset;-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:2px;margin-inline-end:2px}}.sc-ion-buttons-ios-s ion-button:not(.button-round){--border-radius:4px}.sc-ion-buttons-ios-h.ion-color.sc-ion-buttons-ios-s .button,.ion-color .sc-ion-buttons-ios-h.sc-ion-buttons-ios-s .button{--color:initial;--border-color:initial;--background-focused:var(--ion-color-contrast)}.sc-ion-buttons-ios-h.ion-color.sc-ion-buttons-ios-s .button-solid,.ion-color .sc-ion-buttons-ios-h.sc-ion-buttons-ios-s .button-solid{--background:var(--ion-color-contrast);--background-focused:#000;--background-focused-opacity:.12;--background-activated:#000;--background-activated-opacity:.12;--background-hover:var(--ion-color-base);--background-hover-opacity:0.45;--color:var(--ion-color-base);--color-focused:var(--ion-color-base)}.sc-ion-buttons-ios-h.ion-color.sc-ion-buttons-ios-s .button-clear,.ion-color .sc-ion-buttons-ios-h.sc-ion-buttons-ios-s .button-clear{--color-activated:var(--ion-color-contrast);--color-focused:var(--ion-color-contrast)}.sc-ion-buttons-ios-h.ion-color.sc-ion-buttons-ios-s .button-outline,.ion-color .sc-ion-buttons-ios-h.sc-ion-buttons-ios-s .button-outline{--color-activated:var(--ion-color-base);--color-focused:var(--ion-color-contrast)}.sc-ion-buttons-ios-s .button-clear,.sc-ion-buttons-ios-s .button-outline{--background-activated:transparent;--background-focused:currentColor;--background-hover:transparent}.sc-ion-buttons-ios-s .button-solid:not(.ion-color){--background-focused:#000;--background-focused-opacity:.12;--background-activated:#000;--background-activated-opacity:.12}.sc-ion-buttons-ios-s ion-icon[slot=start]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;margin-right:0.3em;font-size:24px;line-height:0.67}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.sc-ion-buttons-ios-s ion-icon[slot=start]{margin-right:unset;-webkit-margin-end:0.3em;margin-inline-end:0.3em}}.sc-ion-buttons-ios-s ion-icon[slot=end]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;margin-left:0.4em;font-size:24px;line-height:0.67}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.sc-ion-buttons-ios-s ion-icon[slot=end]{margin-left:unset;-webkit-margin-start:0.4em;margin-inline-start:0.4em}}.sc-ion-buttons-ios-s ion-icon[slot=icon-only]{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;font-size:28px;line-height:0.67}";
70
71const buttonsMdCss = ".sc-ion-buttons-md-h{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-transform:translateZ(0);transform:translateZ(0);z-index:99}.sc-ion-buttons-md-s ion-button{--padding-top:0;--padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}.sc-ion-buttons-md-s ion-button{--padding-top:0;--padding-bottom:0;--padding-start:8px;--padding-end:8px;--box-shadow:none;margin-left:2px;margin-right:2px;height:32px;font-size:14px;font-weight:500}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.sc-ion-buttons-md-s ion-button{margin-left:unset;margin-right:unset;-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:2px;margin-inline-end:2px}}.sc-ion-buttons-md-s ion-button:not(.button-round){--border-radius:2px}.sc-ion-buttons-md-h.ion-color.sc-ion-buttons-md-s .button,.ion-color .sc-ion-buttons-md-h.sc-ion-buttons-md-s .button{--color:initial;--color-focused:var(--ion-color-contrast);--color-hover:var(--ion-color-contrast);--background-activated:transparent;--background-focused:var(--ion-color-contrast);--background-hover:var(--ion-color-contrast)}.sc-ion-buttons-md-h.ion-color.sc-ion-buttons-md-s .button-solid,.ion-color .sc-ion-buttons-md-h.sc-ion-buttons-md-s .button-solid{--background:var(--ion-color-contrast);--background-activated:transparent;--background-focused:var(--ion-color-shade);--background-hover:var(--ion-color-base);--color:var(--ion-color-base);--color-focused:var(--ion-color-base);--color-hover:var(--ion-color-base)}.sc-ion-buttons-md-h.ion-color.sc-ion-buttons-md-s .button-outline,.ion-color .sc-ion-buttons-md-h.sc-ion-buttons-md-s .button-outline{--border-color:var(--ion-color-contrast)}.sc-ion-buttons-md-s .button-has-icon-only.button-clear{--padding-top:12px;--padding-end:12px;--padding-bottom:12px;--padding-start:12px;--border-radius:50%;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;width:48px;height:48px}.sc-ion-buttons-md-s .button{--background-hover:currentColor}.sc-ion-buttons-md-s .button-solid{--color:var(--ion-toolbar-background, var(--ion-background-color, #fff));--background:var(--ion-toolbar-color, var(--ion-text-color, #424242));--background-activated:transparent;--background-focused:currentColor}.sc-ion-buttons-md-s .button-outline{--color:initial;--background:transparent;--background-activated:transparent;--background-focused:currentColor;--background-hover:currentColor;--border-color:currentColor}.sc-ion-buttons-md-s .button-clear{--color:initial;--background:transparent;--background-activated:transparent;--background-focused:currentColor;--background-hover:currentColor}.sc-ion-buttons-md-s ion-icon[slot=start]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;margin-right:0.3em;font-size:1.4em}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.sc-ion-buttons-md-s ion-icon[slot=start]{margin-right:unset;-webkit-margin-end:0.3em;margin-inline-end:0.3em}}.sc-ion-buttons-md-s ion-icon[slot=end]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;margin-left:0.4em;font-size:1.4em}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.sc-ion-buttons-md-s ion-icon[slot=end]{margin-left:unset;-webkit-margin-start:0.4em;margin-inline-start:0.4em}}.sc-ion-buttons-md-s ion-icon[slot=icon-only]{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;font-size:1.8em}";
72
73const Buttons = class {
74 constructor(hostRef) {
75 index.registerInstance(this, hostRef);
76 /**
77 * If true, buttons will disappear when its
78 * parent toolbar has fully collapsed if the toolbar
79 * is not the first toolbar. If the toolbar is the
80 * first toolbar, the buttons will be hidden and will
81 * only be shown once all toolbars have fully collapsed.
82 *
83 * Only applies in `ios` mode with `collapse` set to
84 * `true` on `ion-header`.
85 *
86 * Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles)
87 */
88 this.collapse = false;
89 }
90 render() {
91 const mode = ionicGlobal.getIonMode(this);
92 return (index.h(index.Host, { class: {
93 [mode]: true,
94 ['buttons-collapse']: this.collapse
95 } }));
96 }
97};
98Buttons.style = {
99 ios: buttonsIosCss,
100 md: buttonsMdCss
101};
102
103const contentCss = ":host{--background:var(--ion-background-color, #fff);--color:var(--ion-text-color, #000);--padding-top:0px;--padding-bottom:0px;--padding-start:0px;--padding-end:0px;--keyboard-offset:0px;--offset-top:0px;--offset-bottom:0px;--overflow:auto;display:block;position:relative;-ms-flex:1;flex:1;width:100%;height:100%;margin:0 !important;padding:0 !important;font-family:var(--ion-font-family, inherit);contain:size style}:host(.ion-color) .inner-scroll{background:var(--ion-color-base);color:var(--ion-color-contrast)}:host(.outer-content){--background:var(--ion-color-step-50, #f2f2f2)}#background-content{left:0px;right:0px;top:calc(var(--offset-top) * -1);bottom:calc(var(--offset-bottom) * -1);position:absolute;background:var(--background)}.inner-scroll{left:0px;right:0px;top:calc(var(--offset-top) * -1);bottom:calc(var(--offset-bottom) * -1);padding-left:var(--padding-start);padding-right:var(--padding-end);padding-top:calc(var(--padding-top) + var(--offset-top));padding-bottom:calc(var(--padding-bottom) + var(--keyboard-offset) + var(--offset-bottom));position:absolute;color:var(--color);-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.inner-scroll{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end)}}.scroll-y,.scroll-x{-webkit-overflow-scrolling:touch;z-index:0;will-change:scroll-position}.scroll-y{-ms-touch-action:pan-y;touch-action:pan-y;overflow-y:var(--overflow);overscroll-behavior-y:contain}.scroll-x{-ms-touch-action:pan-x;touch-action:pan-x;overflow-x:var(--overflow);overscroll-behavior-x:contain}.scroll-x.scroll-y{-ms-touch-action:auto;touch-action:auto}.overscroll::before,.overscroll::after{position:absolute;width:1px;height:1px;content:\"\"}.overscroll::before{bottom:-1px}.overscroll::after{top:-1px}:host(.content-sizing){contain:none}:host(.content-sizing) .inner-scroll{position:relative}.transition-effect{display:none;position:absolute;left:-100%;width:100%;height:100vh;opacity:0;pointer-events:none}.transition-cover{position:absolute;right:0;width:100%;height:100%;background:black;opacity:0.1}.transition-shadow{display:block;position:absolute;right:0;width:10px;height:100%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAgCAYAAAAIXrg4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ1IDc5LjE2MzQ5OSwgMjAxOC8wOC8xMy0xNjo0MDoyMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTE3MDgzRkQ5QTkyMTFFOUEwNzQ5MkJFREE1NUY2MjQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTE3MDgzRkU5QTkyMTFFOUEwNzQ5MkJFREE1NUY2MjQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoxMTcwODNGQjlBOTIxMUU5QTA3NDkyQkVEQTU1RjYyNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoxMTcwODNGQzlBOTIxMUU5QTA3NDkyQkVEQTU1RjYyNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PmePEuQAAABNSURBVHjaYvz//z8DIxAwMDAwATGMhmFmPDQuOSZks0AMmoJBaQHjkPfB0Lfg/2gQjVow+HPy/yHvg9GiYjQfjMbBqAWjFgy/4hogwADYqwdzxy5BuwAAAABJRU5ErkJggg==);background-repeat:repeat-y;background-size:10px 16px}::slotted([slot=fixed]){position:absolute}";
104
105const Content = class {
106 constructor(hostRef) {
107 index.registerInstance(this, hostRef);
108 this.ionScrollStart = index.createEvent(this, "ionScrollStart", 7);
109 this.ionScroll = index.createEvent(this, "ionScroll", 7);
110 this.ionScrollEnd = index.createEvent(this, "ionScrollEnd", 7);
111 this.isScrolling = false;
112 this.lastScroll = 0;
113 this.queued = false;
114 this.cTop = -1;
115 this.cBottom = -1;
116 this.isMainContent = true;
117 // Detail is used in a hot loop in the scroll event, by allocating it here
118 // V8 will be able to inline any read/write to it since it's a monomorphic class.
119 // https://mrale.ph/blog/2015/01/11/whats-up-with-monomorphism.html
120 this.detail = {
121 scrollTop: 0,
122 scrollLeft: 0,
123 type: 'scroll',
124 event: undefined,
125 startX: 0,
126 startY: 0,
127 startTime: 0,
128 currentX: 0,
129 currentY: 0,
130 velocityX: 0,
131 velocityY: 0,
132 deltaX: 0,
133 deltaY: 0,
134 currentTime: 0,
135 data: undefined,
136 isScrolling: true,
137 };
138 /**
139 * If `true`, the content will scroll behind the headers
140 * and footers. This effect can easily be seen by setting the toolbar
141 * to transparent.
142 */
143 this.fullscreen = false;
144 /**
145 * If you want to enable the content scrolling in the X axis, set this property to `true`.
146 */
147 this.scrollX = false;
148 /**
149 * If you want to disable the content scrolling in the Y axis, set this property to `false`.
150 */
151 this.scrollY = true;
152 /**
153 * Because of performance reasons, ionScroll events are disabled by default, in order to enable them
154 * and start listening from (ionScroll), set this property to `true`.
155 */
156 this.scrollEvents = false;
157 }
158 connectedCallback() {
159 this.isMainContent = this.el.closest('ion-menu, ion-popover, ion-modal') === null;
160 }
161 disconnectedCallback() {
162 this.onScrollEnd();
163 }
164 onAppLoad() {
165 this.resize();
166 }
167 onClick(ev) {
168 if (this.isScrolling) {
169 ev.preventDefault();
170 ev.stopPropagation();
171 }
172 }
173 shouldForceOverscroll() {
174 const { forceOverscroll } = this;
175 const mode = ionicGlobal.getIonMode(this);
176 return forceOverscroll === undefined
177 ? mode === 'ios' && ionicGlobal.isPlatform('ios')
178 : forceOverscroll;
179 }
180 resize() {
181 if (this.fullscreen) {
182 index.readTask(() => this.readDimensions());
183 }
184 else if (this.cTop !== 0 || this.cBottom !== 0) {
185 this.cTop = this.cBottom = 0;
186 index.forceUpdate(this);
187 }
188 }
189 readDimensions() {
190 const page = getPageElement(this.el);
191 const top = Math.max(this.el.offsetTop, 0);
192 const bottom = Math.max(page.offsetHeight - top - this.el.offsetHeight, 0);
193 const dirty = top !== this.cTop || bottom !== this.cBottom;
194 if (dirty) {
195 this.cTop = top;
196 this.cBottom = bottom;
197 index.forceUpdate(this);
198 }
199 }
200 onScroll(ev) {
201 const timeStamp = Date.now();
202 const shouldStart = !this.isScrolling;
203 this.lastScroll = timeStamp;
204 if (shouldStart) {
205 this.onScrollStart();
206 }
207 if (!this.queued && this.scrollEvents) {
208 this.queued = true;
209 index.readTask(ts => {
210 this.queued = false;
211 this.detail.event = ev;
212 updateScrollDetail(this.detail, this.scrollEl, ts, shouldStart);
213 this.ionScroll.emit(this.detail);
214 });
215 }
216 }
217 /**
218 * Get the element where the actual scrolling takes place.
219 * This element can be used to subscribe to `scroll` events or manually modify
220 * `scrollTop`. However, it's recommended to use the API provided by `ion-content`:
221 *
222 * i.e. Using `ionScroll`, `ionScrollStart`, `ionScrollEnd` for scrolling events
223 * and `scrollToPoint()` to scroll the content into a certain point.
224 */
225 getScrollElement() {
226 return Promise.resolve(this.scrollEl);
227 }
228 /**
229 * Scroll to the top of the component.
230 *
231 * @param duration The amount of time to take scrolling to the top. Defaults to `0`.
232 */
233 scrollToTop(duration = 0) {
234 return this.scrollToPoint(undefined, 0, duration);
235 }
236 /**
237 * Scroll to the bottom of the component.
238 *
239 * @param duration The amount of time to take scrolling to the bottom. Defaults to `0`.
240 */
241 scrollToBottom(duration = 0) {
242 const y = this.scrollEl.scrollHeight - this.scrollEl.clientHeight;
243 return this.scrollToPoint(undefined, y, duration);
244 }
245 /**
246 * Scroll by a specified X/Y distance in the component.
247 *
248 * @param x The amount to scroll by on the horizontal axis.
249 * @param y The amount to scroll by on the vertical axis.
250 * @param duration The amount of time to take scrolling by that amount.
251 */
252 scrollByPoint(x, y, duration) {
253 return this.scrollToPoint(x + this.scrollEl.scrollLeft, y + this.scrollEl.scrollTop, duration);
254 }
255 /**
256 * Scroll to a specified X/Y location in the component.
257 *
258 * @param x The point to scroll to on the horizontal axis.
259 * @param y The point to scroll to on the vertical axis.
260 * @param duration The amount of time to take scrolling to that point. Defaults to `0`.
261 */
262 async scrollToPoint(x, y, duration = 0) {
263 const el = this.scrollEl;
264 if (duration < 32) {
265 if (y != null) {
266 el.scrollTop = y;
267 }
268 if (x != null) {
269 el.scrollLeft = x;
270 }
271 return;
272 }
273 let resolve;
274 let startTime = 0;
275 const promise = new Promise(r => resolve = r);
276 const fromY = el.scrollTop;
277 const fromX = el.scrollLeft;
278 const deltaY = y != null ? y - fromY : 0;
279 const deltaX = x != null ? x - fromX : 0;
280 // scroll loop
281 const step = (timeStamp) => {
282 const linearTime = Math.min(1, ((timeStamp - startTime) / duration)) - 1;
283 const easedT = Math.pow(linearTime, 3) + 1;
284 if (deltaY !== 0) {
285 el.scrollTop = Math.floor((easedT * deltaY) + fromY);
286 }
287 if (deltaX !== 0) {
288 el.scrollLeft = Math.floor((easedT * deltaX) + fromX);
289 }
290 if (easedT < 1) {
291 // do not use DomController here
292 // must use nativeRaf in order to fire in the next frame
293 // TODO: remove as any
294 requestAnimationFrame(step);
295 }
296 else {
297 resolve();
298 }
299 };
300 // chill out for a frame first
301 requestAnimationFrame(ts => {
302 startTime = ts;
303 step(ts);
304 });
305 return promise;
306 }
307 onScrollStart() {
308 this.isScrolling = true;
309 this.ionScrollStart.emit({
310 isScrolling: true
311 });
312 if (this.watchDog) {
313 clearInterval(this.watchDog);
314 }
315 // watchdog
316 this.watchDog = setInterval(() => {
317 if (this.lastScroll < Date.now() - 120) {
318 this.onScrollEnd();
319 }
320 }, 100);
321 }
322 onScrollEnd() {
323 clearInterval(this.watchDog);
324 this.watchDog = null;
325 if (this.isScrolling) {
326 this.isScrolling = false;
327 this.ionScrollEnd.emit({
328 isScrolling: false
329 });
330 }
331 }
332 render() {
333 const { isMainContent, scrollX, scrollY } = this;
334 const mode = ionicGlobal.getIonMode(this);
335 const forceOverscroll = this.shouldForceOverscroll();
336 const TagType = isMainContent ? 'main' : 'div';
337 const transitionShadow = (mode === 'ios' && ionicGlobal.config.getBoolean('experimentalTransitionShadow', true));
338 this.resize();
339 return (index.h(index.Host, { class: theme.createColorClasses(this.color, {
340 [mode]: true,
341 'content-sizing': theme.hostContext('ion-popover', this.el),
342 'overscroll': forceOverscroll,
343 }), style: {
344 '--offset-top': `${this.cTop}px`,
345 '--offset-bottom': `${this.cBottom}px`,
346 } }, index.h("div", { id: "background-content", part: "background" }), index.h(TagType, { class: {
347 'inner-scroll': true,
348 'scroll-x': scrollX,
349 'scroll-y': scrollY,
350 'overscroll': (scrollX || scrollY) && forceOverscroll
351 }, ref: (el) => this.scrollEl = el, onScroll: (this.scrollEvents) ? (ev) => this.onScroll(ev) : undefined, part: "scroll" }, index.h("slot", null)), transitionShadow ? (index.h("div", { class: "transition-effect" }, index.h("div", { class: "transition-cover" }), index.h("div", { class: "transition-shadow" }))) : null, index.h("slot", { name: "fixed" })));
352 }
353 get el() { return index.getElement(this); }
354};
355const getParentElement = (el) => {
356 if (el.parentElement) {
357 // normal element with a parent element
358 return el.parentElement;
359 }
360 if (el.parentNode && el.parentNode.host) {
361 // shadow dom's document fragment
362 return el.parentNode.host;
363 }
364 return null;
365};
366const getPageElement = (el) => {
367 const tabs = el.closest('ion-tabs');
368 if (tabs) {
369 return tabs;
370 }
371 const page = el.closest('ion-app,ion-page,.ion-page,page-inner');
372 if (page) {
373 return page;
374 }
375 return getParentElement(el);
376};
377// ******** DOM READ ****************
378const updateScrollDetail = (detail, el, timestamp, shouldStart) => {
379 const prevX = detail.currentX;
380 const prevY = detail.currentY;
381 const prevT = detail.currentTime;
382 const currentX = el.scrollLeft;
383 const currentY = el.scrollTop;
384 const timeDelta = timestamp - prevT;
385 if (shouldStart) {
386 // remember the start positions
387 detail.startTime = timestamp;
388 detail.startX = currentX;
389 detail.startY = currentY;
390 detail.velocityX = detail.velocityY = 0;
391 }
392 detail.currentTime = timestamp;
393 detail.currentX = detail.scrollLeft = currentX;
394 detail.currentY = detail.scrollTop = currentY;
395 detail.deltaX = currentX - detail.startX;
396 detail.deltaY = currentY - detail.startY;
397 if (timeDelta > 0 && timeDelta < 100) {
398 const velocityX = (currentX - prevX) / timeDelta;
399 const velocityY = (currentY - prevY) / timeDelta;
400 detail.velocityX = velocityX * 0.7 + detail.velocityX * 0.3;
401 detail.velocityY = velocityY * 0.7 + detail.velocityY * 0.3;
402 }
403};
404Content.style = contentCss;
405
406const footerIosCss = "ion-footer{display:block;position:relative;-ms-flex-order:1;order:1;width:100%;z-index:10}ion-footer ion-toolbar:last-of-type{padding-bottom:var(--ion-safe-area-bottom, 0)}.footer-ios ion-toolbar:first-of-type{--border-width:0.55px 0 0}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.footer-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}.footer-translucent-ios ion-toolbar{--opacity:.8}}.footer-ios.ion-no-border ion-toolbar:first-of-type{--border-width:0}";
407
408const footerMdCss = "ion-footer{display:block;position:relative;-ms-flex-order:1;order:1;width:100%;z-index:10}ion-footer ion-toolbar:last-of-type{padding-bottom:var(--ion-safe-area-bottom, 0)}.footer-md::before{left:0;top:-2px;bottom:auto;background-position:left 0 top 0;position:absolute;width:100%;height:2px;background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAHBAMAAADzDtBxAAAAD1BMVEUAAAAAAAAAAAAAAAAAAABPDueNAAAABXRSTlMUCS0gBIh/TXEAAAAaSURBVAjXYxCEAgY4UIICBmMogMsgFLtAAQCNSwXZKOdPxgAAAABJRU5ErkJggg==\");background-repeat:repeat-x;content:\"\"}[dir=rtl] .footer-md::before,:host-context([dir=rtl]) .footer-md::before{left:unset;right:unset;right:0}[dir=rtl] .footer-md::before,:host-context([dir=rtl]) .footer-md::before{background-position:right 0 top 0}.footer-md.ion-no-border::before{display:none}";
409
410const Footer = class {
411 constructor(hostRef) {
412 index.registerInstance(this, hostRef);
413 /**
414 * If `true`, the footer will be translucent.
415 * Only applies when the mode is `"ios"` and the device supports
416 * [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
417 *
418 * Note: In order to scroll content behind the footer, the `fullscreen`
419 * attribute needs to be set on the content.
420 */
421 this.translucent = false;
422 }
423 render() {
424 const mode = ionicGlobal.getIonMode(this);
425 const translucent = this.translucent;
426 return (index.h(index.Host, { role: "contentinfo", class: {
427 [mode]: true,
428 // Used internally for styling
429 [`footer-${mode}`]: true,
430 [`footer-translucent`]: translucent,
431 [`footer-translucent-${mode}`]: translucent,
432 } }, mode === 'ios' && translucent &&
433 index.h("div", { class: "footer-background" }), index.h("slot", null)));
434 }
435};
436Footer.style = {
437 ios: footerIosCss,
438 md: footerMdCss
439};
440
441const TRANSITION = 'all 0.2s ease-in-out';
442const cloneElement = (tagName) => {
443 const getCachedEl = document.querySelector(`${tagName}.ion-cloned-element`);
444 if (getCachedEl !== null) {
445 return getCachedEl;
446 }
447 const clonedEl = document.createElement(tagName);
448 clonedEl.classList.add('ion-cloned-element');
449 clonedEl.style.setProperty('display', 'none');
450 document.body.appendChild(clonedEl);
451 return clonedEl;
452};
453const createHeaderIndex = (headerEl) => {
454 if (!headerEl) {
455 return;
456 }
457 const toolbars = headerEl.querySelectorAll('ion-toolbar');
458 return {
459 el: headerEl,
460 toolbars: Array.from(toolbars).map((toolbar) => {
461 const ionTitleEl = toolbar.querySelector('ion-title');
462 return {
463 el: toolbar,
464 background: toolbar.shadowRoot.querySelector('.toolbar-background'),
465 ionTitleEl,
466 innerTitleEl: (ionTitleEl) ? ionTitleEl.shadowRoot.querySelector('.toolbar-title') : null,
467 ionButtonsEl: Array.from(toolbar.querySelectorAll('ion-buttons')) || []
468 };
469 }) || []
470 };
471};
472const handleContentScroll = (scrollEl, scrollHeaderIndex, contentEl) => {
473 index.readTask(() => {
474 const scrollTop = scrollEl.scrollTop;
475 const scale = helpers.clamp(1, 1 + (-scrollTop / 500), 1.1);
476 // Native refresher should not cause titles to scale
477 const nativeRefresher = contentEl.querySelector('ion-refresher.refresher-native');
478 if (nativeRefresher === null) {
479 index.writeTask(() => {
480 scaleLargeTitles(scrollHeaderIndex.toolbars, scale);
481 });
482 }
483 });
484};
485const setToolbarBackgroundOpacity = (toolbar, opacity) => {
486 if (opacity === undefined) {
487 toolbar.background.style.removeProperty('--opacity');
488 }
489 else {
490 toolbar.background.style.setProperty('--opacity', opacity.toString());
491 }
492};
493const handleToolbarBorderIntersection = (ev, mainHeaderIndex, scrollTop) => {
494 if (!ev[0].isIntersecting) {
495 return;
496 }
497 /**
498 * There is a bug in Safari where overflow scrolling on a non-body element
499 * does not always reset the scrollTop position to 0 when letting go. It will
500 * set to 1 once the rubber band effect has ended. This causes the background to
501 * appear slightly on certain app setups.
502 *
503 * Additionally, we check if user is rubber banding (scrolling is negative)
504 * as this can mean they are using pull to refresh. Once the refresher starts,
505 * the content is transformed which can cause the intersection observer to erroneously
506 * fire here as well.
507 */
508 const scale = (ev[0].intersectionRatio > 0.9 || scrollTop <= 0) ? 0 : ((1 - ev[0].intersectionRatio) * 100) / 75;
509 mainHeaderIndex.toolbars.forEach(toolbar => {
510 setToolbarBackgroundOpacity(toolbar, (scale === 1) ? undefined : scale);
511 });
512};
513/**
514 * If toolbars are intersecting, hide the scrollable toolbar content
515 * and show the primary toolbar content. If the toolbars are not intersecting,
516 * hide the primary toolbar content and show the scrollable toolbar content
517 */
518const handleToolbarIntersection = (ev, mainHeaderIndex, scrollHeaderIndex, scrollEl) => {
519 index.writeTask(() => {
520 const scrollTop = scrollEl.scrollTop;
521 handleToolbarBorderIntersection(ev, mainHeaderIndex, scrollTop);
522 const event = ev[0];
523 const intersection = event.intersectionRect;
524 const intersectionArea = intersection.width * intersection.height;
525 const rootArea = event.rootBounds.width * event.rootBounds.height;
526 const isPageHidden = intersectionArea === 0 && rootArea === 0;
527 const leftDiff = Math.abs(intersection.left - event.boundingClientRect.left);
528 const rightDiff = Math.abs(intersection.right - event.boundingClientRect.right);
529 const isPageTransitioning = intersectionArea > 0 && (leftDiff >= 5 || rightDiff >= 5);
530 if (isPageHidden || isPageTransitioning) {
531 return;
532 }
533 if (event.isIntersecting) {
534 setHeaderActive(mainHeaderIndex, false);
535 setHeaderActive(scrollHeaderIndex);
536 }
537 else {
538 /**
539 * There is a bug with IntersectionObserver on Safari
540 * where `event.isIntersecting === false` when cancelling
541 * a swipe to go back gesture. Checking the intersection
542 * x, y, width, and height provides a workaround. This bug
543 * does not happen when using Safari + Web Animations,
544 * only Safari + CSS Animations.
545 */
546 const hasValidIntersection = (intersection.x === 0 && intersection.y === 0) || (intersection.width !== 0 && intersection.height !== 0);
547 if (hasValidIntersection && scrollTop > 0) {
548 setHeaderActive(mainHeaderIndex);
549 setHeaderActive(scrollHeaderIndex, false);
550 setToolbarBackgroundOpacity(mainHeaderIndex.toolbars[0]);
551 }
552 }
553 });
554};
555const setHeaderActive = (headerIndex, active = true) => {
556 if (active) {
557 headerIndex.el.classList.remove('header-collapse-condense-inactive');
558 }
559 else {
560 headerIndex.el.classList.add('header-collapse-condense-inactive');
561 }
562};
563const scaleLargeTitles = (toolbars = [], scale = 1, transition = false) => {
564 toolbars.forEach(toolbar => {
565 const ionTitle = toolbar.ionTitleEl;
566 const titleDiv = toolbar.innerTitleEl;
567 if (!ionTitle || ionTitle.size !== 'large') {
568 return;
569 }
570 titleDiv.style.transition = (transition) ? TRANSITION : '';
571 titleDiv.style.transform = `scale3d(${scale}, ${scale}, 1)`;
572 });
573};
574
575const headerIosCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-ios ion-toolbar:last-of-type{--border-width:0 0 0.55px}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.header-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}.header-translucent-ios ion-toolbar{--opacity:.8}.header-collapse-condense-inactive .header-background{-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px)}}.header-ios.ion-no-border ion-toolbar:last-of-type{--border-width:0}.header-collapse-condense{z-index:9}.header-collapse-condense ion-toolbar{position:-webkit-sticky;position:sticky;top:0}.header-collapse-condense ion-toolbar:first-of-type{padding-top:7px;z-index:1}.header-collapse-condense ion-toolbar{--background:var(--ion-background-color, #fff);z-index:0}.header-collapse-condense ion-toolbar ion-searchbar{height:48px;padding-top:0px;padding-bottom:13px}.header-collapse-main ion-toolbar.in-toolbar ion-title,.header-collapse-main ion-toolbar.in-toolbar ion-buttons{-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-buttons.buttons-collapse{opacity:0;pointer-events:none}.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-buttons.buttons-collapse{visibility:hidden}";
576
577const headerMdCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-md::after{left:0;bottom:-5px;background-position:left 0 top -2px;position:absolute;width:100%;height:5px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAHBAMAAADzDtBxAAAAD1BMVEUAAAAAAAAAAAAAAAAAAABPDueNAAAABXRSTlMUCS0gBIh/TXEAAAAaSURBVAjXYxCEAgY4UIICBmMogMsgFLtAAQCNSwXZKOdPxgAAAABJRU5ErkJggg==);background-repeat:repeat-x;content:\"\"}[dir=rtl] .header-md::after,:host-context([dir=rtl]) .header-md::after{left:unset;right:unset;right:0}[dir=rtl] .header-md::after,:host-context([dir=rtl]) .header-md::after{background-position:right 0 top -2px}.header-collapse-condense{display:none}.header-md.ion-no-border::after{display:none}";
578
579const Header = class {
580 constructor(hostRef) {
581 index.registerInstance(this, hostRef);
582 this.collapsibleHeaderInitialized = false;
583 /**
584 * If `true`, the header will be translucent.
585 * Only applies when the mode is `"ios"` and the device supports
586 * [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
587 *
588 * Note: In order to scroll content behind the header, the `fullscreen`
589 * attribute needs to be set on the content.
590 */
591 this.translucent = false;
592 }
593 async componentDidLoad() {
594 await this.checkCollapsibleHeader();
595 }
596 async componentDidUpdate() {
597 await this.checkCollapsibleHeader();
598 }
599 disconnectedCallback() {
600 this.destroyCollapsibleHeader();
601 }
602 async checkCollapsibleHeader() {
603 // Determine if the header can collapse
604 const hasCollapse = this.collapse === 'condense';
605 const canCollapse = (hasCollapse && ionicGlobal.getIonMode(this) === 'ios') ? hasCollapse : false;
606 if (!canCollapse && this.collapsibleHeaderInitialized) {
607 this.destroyCollapsibleHeader();
608 }
609 else if (canCollapse && !this.collapsibleHeaderInitialized) {
610 const pageEl = this.el.closest('ion-app,ion-page,.ion-page,page-inner');
611 const contentEl = (pageEl) ? pageEl.querySelector('ion-content') : null;
612 // Cloned elements are always needed in iOS transition
613 index.writeTask(() => {
614 const title = cloneElement('ion-title');
615 title.size = 'large';
616 cloneElement('ion-back-button');
617 });
618 await this.setupCollapsibleHeader(contentEl, pageEl);
619 }
620 }
621 destroyCollapsibleHeader() {
622 if (this.intersectionObserver) {
623 this.intersectionObserver.disconnect();
624 this.intersectionObserver = undefined;
625 }
626 if (this.scrollEl && this.contentScrollCallback) {
627 this.scrollEl.removeEventListener('scroll', this.contentScrollCallback);
628 this.contentScrollCallback = undefined;
629 }
630 if (this.collapsibleMainHeader) {
631 this.collapsibleMainHeader.classList.remove('header-collapse-main');
632 this.collapsibleMainHeader = undefined;
633 }
634 }
635 async setupCollapsibleHeader(contentEl, pageEl) {
636 if (!contentEl || !pageEl) {
637 console.error('ion-header requires a content to collapse, make sure there is an ion-content.');
638 return;
639 }
640 if (typeof IntersectionObserver === 'undefined') {
641 return;
642 }
643 this.scrollEl = await contentEl.getScrollElement();
644 const headers = pageEl.querySelectorAll('ion-header');
645 this.collapsibleMainHeader = Array.from(headers).find((header) => header.collapse !== 'condense');
646 if (!this.collapsibleMainHeader) {
647 return;
648 }
649 const mainHeaderIndex = createHeaderIndex(this.collapsibleMainHeader);
650 const scrollHeaderIndex = createHeaderIndex(this.el);
651 if (!mainHeaderIndex || !scrollHeaderIndex) {
652 return;
653 }
654 setHeaderActive(mainHeaderIndex, false);
655 mainHeaderIndex.toolbars.forEach(toolbar => {
656 setToolbarBackgroundOpacity(toolbar, 0);
657 });
658 /**
659 * Handle interaction between toolbar collapse and
660 * showing/hiding content in the primary ion-header
661 * as well as progressively showing/hiding the main header
662 * border as the top-most toolbar collapses or expands.
663 */
664 const toolbarIntersection = (ev) => { handleToolbarIntersection(ev, mainHeaderIndex, scrollHeaderIndex, this.scrollEl); };
665 this.intersectionObserver = new IntersectionObserver(toolbarIntersection, { root: contentEl, threshold: [0.25, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1] });
666 this.intersectionObserver.observe(scrollHeaderIndex.toolbars[scrollHeaderIndex.toolbars.length - 1].el);
667 /**
668 * Handle scaling of large iOS titles and
669 * showing/hiding border on last toolbar
670 * in primary header
671 */
672 this.contentScrollCallback = () => { handleContentScroll(this.scrollEl, scrollHeaderIndex, contentEl); };
673 this.scrollEl.addEventListener('scroll', this.contentScrollCallback);
674 index.writeTask(() => {
675 if (this.collapsibleMainHeader !== undefined) {
676 this.collapsibleMainHeader.classList.add('header-collapse-main');
677 }
678 });
679 this.collapsibleHeaderInitialized = true;
680 }
681 render() {
682 const { translucent } = this;
683 const mode = ionicGlobal.getIonMode(this);
684 const collapse = this.collapse || 'none';
685 return (index.h(index.Host, { role: "banner", class: {
686 [mode]: true,
687 // Used internally for styling
688 [`header-${mode}`]: true,
689 [`header-translucent`]: this.translucent,
690 [`header-collapse-${collapse}`]: true,
691 [`header-translucent-${mode}`]: this.translucent,
692 } }, mode === 'ios' && translucent &&
693 index.h("div", { class: "header-background" }), index.h("slot", null)));
694 }
695 get el() { return index.getElement(this); }
696};
697Header.style = {
698 ios: headerIosCss,
699 md: headerMdCss
700};
701
702const routeOutletCss = ":host{left:0;right:0;top:0;bottom:0;position:absolute;contain:layout size style;overflow:hidden;z-index:0}";
703
704const RouterOutlet = class {
705 constructor(hostRef) {
706 index.registerInstance(this, hostRef);
707 this.ionNavWillLoad = index.createEvent(this, "ionNavWillLoad", 7);
708 this.ionNavWillChange = index.createEvent(this, "ionNavWillChange", 3);
709 this.ionNavDidChange = index.createEvent(this, "ionNavDidChange", 3);
710 this.gestureOrAnimationInProgress = false;
711 /**
712 * The mode determines which platform styles to use.
713 */
714 this.mode = ionicGlobal.getIonMode(this);
715 /**
716 * If `true`, the router-outlet should animate the transition of components.
717 */
718 this.animated = true;
719 }
720 swipeHandlerChanged() {
721 if (this.gesture) {
722 this.gesture.enable(this.swipeHandler !== undefined);
723 }
724 }
725 async connectedCallback() {
726 const onStart = () => {
727 this.gestureOrAnimationInProgress = true;
728 if (this.swipeHandler) {
729 this.swipeHandler.onStart();
730 }
731 };
732 this.gesture = (await Promise.resolve().then(function () { return require('./swipe-back-e654d7fd.js'); })).createSwipeBackGesture(this.el, () => !this.gestureOrAnimationInProgress && !!this.swipeHandler && this.swipeHandler.canStart(), () => onStart(), step => this.ani && this.ani.progressStep(step), (shouldComplete, step, dur) => {
733 if (this.ani) {
734 this.ani.onFinish(() => {
735 this.gestureOrAnimationInProgress = false;
736 if (this.swipeHandler) {
737 this.swipeHandler.onEnd(shouldComplete);
738 }
739 }, { oneTimeCallback: true });
740 // Account for rounding errors in JS
741 let newStepValue = (shouldComplete) ? -0.001 : 0.001;
742 /**
743 * Animation will be reversed here, so need to
744 * reverse the easing curve as well
745 *
746 * Additionally, we need to account for the time relative
747 * to the new easing curve, as `stepValue` is going to be given
748 * in terms of a linear curve.
749 */
750 if (!shouldComplete) {
751 this.ani.easing('cubic-bezier(1, 0, 0.68, 0.28)');
752 newStepValue += cubicBezier.getTimeGivenProgression([0, 0], [1, 0], [0.68, 0.28], [1, 1], step)[0];
753 }
754 else {
755 newStepValue += cubicBezier.getTimeGivenProgression([0, 0], [0.32, 0.72], [0, 1], [1, 1], step)[0];
756 }
757 this.ani.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
758 }
759 else {
760 this.gestureOrAnimationInProgress = false;
761 }
762 });
763 this.swipeHandlerChanged();
764 }
765 componentWillLoad() {
766 this.ionNavWillLoad.emit();
767 }
768 disconnectedCallback() {
769 if (this.gesture) {
770 this.gesture.destroy();
771 this.gesture = undefined;
772 }
773 }
774 /** @internal */
775 async commit(enteringEl, leavingEl, opts) {
776 const unlock = await this.lock();
777 let changed = false;
778 try {
779 changed = await this.transition(enteringEl, leavingEl, opts);
780 }
781 catch (e) {
782 console.error(e);
783 }
784 unlock();
785 return changed;
786 }
787 /** @internal */
788 async setRouteId(id, params, direction, animation) {
789 const changed = await this.setRoot(id, params, {
790 duration: direction === 'root' ? 0 : undefined,
791 direction: direction === 'back' ? 'back' : 'forward',
792 animationBuilder: animation
793 });
794 return {
795 changed,
796 element: this.activeEl
797 };
798 }
799 /** @internal */
800 async getRouteId() {
801 const active = this.activeEl;
802 return active ? {
803 id: active.tagName,
804 element: active,
805 } : undefined;
806 }
807 async setRoot(component, params, opts) {
808 if (this.activeComponent === component) {
809 return false;
810 }
811 // attach entering view to DOM
812 const leavingEl = this.activeEl;
813 const enteringEl = await frameworkDelegate.attachComponent(this.delegate, this.el, component, ['ion-page', 'ion-page-invisible'], params);
814 this.activeComponent = component;
815 this.activeEl = enteringEl;
816 // commit animation
817 await this.commit(enteringEl, leavingEl, opts);
818 await frameworkDelegate.detachComponent(this.delegate, leavingEl);
819 return true;
820 }
821 async transition(enteringEl, leavingEl, opts = {}) {
822 if (leavingEl === enteringEl) {
823 return false;
824 }
825 // emit nav will change event
826 this.ionNavWillChange.emit();
827 const { el, mode } = this;
828 const animated = this.animated && ionicGlobal.config.getBoolean('animated', true);
829 const animationBuilder = opts.animationBuilder || this.animation || ionicGlobal.config.get('navAnimation');
830 await index$1.transition(Object.assign(Object.assign({ mode,
831 animated,
832 enteringEl,
833 leavingEl, baseEl: el, progressCallback: (opts.progressAnimation
834 ? ani => {
835 /**
836 * Because this progress callback is called asynchronously
837 * it is possible for the gesture to start and end before
838 * the animation is ever set. In that scenario, we should
839 * immediately call progressEnd so that the transition promise
840 * resolves and the gesture does not get locked up.
841 */
842 if (ani !== undefined && !this.gestureOrAnimationInProgress) {
843 this.gestureOrAnimationInProgress = true;
844 ani.onFinish(() => {
845 this.gestureOrAnimationInProgress = false;
846 if (this.swipeHandler) {
847 this.swipeHandler.onEnd(false);
848 }
849 }, { oneTimeCallback: true });
850 /**
851 * Playing animation to beginning
852 * with a duration of 0 prevents
853 * any flickering when the animation
854 * is later cleaned up.
855 */
856 ani.progressEnd(0, 0, 0);
857 }
858 else {
859 this.ani = ani;
860 }
861 }
862 : undefined) }, opts), { animationBuilder }));
863 // emit nav changed event
864 this.ionNavDidChange.emit();
865 return true;
866 }
867 async lock() {
868 const p = this.waitPromise;
869 let resolve;
870 this.waitPromise = new Promise(r => resolve = r);
871 if (p !== undefined) {
872 await p;
873 }
874 return resolve;
875 }
876 render() {
877 return (index.h("slot", null));
878 }
879 get el() { return index.getElement(this); }
880 static get watchers() { return {
881 "swipeHandler": ["swipeHandlerChanged"]
882 }; }
883};
884RouterOutlet.style = routeOutletCss;
885
886const titleIosCss = ":host{--color:initial;display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-align:center;align-items:center;-webkit-transform:translateZ(0);transform:translateZ(0);color:var(--color)}:host(.ion-color){color:var(--ion-color-base)}.toolbar-title{display:block;width:100%;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;pointer-events:auto}:host(.title-small) .toolbar-title{white-space:normal}:host{left:0;top:0;padding-left:90px;padding-right:90px;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);position:absolute;width:100%;height:100%;-webkit-transform:translateZ(0);transform:translateZ(0);font-size:17px;font-weight:600;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;pointer-events:none}:host-context([dir=rtl]){left:unset;right:unset;right:0}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){:host{padding-left:unset;padding-right:unset;-webkit-padding-start:90px;padding-inline-start:90px;-webkit-padding-end:90px;padding-inline-end:90px}}:host(.title-small){padding-left:9px;padding-right:9px;padding-top:6px;padding-bottom:16px;position:relative;font-size:13px;font-weight:normal}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){:host(.title-small){padding-left:unset;padding-right:unset;-webkit-padding-start:9px;padding-inline-start:9px;-webkit-padding-end:9px;padding-inline-end:9px}}:host(.title-large){padding-left:16px;padding-right:16px;padding-top:0;padding-bottom:0;-webkit-transform-origin:left center;transform-origin:left center;bottom:0;-ms-flex-align:end;align-items:flex-end;min-width:100%;padding-bottom:6px;font-size:34px;font-weight:700;text-align:start}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){:host(.title-large){padding-left:unset;padding-right:unset;-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px}}:host(.title-large.title-rtl){-webkit-transform-origin:right center;transform-origin:right center}:host(.title-large.ion-cloned-element){--color:var(--ion-text-color, #000)}:host(.title-large) .toolbar-title{-webkit-transform-origin:inherit;transform-origin:inherit}:host-context([dir=rtl]):host(.title-large) .toolbar-title,:host-context([dir=rtl]).title-large .toolbar-title{-webkit-transform-origin:calc(100% - inherit);transform-origin:calc(100% - inherit)}";
887
888const titleMdCss = ":host{--color:initial;display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-align:center;align-items:center;-webkit-transform:translateZ(0);transform:translateZ(0);color:var(--color)}:host(.ion-color){color:var(--ion-color-base)}.toolbar-title{display:block;width:100%;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;pointer-events:auto}:host(.title-small) .toolbar-title{white-space:normal}:host{padding-left:20px;padding-right:20px;padding-top:0;padding-bottom:0;font-size:20px;font-weight:500;letter-spacing:0.0125em}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){:host{padding-left:unset;padding-right:unset;-webkit-padding-start:20px;padding-inline-start:20px;-webkit-padding-end:20px;padding-inline-end:20px}}:host(.title-small){width:100%;height:100%;font-size:15px;font-weight:normal}";
889
890const ToolbarTitle = class {
891 constructor(hostRef) {
892 index.registerInstance(this, hostRef);
893 this.ionStyle = index.createEvent(this, "ionStyle", 7);
894 }
895 sizeChanged() {
896 this.emitStyle();
897 }
898 connectedCallback() {
899 this.emitStyle();
900 }
901 emitStyle() {
902 const size = this.getSize();
903 this.ionStyle.emit({
904 [`title-${size}`]: true
905 });
906 }
907 getSize() {
908 return (this.size !== undefined) ? this.size : 'default';
909 }
910 render() {
911 const mode = ionicGlobal.getIonMode(this);
912 const size = this.getSize();
913 return (index.h(index.Host, { class: theme.createColorClasses(this.color, {
914 [mode]: true,
915 [`title-${size}`]: true,
916 'title-rtl': document.dir === 'rtl'
917 }) }, index.h("div", { class: "toolbar-title" }, index.h("slot", null))));
918 }
919 get el() { return index.getElement(this); }
920 static get watchers() { return {
921 "size": ["sizeChanged"]
922 }; }
923};
924ToolbarTitle.style = {
925 ios: titleIosCss,
926 md: titleMdCss
927};
928
929const toolbarIosCss = ":host{--border-width:0;--border-style:solid;--opacity:1;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;padding-left:var(--ion-safe-area-left);padding-right:var(--ion-safe-area-right);display:block;position:relative;width:100%;color:var(--color);font-family:var(--ion-font-family, inherit);contain:content;z-index:10;-webkit-box-sizing:border-box;box-sizing:border-box}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){:host{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--ion-safe-area-left);padding-inline-start:var(--ion-safe-area-left);-webkit-padding-end:var(--ion-safe-area-right);padding-inline-end:var(--ion-safe-area-right)}}:host(.ion-color){color:var(--ion-color-contrast)}:host(.ion-color) .toolbar-background{background:var(--ion-color-base)}.toolbar-container{padding-left:var(--padding-start);padding-right:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:row;flex-direction:row;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;width:100%;min-height:var(--min-height);contain:content;overflow:hidden;z-index:10;-webkit-box-sizing:border-box;box-sizing:border-box}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toolbar-container{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end)}}.toolbar-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-transform:translateZ(0);transform:translateZ(0);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);contain:strict;opacity:var(--opacity);z-index:-1;pointer-events:none}::slotted(ion-progress-bar){left:0;right:0;bottom:0;position:absolute}:host{--background:var(--ion-toolbar-background, var(--ion-color-step-50, #fff));--color:var(--ion-toolbar-color, var(--ion-text-color, #000));--border-color:var(--ion-toolbar-border-color, var(--ion-border-color, var(--ion-color-step-150, rgba(0, 0, 0, 0.2))));--padding-top:3px;--padding-bottom:3px;--padding-start:4px;--padding-end:4px;--min-height:44px}.toolbar-content{-ms-flex:1;flex:1;-ms-flex-order:4;order:4;min-width:0}:host(.toolbar-segment) .toolbar-content{display:-ms-inline-flexbox;display:inline-flex}:host(.toolbar-searchbar) .toolbar-container{padding-top:0;padding-bottom:0}:host(.toolbar-searchbar) ::slotted(*){-ms-flex-item-align:start;align-self:start}:host(.toolbar-searchbar) ::slotted(ion-chip){margin-top:3px}:host(.toolbar-searchbar) ::slotted(ion-back-button){height:38px}::slotted(ion-buttons){min-height:38px}::slotted([slot=start]){-ms-flex-order:2;order:2}::slotted([slot=secondary]){-ms-flex-order:3;order:3}::slotted([slot=primary]){-ms-flex-order:5;order:5;text-align:end}::slotted([slot=end]){-ms-flex-order:6;order:6;text-align:end}:host(.toolbar-title-large) .toolbar-container{-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:start;align-items:flex-start}:host(.toolbar-title-large) .toolbar-content ion-title{-ms-flex:1;flex:1;-ms-flex-order:8;order:8;min-width:100%}";
930
931const toolbarMdCss = ":host{--border-width:0;--border-style:solid;--opacity:1;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;padding-left:var(--ion-safe-area-left);padding-right:var(--ion-safe-area-right);display:block;position:relative;width:100%;color:var(--color);font-family:var(--ion-font-family, inherit);contain:content;z-index:10;-webkit-box-sizing:border-box;box-sizing:border-box}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){:host{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--ion-safe-area-left);padding-inline-start:var(--ion-safe-area-left);-webkit-padding-end:var(--ion-safe-area-right);padding-inline-end:var(--ion-safe-area-right)}}:host(.ion-color){color:var(--ion-color-contrast)}:host(.ion-color) .toolbar-background{background:var(--ion-color-base)}.toolbar-container{padding-left:var(--padding-start);padding-right:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:row;flex-direction:row;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;width:100%;min-height:var(--min-height);contain:content;overflow:hidden;z-index:10;-webkit-box-sizing:border-box;box-sizing:border-box}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toolbar-container{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end)}}.toolbar-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-transform:translateZ(0);transform:translateZ(0);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);contain:strict;opacity:var(--opacity);z-index:-1;pointer-events:none}::slotted(ion-progress-bar){left:0;right:0;bottom:0;position:absolute}:host{--background:var(--ion-toolbar-background, var(--ion-background-color, #fff));--color:var(--ion-toolbar-color, var(--ion-text-color, #424242));--border-color:var(--ion-toolbar-border-color, var(--ion-border-color, var(--ion-color-step-150, #c1c4cd)));--padding-top:0;--padding-bottom:0;--padding-start:0;--padding-end:0;--min-height:56px}.toolbar-content{-ms-flex:1;flex:1;-ms-flex-order:3;order:3;min-width:0;max-width:100%}::slotted(ion-segment){min-height:var(--min-height)}::slotted(.buttons-first-slot){margin-left:4px}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){::slotted(.buttons-first-slot){margin-left:unset;-webkit-margin-start:4px;margin-inline-start:4px}}::slotted(.buttons-last-slot){margin-right:4px}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){::slotted(.buttons-last-slot){margin-right:unset;-webkit-margin-end:4px;margin-inline-end:4px}}::slotted([slot=start]){-ms-flex-order:2;order:2}::slotted([slot=secondary]){-ms-flex-order:4;order:4}::slotted([slot=primary]){-ms-flex-order:5;order:5;text-align:end}::slotted([slot=end]){-ms-flex-order:6;order:6;text-align:end}";
932
933const Toolbar = class {
934 constructor(hostRef) {
935 index.registerInstance(this, hostRef);
936 this.childrenStyles = new Map();
937 }
938 componentWillLoad() {
939 const buttons = Array.from(this.el.querySelectorAll('ion-buttons'));
940 const firstButtons = buttons.find(button => {
941 return button.slot === 'start';
942 });
943 if (firstButtons) {
944 firstButtons.classList.add('buttons-first-slot');
945 }
946 const buttonsReversed = buttons.reverse();
947 const lastButtons = buttonsReversed.find(button => button.slot === 'end') ||
948 buttonsReversed.find(button => button.slot === 'primary') ||
949 buttonsReversed.find(button => button.slot === 'secondary');
950 if (lastButtons) {
951 lastButtons.classList.add('buttons-last-slot');
952 }
953 }
954 childrenStyle(ev) {
955 ev.stopPropagation();
956 const tagName = ev.target.tagName;
957 const updatedStyles = ev.detail;
958 const newStyles = {};
959 const childStyles = this.childrenStyles.get(tagName) || {};
960 let hasStyleChange = false;
961 Object.keys(updatedStyles).forEach(key => {
962 const childKey = `toolbar-${key}`;
963 const newValue = updatedStyles[key];
964 if (newValue !== childStyles[childKey]) {
965 hasStyleChange = true;
966 }
967 if (newValue) {
968 newStyles[childKey] = true;
969 }
970 });
971 if (hasStyleChange) {
972 this.childrenStyles.set(tagName, newStyles);
973 index.forceUpdate(this);
974 }
975 }
976 render() {
977 const mode = ionicGlobal.getIonMode(this);
978 const childStyles = {};
979 this.childrenStyles.forEach(value => {
980 Object.assign(childStyles, value);
981 });
982 return (index.h(index.Host, { class: Object.assign(Object.assign({}, childStyles), theme.createColorClasses(this.color, {
983 [mode]: true,
984 'in-toolbar': theme.hostContext('ion-toolbar', this.el),
985 })) }, index.h("div", { class: "toolbar-background" }), index.h("div", { class: "toolbar-container" }, index.h("slot", { name: "start" }), index.h("slot", { name: "secondary" }), index.h("div", { class: "toolbar-content" }, index.h("slot", null)), index.h("slot", { name: "primary" }), index.h("slot", { name: "end" }))));
986 }
987 get el() { return index.getElement(this); }
988};
989Toolbar.style = {
990 ios: toolbarIosCss,
991 md: toolbarMdCss
992};
993
994exports.ion_app = App;
995exports.ion_buttons = Buttons;
996exports.ion_content = Content;
997exports.ion_footer = Footer;
998exports.ion_header = Header;
999exports.ion_router_outlet = RouterOutlet;
1000exports.ion_title = ToolbarTitle;
1001exports.ion_toolbar = Toolbar;