UNPKG

47.3 kBJavaScriptView Raw
1/*!
2 * (C) Ionic http://ionicframework.com - MIT License
3 */
4import { proxyCustomElement, HTMLElement, createEvent, writeTask, h, Host } from '@stencil/core/internal/client';
5import { b as getIonMode, c as config } from './ionic-global.js';
6import { C as CoreDelegate, a as attachComponent, d as detachComponent } from './framework-delegate.js';
7import { j as clamp, g as getElementRoot, r as raf } from './helpers.js';
8import { KEYBOARD_DID_OPEN } from './keyboard.js';
9import { B as BACKDROP, e as prepareOverlay, d as present, k as activeAnimations, f as dismiss, g as eventMethod } from './overlays.js';
10import { g as getClassMap } from './theme.js';
11import { e as deepReady } from './index4.js';
12import { c as createAnimation } from './animation.js';
13import { g as getTimeGivenProgression } from './cubic-bezier.js';
14import { createGesture } from './index2.js';
15import { d as defineCustomElement$2 } from './backdrop.js';
16
17// Defaults for the card swipe animation
18const SwipeToCloseDefaults = {
19 MIN_PRESENTING_SCALE: 0.93,
20};
21const createSwipeToCloseGesture = (el, animation, onDismiss) => {
22 const height = el.offsetHeight;
23 let isOpen = false;
24 const canStart = (detail) => {
25 const target = detail.event.target;
26 if (target === null ||
27 !target.closest) {
28 return true;
29 }
30 const contentOrFooter = target.closest('ion-content, ion-footer');
31 if (contentOrFooter === null) {
32 return true;
33 }
34 // Target is in the content or the footer so do not start the gesture.
35 // We could be more nuanced here and allow it for content that
36 // does not need to scroll.
37 return false;
38 };
39 const onStart = () => {
40 animation.progressStart(true, (isOpen) ? 1 : 0);
41 };
42 const onMove = (detail) => {
43 const step = clamp(0.0001, detail.deltaY / height, 0.9999);
44 animation.progressStep(step);
45 };
46 const onEnd = (detail) => {
47 const velocity = detail.velocityY;
48 const step = clamp(0.0001, detail.deltaY / height, 0.9999);
49 const threshold = (detail.deltaY + velocity * 1000) / height;
50 const shouldComplete = threshold >= 0.5;
51 let newStepValue = (shouldComplete) ? -0.001 : 0.001;
52 if (!shouldComplete) {
53 animation.easing('cubic-bezier(1, 0, 0.68, 0.28)');
54 newStepValue += getTimeGivenProgression([0, 0], [1, 0], [0.68, 0.28], [1, 1], step)[0];
55 }
56 else {
57 animation.easing('cubic-bezier(0.32, 0.72, 0, 1)');
58 newStepValue += getTimeGivenProgression([0, 0], [0.32, 0.72], [0, 1], [1, 1], step)[0];
59 }
60 const duration = (shouldComplete) ? computeDuration(step * height, velocity) : computeDuration((1 - step) * height, velocity);
61 isOpen = shouldComplete;
62 gesture.enable(false);
63 animation
64 .onFinish(() => {
65 if (!shouldComplete) {
66 gesture.enable(true);
67 }
68 })
69 .progressEnd((shouldComplete) ? 1 : 0, newStepValue, duration);
70 if (shouldComplete) {
71 onDismiss();
72 }
73 };
74 const gesture = createGesture({
75 el,
76 gestureName: 'modalSwipeToClose',
77 gesturePriority: 40,
78 direction: 'y',
79 threshold: 10,
80 canStart,
81 onStart,
82 onMove,
83 onEnd
84 });
85 return gesture;
86};
87const computeDuration = (remaining, velocity) => {
88 return clamp(400, remaining / Math.abs(velocity * 1.1), 500);
89};
90
91/**
92 * Use y = mx + b to
93 * figure out the backdrop value
94 * at a particular x coordinate. This
95 * is useful when the backdrop does
96 * not begin to fade in until after
97 * the 0 breakpoint.
98 */
99const getBackdropValueForSheet = (x, backdropBreakpoint) => {
100 /**
101 * We will use these points:
102 * (backdropBreakpoint, 0)
103 * (maxBreakpoint, 1)
104 * We know that at the beginning breakpoint,
105 * the backdrop will be hidden. We also
106 * know that at the maxBreakpoint, the backdrop
107 * must be fully visible. maxBreakpoint should
108 * always be 1 even if the maximum value
109 * of the breakpoints array is not 1 since
110 * the animation runs from a progress of 0
111 * to a progress of 1.
112 * m = (y2 - y1) / (x2 - x1)
113 *
114 * This is simplified from:
115 * m = (1 - 0) / (maxBreakpoint - backdropBreakpoint)
116 */
117 const slope = 1 / (1 - backdropBreakpoint);
118 /**
119 * From here, compute b which is
120 * the backdrop opacity if the offset
121 * is 0. If the backdrop does not
122 * begin to fade in until after the
123 * 0 breakpoint, this b value will be
124 * negative. This is fine as we never pass
125 * b directly into the animation keyframes.
126 * b = y - mx
127 * Use a known point: (backdropBreakpoint, 0)
128 * This is simplified from:
129 * b = 0 - (backdropBreakpoint * slope)
130 */
131 const b = -(backdropBreakpoint * slope);
132 /**
133 * Finally, we can now determine the
134 * backdrop offset given an arbitrary
135 * gesture offset.
136 */
137 return (x * slope) + b;
138};
139
140const createSheetEnterAnimation = (opts) => {
141 const { currentBreakpoint, backdropBreakpoint } = opts;
142 /**
143 * If the backdropBreakpoint is undefined, then the backdrop
144 * should always fade in. If the backdropBreakpoint came before the
145 * current breakpoint, then the backdrop should be fading in.
146 */
147 const shouldShowBackdrop = backdropBreakpoint === undefined || backdropBreakpoint < currentBreakpoint;
148 const initialBackdrop = shouldShowBackdrop ? `calc(var(--backdrop-opacity) * ${currentBreakpoint})` : '0';
149 const backdropAnimation = createAnimation('backdropAnimation')
150 .fromTo('opacity', 0, initialBackdrop);
151 if (shouldShowBackdrop) {
152 backdropAnimation
153 .beforeStyles({
154 'pointer-events': 'none'
155 })
156 .afterClearStyles(['pointer-events']);
157 }
158 const wrapperAnimation = createAnimation('wrapperAnimation')
159 .keyframes([
160 { offset: 0, opacity: 1, transform: 'translateY(100%)' },
161 { offset: 1, opacity: 1, transform: `translateY(${100 - (currentBreakpoint * 100)}%)` }
162 ]);
163 return { wrapperAnimation, backdropAnimation };
164};
165const createSheetLeaveAnimation = (opts) => {
166 const { currentBreakpoint, backdropBreakpoint } = opts;
167 /**
168 * Backdrop does not always fade in from 0 to 1 if backdropBreakpoint
169 * is defined, so we need to account for that offset by figuring out
170 * what the current backdrop value should be.
171 */
172 const backdropValue = `calc(var(--backdrop-opacity) * ${getBackdropValueForSheet(currentBreakpoint, backdropBreakpoint)})`;
173 const defaultBackdrop = [
174 { offset: 0, opacity: backdropValue },
175 { offset: 1, opacity: 0 }
176 ];
177 const customBackdrop = [
178 { offset: 0, opacity: backdropValue },
179 { offset: backdropBreakpoint, opacity: 0 },
180 { offset: 1, opacity: 0 }
181 ];
182 const backdropAnimation = createAnimation('backdropAnimation')
183 .keyframes(backdropBreakpoint !== 0 ? customBackdrop : defaultBackdrop);
184 const wrapperAnimation = createAnimation('wrapperAnimation')
185 .keyframes([
186 { offset: 0, opacity: 1, transform: `translateY(${100 - (currentBreakpoint * 100)}%)` },
187 { offset: 1, opacity: 1, transform: `translateY(100%)` }
188 ]);
189 return { wrapperAnimation, backdropAnimation };
190};
191
192const createEnterAnimation$1 = () => {
193 const backdropAnimation = createAnimation()
194 .fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
195 .beforeStyles({
196 'pointer-events': 'none'
197 })
198 .afterClearStyles(['pointer-events']);
199 const wrapperAnimation = createAnimation()
200 .fromTo('transform', 'translateY(100vh)', 'translateY(0vh)');
201 return { backdropAnimation, wrapperAnimation };
202};
203/**
204 * iOS Modal Enter Animation for the Card presentation style
205 */
206const iosEnterAnimation = (baseEl, opts) => {
207 const { presentingEl, currentBreakpoint } = opts;
208 const root = getElementRoot(baseEl);
209 const { wrapperAnimation, backdropAnimation } = currentBreakpoint !== undefined ? createSheetEnterAnimation(opts) : createEnterAnimation$1();
210 backdropAnimation
211 .addElement(root.querySelector('ion-backdrop'));
212 wrapperAnimation
213 .addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow'))
214 .beforeStyles({ 'opacity': 1 });
215 const baseAnimation = createAnimation('entering-base')
216 .addElement(baseEl)
217 .easing('cubic-bezier(0.32,0.72,0,1)')
218 .duration(500)
219 .addAnimation(wrapperAnimation);
220 if (presentingEl) {
221 const isMobile = window.innerWidth < 768;
222 const hasCardModal = (presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined);
223 const presentingElRoot = getElementRoot(presentingEl);
224 const presentingAnimation = createAnimation()
225 .beforeStyles({
226 'transform': 'translateY(0)',
227 'transform-origin': 'top center',
228 'overflow': 'hidden'
229 });
230 const bodyEl = document.body;
231 if (isMobile) {
232 /**
233 * Fallback for browsers that does not support `max()` (ex: Firefox)
234 * No need to worry about statusbar padding since engines like Gecko
235 * are not used as the engine for standalone Cordova/Capacitor apps
236 */
237 const transformOffset = (!CSS.supports('width', 'max(0px, 1px)')) ? '30px' : 'max(30px, var(--ion-safe-area-top))';
238 const modalTransform = hasCardModal ? '-10px' : transformOffset;
239 const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
240 const finalTransform = `translateY(${modalTransform}) scale(${toPresentingScale})`;
241 presentingAnimation
242 .afterStyles({
243 'transform': finalTransform
244 })
245 .beforeAddWrite(() => bodyEl.style.setProperty('background-color', 'black'))
246 .addElement(presentingEl)
247 .keyframes([
248 { offset: 0, filter: 'contrast(1)', transform: 'translateY(0px) scale(1)', borderRadius: '0px' },
249 { offset: 1, filter: 'contrast(0.85)', transform: finalTransform, borderRadius: '10px 10px 0 0' }
250 ]);
251 baseAnimation.addAnimation(presentingAnimation);
252 }
253 else {
254 baseAnimation.addAnimation(backdropAnimation);
255 if (!hasCardModal) {
256 wrapperAnimation.fromTo('opacity', '0', '1');
257 }
258 else {
259 const toPresentingScale = (hasCardModal) ? SwipeToCloseDefaults.MIN_PRESENTING_SCALE : 1;
260 const finalTransform = `translateY(-10px) scale(${toPresentingScale})`;
261 presentingAnimation
262 .afterStyles({
263 'transform': finalTransform
264 })
265 .addElement(presentingElRoot.querySelector('.modal-wrapper'))
266 .keyframes([
267 { offset: 0, filter: 'contrast(1)', transform: 'translateY(0) scale(1)' },
268 { offset: 1, filter: 'contrast(0.85)', transform: finalTransform }
269 ]);
270 const shadowAnimation = createAnimation()
271 .afterStyles({
272 'transform': finalTransform
273 })
274 .addElement(presentingElRoot.querySelector('.modal-shadow'))
275 .keyframes([
276 { offset: 0, opacity: '1', transform: 'translateY(0) scale(1)' },
277 { offset: 1, opacity: '0', transform: finalTransform }
278 ]);
279 baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
280 }
281 }
282 }
283 else {
284 baseAnimation.addAnimation(backdropAnimation);
285 }
286 return baseAnimation;
287};
288
289const createLeaveAnimation$1 = () => {
290 const backdropAnimation = createAnimation()
291 .fromTo('opacity', 'var(--backdrop-opacity)', 0);
292 const wrapperAnimation = createAnimation()
293 .fromTo('transform', 'translateY(0vh)', 'translateY(100vh)');
294 return { backdropAnimation, wrapperAnimation };
295};
296/**
297 * iOS Modal Leave Animation
298 */
299const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
300 const { presentingEl, currentBreakpoint } = opts;
301 const root = getElementRoot(baseEl);
302 const { wrapperAnimation, backdropAnimation } = currentBreakpoint !== undefined ? createSheetLeaveAnimation(opts) : createLeaveAnimation$1();
303 backdropAnimation.addElement(root.querySelector('ion-backdrop'));
304 wrapperAnimation
305 .addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow'))
306 .beforeStyles({ 'opacity': 1 });
307 const baseAnimation = createAnimation('leaving-base')
308 .addElement(baseEl)
309 .easing('cubic-bezier(0.32,0.72,0,1)')
310 .duration(duration)
311 .addAnimation(wrapperAnimation);
312 if (presentingEl) {
313 const isMobile = window.innerWidth < 768;
314 const hasCardModal = (presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined);
315 const presentingElRoot = getElementRoot(presentingEl);
316 const presentingAnimation = createAnimation()
317 .beforeClearStyles(['transform'])
318 .afterClearStyles(['transform'])
319 .onFinish(currentStep => {
320 // only reset background color if this is the last card-style modal
321 if (currentStep !== 1) {
322 return;
323 }
324 presentingEl.style.setProperty('overflow', '');
325 const numModals = Array.from(bodyEl.querySelectorAll('ion-modal')).filter(m => m.presentingElement !== undefined).length;
326 if (numModals <= 1) {
327 bodyEl.style.setProperty('background-color', '');
328 }
329 });
330 const bodyEl = document.body;
331 if (isMobile) {
332 const transformOffset = (!CSS.supports('width', 'max(0px, 1px)')) ? '30px' : 'max(30px, var(--ion-safe-area-top))';
333 const modalTransform = hasCardModal ? '-10px' : transformOffset;
334 const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
335 const finalTransform = `translateY(${modalTransform}) scale(${toPresentingScale})`;
336 presentingAnimation
337 .addElement(presentingEl)
338 .keyframes([
339 { offset: 0, filter: 'contrast(0.85)', transform: finalTransform, borderRadius: '10px 10px 0 0' },
340 { offset: 1, filter: 'contrast(1)', transform: 'translateY(0px) scale(1)', borderRadius: '0px' }
341 ]);
342 baseAnimation.addAnimation(presentingAnimation);
343 }
344 else {
345 baseAnimation.addAnimation(backdropAnimation);
346 if (!hasCardModal) {
347 wrapperAnimation.fromTo('opacity', '1', '0');
348 }
349 else {
350 const toPresentingScale = (hasCardModal) ? SwipeToCloseDefaults.MIN_PRESENTING_SCALE : 1;
351 const finalTransform = `translateY(-10px) scale(${toPresentingScale})`;
352 presentingAnimation
353 .addElement(presentingElRoot.querySelector('.modal-wrapper'))
354 .afterStyles({
355 'transform': 'translate3d(0, 0, 0)'
356 })
357 .keyframes([
358 { offset: 0, filter: 'contrast(0.85)', transform: finalTransform },
359 { offset: 1, filter: 'contrast(1)', transform: 'translateY(0) scale(1)' }
360 ]);
361 const shadowAnimation = createAnimation()
362 .addElement(presentingElRoot.querySelector('.modal-shadow'))
363 .afterStyles({
364 'transform': 'translateY(0) scale(1)'
365 })
366 .keyframes([
367 { offset: 0, opacity: '0', transform: finalTransform },
368 { offset: 1, opacity: '1', transform: 'translateY(0) scale(1)' }
369 ]);
370 baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
371 }
372 }
373 }
374 else {
375 baseAnimation.addAnimation(backdropAnimation);
376 }
377 return baseAnimation;
378};
379
380const createEnterAnimation = () => {
381 const backdropAnimation = createAnimation()
382 .fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
383 .beforeStyles({
384 'pointer-events': 'none'
385 })
386 .afterClearStyles(['pointer-events']);
387 const wrapperAnimation = createAnimation()
388 .keyframes([
389 { offset: 0, opacity: 0.01, transform: 'translateY(40px)' },
390 { offset: 1, opacity: 1, transform: `translateY(0px)` }
391 ]);
392 return { backdropAnimation, wrapperAnimation };
393};
394/**
395 * Md Modal Enter Animation
396 */
397const mdEnterAnimation = (baseEl, opts) => {
398 const { currentBreakpoint } = opts;
399 const root = getElementRoot(baseEl);
400 const { wrapperAnimation, backdropAnimation } = currentBreakpoint !== undefined ? createSheetEnterAnimation(opts) : createEnterAnimation();
401 backdropAnimation
402 .addElement(root.querySelector('ion-backdrop'));
403 wrapperAnimation
404 .addElement(root.querySelector('.modal-wrapper'));
405 return createAnimation()
406 .addElement(baseEl)
407 .easing('cubic-bezier(0.36,0.66,0.04,1)')
408 .duration(280)
409 .addAnimation([backdropAnimation, wrapperAnimation]);
410};
411
412const createLeaveAnimation = () => {
413 const backdropAnimation = createAnimation()
414 .fromTo('opacity', 'var(--backdrop-opacity)', 0);
415 const wrapperAnimation = createAnimation()
416 .keyframes([
417 { offset: 0, opacity: 0.99, transform: `translateY(0px)` },
418 { offset: 1, opacity: 0, transform: 'translateY(40px)' }
419 ]);
420 return { backdropAnimation, wrapperAnimation };
421};
422/**
423 * Md Modal Leave Animation
424 */
425const mdLeaveAnimation = (baseEl, opts) => {
426 const { currentBreakpoint } = opts;
427 const root = getElementRoot(baseEl);
428 const { wrapperAnimation, backdropAnimation } = currentBreakpoint !== undefined ? createSheetLeaveAnimation(opts) : createLeaveAnimation();
429 backdropAnimation.addElement(root.querySelector('ion-backdrop'));
430 wrapperAnimation.addElement(root.querySelector('.modal-wrapper'));
431 return createAnimation()
432 .easing('cubic-bezier(0.47,0,0.745,0.715)')
433 .duration(200)
434 .addAnimation([backdropAnimation, wrapperAnimation]);
435};
436
437const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], onDismiss, onBreakpointChange) => {
438 // Defaults for the sheet swipe animation
439 const defaultBackdrop = [
440 { offset: 0, opacity: 'var(--backdrop-opacity)' },
441 { offset: 1, opacity: 0.01 }
442 ];
443 const customBackdrop = [
444 { offset: 0, opacity: 'var(--backdrop-opacity)' },
445 { offset: 1 - backdropBreakpoint, opacity: 0 },
446 { offset: 1, opacity: 0 }
447 ];
448 const SheetDefaults = {
449 WRAPPER_KEYFRAMES: [
450 { offset: 0, transform: 'translateY(0%)' },
451 { offset: 1, transform: 'translateY(100%)' }
452 ],
453 BACKDROP_KEYFRAMES: (backdropBreakpoint !== 0) ? customBackdrop : defaultBackdrop
454 };
455 const contentEl = baseEl.querySelector('ion-content');
456 const height = wrapperEl.clientHeight;
457 let currentBreakpoint = initialBreakpoint;
458 let offset = 0;
459 const wrapperAnimation = animation.childAnimations.find(ani => ani.id === 'wrapperAnimation');
460 const backdropAnimation = animation.childAnimations.find(ani => ani.id === 'backdropAnimation');
461 const maxBreakpoint = breakpoints[breakpoints.length - 1];
462 const enableBackdrop = () => {
463 baseEl.style.setProperty('pointer-events', 'auto');
464 backdropEl.style.setProperty('pointer-events', 'auto');
465 /**
466 * When the backdrop is enabled, elements such
467 * as inputs should not be focusable outside
468 * the sheet.
469 */
470 baseEl.classList.remove('ion-disable-focus-trap');
471 };
472 const disableBackdrop = () => {
473 baseEl.style.setProperty('pointer-events', 'none');
474 backdropEl.style.setProperty('pointer-events', 'none');
475 /**
476 * When the backdrop is enabled, elements such
477 * as inputs should not be focusable outside
478 * the sheet.
479 * Adding this class disables focus trapping
480 * for the sheet temporarily.
481 */
482 baseEl.classList.add('ion-disable-focus-trap');
483 };
484 /**
485 * After the entering animation completes,
486 * we need to set the animation to go from
487 * offset 0 to offset 1 so that users can
488 * swipe in any direction. We then set the
489 * animation offset to the current breakpoint
490 * so there is no flickering.
491 */
492 if (wrapperAnimation && backdropAnimation) {
493 wrapperAnimation.keyframes([...SheetDefaults.WRAPPER_KEYFRAMES]);
494 backdropAnimation.keyframes([...SheetDefaults.BACKDROP_KEYFRAMES]);
495 animation.progressStart(true, 1 - currentBreakpoint);
496 /**
497 * If backdrop is not enabled, then content
498 * behind modal should be clickable. To do this, we need
499 * to remove pointer-events from ion-modal as a whole.
500 * ion-backdrop and .modal-wrapper always have pointer-events: auto
501 * applied, so the modal content can still be interacted with.
502 */
503 const shouldEnableBackdrop = currentBreakpoint > backdropBreakpoint;
504 if (shouldEnableBackdrop) {
505 enableBackdrop();
506 }
507 else {
508 disableBackdrop();
509 }
510 }
511 if (contentEl && currentBreakpoint !== maxBreakpoint) {
512 contentEl.scrollY = false;
513 }
514 const canStart = (detail) => {
515 /**
516 * If the sheet is fully expanded and
517 * the user is swiping on the content,
518 * the gesture should not start to
519 * allow for scrolling on the content.
520 */
521 const content = detail.event.target.closest('ion-content');
522 if (currentBreakpoint === 1 && content) {
523 return false;
524 }
525 return true;
526 };
527 const onStart = () => {
528 /**
529 * If swiping on the content
530 * we should disable scrolling otherwise
531 * the sheet will expand and the content will scroll.
532 */
533 if (contentEl) {
534 contentEl.scrollY = false;
535 }
536 raf(() => {
537 /**
538 * Dismisses the open keyboard when the sheet drag gesture is started.
539 * Sets the focus onto the modal element.
540 */
541 baseEl.focus();
542 });
543 animation.progressStart(true, 1 - currentBreakpoint);
544 };
545 const onMove = (detail) => {
546 /**
547 * Given the change in gesture position on the Y axis,
548 * compute where the offset of the animation should be
549 * relative to where the user dragged.
550 */
551 const initialStep = 1 - currentBreakpoint;
552 offset = clamp(0.0001, initialStep + (detail.deltaY / height), 0.9999);
553 animation.progressStep(offset);
554 };
555 const onEnd = (detail) => {
556 /**
557 * When the gesture releases, we need to determine
558 * the closest breakpoint to snap to.
559 */
560 const velocity = detail.velocityY;
561 const threshold = (detail.deltaY + velocity * 100) / height;
562 const diff = currentBreakpoint - threshold;
563 const closest = breakpoints.reduce((a, b) => {
564 return Math.abs(b - diff) < Math.abs(a - diff) ? b : a;
565 });
566 const shouldRemainOpen = closest !== 0;
567 currentBreakpoint = 0;
568 /**
569 * Update the animation so that it plays from
570 * the last offset to the closest snap point.
571 */
572 if (wrapperAnimation && backdropAnimation) {
573 wrapperAnimation.keyframes([
574 { offset: 0, transform: `translateY(${offset * 100}%)` },
575 { offset: 1, transform: `translateY(${(1 - closest) * 100}%)` }
576 ]);
577 backdropAnimation.keyframes([
578 { offset: 0, opacity: `calc(var(--backdrop-opacity) * ${getBackdropValueForSheet(1 - offset, backdropBreakpoint)})` },
579 { offset: 1, opacity: `calc(var(--backdrop-opacity) * ${getBackdropValueForSheet(closest, backdropBreakpoint)})` }
580 ]);
581 animation.progressStep(0);
582 }
583 /**
584 * Gesture should remain disabled until the
585 * snapping animation completes.
586 */
587 gesture.enable(false);
588 animation
589 .onFinish(() => {
590 if (shouldRemainOpen) {
591 /**
592 * Once the snapping animation completes,
593 * we need to reset the animation to go
594 * from 0 to 1 so users can swipe in any direction.
595 * We then set the animation offset to the current
596 * breakpoint so that it starts at the snapped position.
597 */
598 if (wrapperAnimation && backdropAnimation) {
599 raf(() => {
600 wrapperAnimation.keyframes([...SheetDefaults.WRAPPER_KEYFRAMES]);
601 backdropAnimation.keyframes([...SheetDefaults.BACKDROP_KEYFRAMES]);
602 animation.progressStart(true, 1 - closest);
603 currentBreakpoint = closest;
604 onBreakpointChange(currentBreakpoint);
605 /**
606 * If the sheet is fully expanded, we can safely
607 * enable scrolling again.
608 */
609 if (contentEl && currentBreakpoint === breakpoints[breakpoints.length - 1]) {
610 contentEl.scrollY = true;
611 }
612 /**
613 * Backdrop should become enabled
614 * after the backdropBreakpoint value
615 */
616 const shouldEnableBackdrop = currentBreakpoint > backdropBreakpoint;
617 if (shouldEnableBackdrop) {
618 enableBackdrop();
619 }
620 else {
621 disableBackdrop();
622 }
623 gesture.enable(true);
624 });
625 }
626 else {
627 gesture.enable(true);
628 }
629 }
630 /**
631 * This must be a one time callback
632 * otherwise a new callback will
633 * be added every time onEnd runs.
634 */
635 }, { oneTimeCallback: true })
636 .progressEnd(1, 0, 500);
637 if (!shouldRemainOpen) {
638 onDismiss();
639 }
640 };
641 const gesture = createGesture({
642 el: wrapperEl,
643 gestureName: 'modalSheet',
644 gesturePriority: 40,
645 direction: 'y',
646 threshold: 10,
647 canStart,
648 onStart,
649 onMove,
650 onEnd
651 });
652 return gesture;
653};
654
655const modalIosCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px;--ion-safe-area-top:0px;--ion-safe-area-bottom:0px;--ion-safe-area-right:0px;--ion-safe-area-left:0px}}@media only screen and (min-width: 768px) and (min-height: 768px){:host{--width:600px;--height:600px}}.modal-handle{left:0px;right:0px;top:5px;border-radius:8px;margin-left:auto;margin-right:auto;position:absolute;width:36px;height:5px;-webkit-transform:translateZ(0);transform:translateZ(0);background:var(--ion-color-step-350, #c0c0be);z-index:11}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.modal-handle{margin-left:unset;margin-right:unset;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto}}:host(.modal-sheet){--height:calc(100% - (var(--ion-safe-area-top) + 10px))}:host(.modal-sheet) .modal-wrapper,:host(.modal-sheet) .modal-shadow{position:absolute;bottom:0}:host{--backdrop-opacity:var(--ion-backdrop-opacity, 0.4)}:host(.modal-card),:host(.modal-sheet){--border-radius:10px}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--border-radius:10px}}.modal-wrapper{-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0)}@media screen and (max-width: 767px){@supports (width: max(0px, 1px)){:host(.modal-card){--height:calc(100% - max(30px, var(--ion-safe-area-top)) - 10px)}}@supports not (width: max(0px, 1px)){:host(.modal-card){--height:calc(100% - 40px)}}:host(.modal-card) .modal-wrapper{border-top-left-radius:var(--border-radius);border-top-right-radius:var(--border-radius);border-bottom-right-radius:0;border-bottom-left-radius:0}:host-context([dir=rtl]):host(.modal-card) .modal-wrapper,:host-context([dir=rtl]).modal-card .modal-wrapper{border-top-left-radius:var(--border-radius);border-top-right-radius:var(--border-radius);border-bottom-right-radius:0;border-bottom-left-radius:0}:host(.modal-card){--backdrop-opacity:0;--width:100%;-ms-flex-align:end;align-items:flex-end}:host(.modal-card) .modal-shadow{display:none}:host(.modal-card) ion-backdrop{pointer-events:none}}@media screen and (min-width: 768px){:host(.modal-card){--width:calc(100% - 120px);--height:calc(100% - (120px + var(--ion-safe-area-top) + var(--ion-safe-area-bottom)));--max-width:720px;--max-height:1000px;--backdrop-opacity:0;--box-shadow:0px 0px 30px 10px rgba(0, 0, 0, 0.1);-webkit-transition:all 0.5s ease-in-out;transition:all 0.5s ease-in-out}:host(.modal-card) .modal-wrapper{-webkit-box-shadow:none;box-shadow:none}:host(.modal-card) .modal-shadow{-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow)}}:host(.modal-sheet) .modal-wrapper{border-top-left-radius:var(--border-radius);border-top-right-radius:var(--border-radius);border-bottom-right-radius:0;border-bottom-left-radius:0}:host-context([dir=rtl]):host(.modal-sheet) .modal-wrapper,:host-context([dir=rtl]).modal-sheet .modal-wrapper{border-top-left-radius:var(--border-radius);border-top-right-radius:var(--border-radius);border-bottom-right-radius:0;border-bottom-left-radius:0}";
656
657const modalMdCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px;--ion-safe-area-top:0px;--ion-safe-area-bottom:0px;--ion-safe-area-right:0px;--ion-safe-area-left:0px}}@media only screen and (min-width: 768px) and (min-height: 768px){:host{--width:600px;--height:600px}}.modal-handle{left:0px;right:0px;top:5px;border-radius:8px;margin-left:auto;margin-right:auto;position:absolute;width:36px;height:5px;-webkit-transform:translateZ(0);transform:translateZ(0);background:var(--ion-color-step-350, #c0c0be);z-index:11}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.modal-handle{margin-left:unset;margin-right:unset;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto}}:host(.modal-sheet){--height:calc(100% - (var(--ion-safe-area-top) + 10px))}:host(.modal-sheet) .modal-wrapper,:host(.modal-sheet) .modal-shadow{position:absolute;bottom:0}:host{--backdrop-opacity:var(--ion-backdrop-opacity, 0.32)}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--border-radius:2px;--box-shadow:0 28px 48px rgba(0, 0, 0, 0.4)}}.modal-wrapper{-webkit-transform:translate3d(0, 40px, 0);transform:translate3d(0, 40px, 0);opacity:0.01}";
658
659const Modal = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
660 constructor() {
661 super();
662 this.__registerHost();
663 this.__attachShadow();
664 this.didPresent = createEvent(this, "ionModalDidPresent", 7);
665 this.willPresent = createEvent(this, "ionModalWillPresent", 7);
666 this.willDismiss = createEvent(this, "ionModalWillDismiss", 7);
667 this.didDismiss = createEvent(this, "ionModalDidDismiss", 7);
668 this.didPresentShorthand = createEvent(this, "didPresent", 7);
669 this.willPresentShorthand = createEvent(this, "willPresent", 7);
670 this.willDismissShorthand = createEvent(this, "willDismiss", 7);
671 this.didDismissShorthand = createEvent(this, "didDismiss", 7);
672 this.modalIndex = modalIds++;
673 this.coreDelegate = CoreDelegate();
674 this.isSheetModal = false;
675 this.inline = false;
676 // Whether or not modal is being dismissed via gesture
677 this.gestureAnimationDismissing = false;
678 this.presented = false;
679 /** @internal */
680 this.hasController = false;
681 /**
682 * If `true`, the keyboard will be automatically dismissed when the overlay is presented.
683 */
684 this.keyboardClose = true;
685 /**
686 * A decimal value between 0 and 1 that indicates the
687 * point after which the backdrop will begin to fade in
688 * when using a sheet modal. Prior to this point, the
689 * backdrop will be hidden and the content underneath
690 * the sheet can be interacted with. This value is exclusive
691 * meaning the backdrop will become active after the value
692 * specified.
693 */
694 this.backdropBreakpoint = 0;
695 /**
696 * If `true`, the modal will be dismissed when the backdrop is clicked.
697 */
698 this.backdropDismiss = true;
699 /**
700 * If `true`, a backdrop will be displayed behind the modal.
701 */
702 this.showBackdrop = true;
703 /**
704 * If `true`, the modal will animate.
705 */
706 this.animated = true;
707 /**
708 * If `true`, the modal can be swiped to dismiss. Only applies in iOS mode.
709 */
710 this.swipeToClose = false;
711 /**
712 * If `true`, the modal will open. If `false`, the modal will close.
713 * Use this if you need finer grained control over presentation, otherwise
714 * just use the modalController or the `trigger` property.
715 * Note: `isOpen` will not automatically be set back to `false` when
716 * the modal dismisses. You will need to do that in your code.
717 */
718 this.isOpen = false;
719 this.configureTriggerInteraction = () => {
720 const { trigger, el, destroyTriggerInteraction } = this;
721 if (destroyTriggerInteraction) {
722 destroyTriggerInteraction();
723 }
724 const triggerEl = (trigger !== undefined) ? document.getElementById(trigger) : null;
725 if (!triggerEl) {
726 return;
727 }
728 const configureTriggerInteraction = (trigEl, modalEl) => {
729 const openModal = () => {
730 modalEl.present();
731 };
732 trigEl.addEventListener('click', openModal);
733 return () => {
734 trigEl.removeEventListener('click', openModal);
735 };
736 };
737 this.destroyTriggerInteraction = configureTriggerInteraction(triggerEl, el);
738 };
739 this.onBackdropTap = () => {
740 this.dismiss(undefined, BACKDROP);
741 };
742 this.onDismiss = (ev) => {
743 ev.stopPropagation();
744 ev.preventDefault();
745 this.dismiss();
746 };
747 this.onLifecycle = (modalEvent) => {
748 const el = this.usersElement;
749 const name = LIFECYCLE_MAP[modalEvent.type];
750 if (el && name) {
751 const ev = new CustomEvent(name, {
752 bubbles: false,
753 cancelable: false,
754 detail: modalEvent.detail
755 });
756 el.dispatchEvent(ev);
757 }
758 };
759 }
760 onIsOpenChange(newValue, oldValue) {
761 if (newValue === true && oldValue === false) {
762 this.present();
763 }
764 else if (newValue === false && oldValue === true) {
765 this.dismiss();
766 }
767 }
768 onTriggerChange() {
769 this.configureTriggerInteraction();
770 }
771 swipeToCloseChanged(enable) {
772 if (this.gesture) {
773 this.gesture.enable(enable);
774 }
775 else if (enable) {
776 this.initSwipeToClose();
777 }
778 }
779 connectedCallback() {
780 prepareOverlay(this.el);
781 }
782 componentWillLoad() {
783 const { breakpoints, initialBreakpoint } = this;
784 /**
785 * If user has custom ID set then we should
786 * not assign the default incrementing ID.
787 */
788 this.modalId = (this.el.hasAttribute('id')) ? this.el.getAttribute('id') : `ion-modal-${this.modalIndex}`;
789 this.isSheetModal = breakpoints !== undefined && initialBreakpoint !== undefined;
790 if (breakpoints !== undefined && initialBreakpoint !== undefined && !breakpoints.includes(initialBreakpoint)) {
791 console.warn('[Ionic Warning]: Your breakpoints array must include the initialBreakpoint value.');
792 }
793 }
794 componentDidLoad() {
795 /**
796 * If modal was rendered with isOpen="true"
797 * then we should open modal immediately.
798 */
799 if (this.isOpen === true) {
800 raf(() => this.present());
801 }
802 this.configureTriggerInteraction();
803 }
804 /**
805 * Determines whether or not an overlay
806 * is being used inline or via a controller/JS
807 * and returns the correct delegate.
808 * By default, subsequent calls to getDelegate
809 * will use a cached version of the delegate.
810 * This is useful for calling dismiss after
811 * present so that the correct delegate is given.
812 */
813 getDelegate(force = false) {
814 if (this.workingDelegate && !force) {
815 return {
816 delegate: this.workingDelegate,
817 inline: this.inline
818 };
819 }
820 /**
821 * If using overlay inline
822 * we potentially need to use the coreDelegate
823 * so that this works in vanilla JS apps.
824 * If a developer has presented this component
825 * via a controller, then we can assume
826 * the component is already in the
827 * correct place.
828 */
829 const parentEl = this.el.parentNode;
830 const inline = this.inline = parentEl !== null && !this.hasController;
831 const delegate = this.workingDelegate = (inline) ? this.delegate || this.coreDelegate : this.delegate;
832 return { inline, delegate };
833 }
834 /**
835 * Present the modal overlay after it has been created.
836 */
837 async present() {
838 if (this.presented) {
839 return;
840 }
841 /**
842 * When using an inline modal
843 * and dismissing a modal it is possible to
844 * quickly present the modal while it is
845 * dismissing. We need to await any current
846 * transition to allow the dismiss to finish
847 * before presenting again.
848 */
849 if (this.currentTransition !== undefined) {
850 await this.currentTransition;
851 }
852 const data = Object.assign(Object.assign({}, this.componentProps), { modal: this.el });
853 const { inline, delegate } = this.getDelegate(true);
854 this.usersElement = await attachComponent(delegate, this.el, this.component, ['ion-page'], data, inline);
855 await deepReady(this.usersElement);
856 writeTask(() => this.el.classList.add('show-modal'));
857 this.currentTransition = present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation, { presentingEl: this.presentingElement, currentBreakpoint: this.initialBreakpoint, backdropBreakpoint: this.backdropBreakpoint });
858 await this.currentTransition;
859 if (this.isSheetModal) {
860 this.initSheetGesture();
861 }
862 else if (this.swipeToClose) {
863 this.initSwipeToClose();
864 }
865 /* tslint:disable-next-line */
866 if (typeof window !== 'undefined') {
867 this.keyboardOpenCallback = () => {
868 if (this.gesture) {
869 /**
870 * When the native keyboard is opened and the webview
871 * is resized, the gesture implementation will become unresponsive
872 * and enter a free-scroll mode.
873 *
874 * When the keyboard is opened, we disable the gesture for
875 * a single frame and re-enable once the contents have repositioned
876 * from the keyboard placement.
877 */
878 this.gesture.enable(false);
879 raf(() => {
880 if (this.gesture) {
881 this.gesture.enable(true);
882 }
883 });
884 }
885 };
886 window.addEventListener(KEYBOARD_DID_OPEN, this.keyboardOpenCallback);
887 }
888 this.currentTransition = undefined;
889 }
890 initSwipeToClose() {
891 if (getIonMode(this) !== 'ios') {
892 return;
893 }
894 // All of the elements needed for the swipe gesture
895 // should be in the DOM and referenced by now, except
896 // for the presenting el
897 const animationBuilder = this.leaveAnimation || config.get('modalLeave', iosLeaveAnimation);
898 const ani = this.animation = animationBuilder(this.el, { presentingEl: this.presentingElement });
899 this.gesture = createSwipeToCloseGesture(this.el, ani, () => {
900 /**
901 * While the gesture animation is finishing
902 * it is possible for a user to tap the backdrop.
903 * This would result in the dismiss animation
904 * being played again. Typically this is avoided
905 * by setting `presented = false` on the overlay
906 * component; however, we cannot do that here as
907 * that would prevent the element from being
908 * removed from the DOM.
909 */
910 this.gestureAnimationDismissing = true;
911 this.animation.onFinish(async () => {
912 await this.dismiss(undefined, 'gesture');
913 this.gestureAnimationDismissing = false;
914 });
915 });
916 this.gesture.enable(true);
917 }
918 initSheetGesture() {
919 var _a;
920 const { wrapperEl, initialBreakpoint, backdropBreakpoint } = this;
921 if (!wrapperEl || initialBreakpoint === undefined) {
922 return;
923 }
924 const animationBuilder = this.enterAnimation || config.get('modalEnter', iosEnterAnimation);
925 const ani = this.animation = animationBuilder(this.el, { presentingEl: this.presentingElement, currentBreakpoint: initialBreakpoint, backdropBreakpoint });
926 ani.progressStart(true, 1);
927 const sortedBreakpoints = ((_a = this.breakpoints) === null || _a === void 0 ? void 0 : _a.sort((a, b) => a - b)) || [];
928 this.gesture = createSheetGesture(this.el, this.backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, ani, sortedBreakpoints, () => {
929 /**
930 * While the gesture animation is finishing
931 * it is possible for a user to tap the backdrop.
932 * This would result in the dismiss animation
933 * being played again. Typically this is avoided
934 * by setting `presented = false` on the overlay
935 * component; however, we cannot do that here as
936 * that would prevent the element from being
937 * removed from the DOM.
938 */
939 this.gestureAnimationDismissing = true;
940 this.animation.onFinish(async () => {
941 await this.dismiss(undefined, 'gesture');
942 this.gestureAnimationDismissing = false;
943 });
944 }, (breakpoint) => {
945 this.currentBreakpoint = breakpoint;
946 });
947 this.gesture.enable(true);
948 }
949 /**
950 * Dismiss the modal overlay after it has been presented.
951 *
952 * @param data Any data to emit in the dismiss events.
953 * @param role The role of the element that is dismissing the modal. For example, 'cancel' or 'backdrop'.
954 */
955 async dismiss(data, role) {
956 if (this.gestureAnimationDismissing && role !== 'gesture') {
957 return false;
958 }
959 /* tslint:disable-next-line */
960 if (typeof window !== 'undefined' && this.keyboardOpenCallback) {
961 window.removeEventListener(KEYBOARD_DID_OPEN, this.keyboardOpenCallback);
962 }
963 /**
964 * When using an inline modal
965 * and presenting a modal it is possible to
966 * quickly dismiss the modal while it is
967 * presenting. We need to await any current
968 * transition to allow the present to finish
969 * before dismissing again.
970 */
971 if (this.currentTransition !== undefined) {
972 await this.currentTransition;
973 }
974 const enteringAnimation = activeAnimations.get(this) || [];
975 this.currentTransition = dismiss(this, data, role, 'modalLeave', iosLeaveAnimation, mdLeaveAnimation, { presentingEl: this.presentingElement, currentBreakpoint: this.currentBreakpoint || this.initialBreakpoint, backdropBreakpoint: this.backdropBreakpoint });
976 const dismissed = await this.currentTransition;
977 if (dismissed) {
978 const { delegate } = this.getDelegate();
979 await detachComponent(delegate, this.usersElement);
980 writeTask(() => this.el.classList.remove('show-modal'));
981 if (this.animation) {
982 this.animation.destroy();
983 }
984 if (this.gesture) {
985 this.gesture.destroy();
986 }
987 enteringAnimation.forEach(ani => ani.destroy());
988 }
989 this.currentTransition = undefined;
990 this.animation = undefined;
991 return dismissed;
992 }
993 /**
994 * Returns a promise that resolves when the modal did dismiss.
995 */
996 onDidDismiss() {
997 return eventMethod(this.el, 'ionModalDidDismiss');
998 }
999 /**
1000 * Returns a promise that resolves when the modal will dismiss.
1001 */
1002 onWillDismiss() {
1003 return eventMethod(this.el, 'ionModalWillDismiss');
1004 }
1005 render() {
1006 const { handle, isSheetModal, presentingElement, htmlAttributes } = this;
1007 const showHandle = handle !== false && isSheetModal;
1008 const mode = getIonMode(this);
1009 const { modalId } = this;
1010 const isCardModal = presentingElement !== undefined && mode === 'ios';
1011 return (h(Host, Object.assign({ "no-router": true, "aria-modal": "true", tabindex: "-1" }, htmlAttributes, { style: {
1012 zIndex: `${20000 + this.overlayIndex}`,
1013 }, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, 'overlay-hidden': true }, getClassMap(this.cssClass)), id: modalId, onIonBackdropTap: this.onBackdropTap, onIonDismiss: this.onDismiss, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle }), h("ion-backdrop", { ref: el => this.backdropEl = el, visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { class: "modal-shadow" }), h("div", { role: "dialog", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: el => this.wrapperEl = el }, showHandle && h("div", { class: "modal-handle", part: "handle" }), h("slot", null))));
1014 }
1015 get el() { return this; }
1016 static get watchers() { return {
1017 "isOpen": ["onIsOpenChange"],
1018 "trigger": ["onTriggerChange"],
1019 "swipeToClose": ["swipeToCloseChanged"]
1020 }; }
1021 static get style() { return {
1022 ios: modalIosCss,
1023 md: modalMdCss
1024 }; }
1025}, [33, "ion-modal", {
1026 "hasController": [4, "has-controller"],
1027 "overlayIndex": [2, "overlay-index"],
1028 "delegate": [16],
1029 "keyboardClose": [4, "keyboard-close"],
1030 "enterAnimation": [16],
1031 "leaveAnimation": [16],
1032 "breakpoints": [16],
1033 "initialBreakpoint": [2, "initial-breakpoint"],
1034 "backdropBreakpoint": [2, "backdrop-breakpoint"],
1035 "handle": [4],
1036 "component": [1],
1037 "componentProps": [16],
1038 "cssClass": [1, "css-class"],
1039 "backdropDismiss": [4, "backdrop-dismiss"],
1040 "showBackdrop": [4, "show-backdrop"],
1041 "animated": [4],
1042 "swipeToClose": [4, "swipe-to-close"],
1043 "presentingElement": [16],
1044 "htmlAttributes": [16],
1045 "isOpen": [4, "is-open"],
1046 "trigger": [1],
1047 "presented": [32],
1048 "present": [64],
1049 "dismiss": [64],
1050 "onDidDismiss": [64],
1051 "onWillDismiss": [64]
1052 }]);
1053const LIFECYCLE_MAP = {
1054 'ionModalDidPresent': 'ionViewDidEnter',
1055 'ionModalWillPresent': 'ionViewWillEnter',
1056 'ionModalWillDismiss': 'ionViewWillLeave',
1057 'ionModalDidDismiss': 'ionViewDidLeave',
1058};
1059let modalIds = 0;
1060function defineCustomElement$1() {
1061 if (typeof customElements === "undefined") {
1062 return;
1063 }
1064 const components = ["ion-modal", "ion-backdrop"];
1065 components.forEach(tagName => { switch (tagName) {
1066 case "ion-modal":
1067 if (!customElements.get(tagName)) {
1068 customElements.define(tagName, Modal);
1069 }
1070 break;
1071 case "ion-backdrop":
1072 if (!customElements.get(tagName)) {
1073 defineCustomElement$2();
1074 }
1075 break;
1076 } });
1077}
1078
1079const IonModal = Modal;
1080const defineCustomElement = defineCustomElement$1;
1081
1082export { IonModal, defineCustomElement };