@ionic/core 9.0.1-dev.11787248963.10a00c73 → 9.0.1-dev.11787589191.1e183b55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/components/index.js +1 -1
  2. package/components/ion-action-sheet.js +1 -1
  3. package/components/ion-alert.js +1 -1
  4. package/components/ion-datetime.js +1 -1
  5. package/components/ion-item-sliding.js +1 -1
  6. package/components/ion-loading.js +1 -1
  7. package/components/ion-menu.js +1 -1
  8. package/components/ion-modal.js +1 -1
  9. package/components/ion-popover.js +1 -1
  10. package/components/ion-segment-button.js +1 -1
  11. package/components/ion-select-modal.js +1 -1
  12. package/components/ion-select-popover.js +1 -1
  13. package/components/ion-select.js +1 -1
  14. package/components/ion-toast.js +1 -1
  15. package/components/p-BPnXVGaS.js +4 -0
  16. package/components/p-BQAiulS1.js +4 -0
  17. package/components/p-Bh2ta0iG.js +4 -0
  18. package/components/{p-CaiZOhfC.js → p-BnUOVmKh.js} +1 -1
  19. package/components/{p-Bnc0m4SW.js → p-D1OCo42s.js} +1 -1
  20. package/components/p-DD57rSP_.js +4 -0
  21. package/components/p-DnXLaaf7.js +4 -0
  22. package/dist/cjs/index.cjs.js +1 -1
  23. package/dist/cjs/ion-action-sheet.cjs.entry.js +35 -20
  24. package/dist/cjs/ion-alert.cjs.entry.js +20 -12
  25. package/dist/cjs/ion-datetime.cjs.entry.js +1 -1
  26. package/dist/cjs/ion-item-option_3.cjs.entry.js +11 -9
  27. package/dist/cjs/ion-loading.cjs.entry.js +7 -3
  28. package/dist/cjs/ion-menu_3.cjs.entry.js +1 -1
  29. package/dist/cjs/ion-modal.cjs.entry.js +75 -22
  30. package/dist/cjs/ion-popover.cjs.entry.js +13 -3
  31. package/dist/cjs/ion-segment_2.cjs.entry.js +7 -11
  32. package/dist/cjs/ion-select-modal.cjs.entry.js +1 -1
  33. package/dist/cjs/ion-select_3.cjs.entry.js +1 -1
  34. package/dist/cjs/ion-toast.cjs.entry.js +1 -1
  35. package/dist/cjs/{overlays-Bg0auTQa.js → overlays-B5JeC8OQ.js} +52 -29
  36. package/dist/collection/components/action-sheet/action-sheet.js +35 -20
  37. package/dist/collection/components/alert/alert.js +20 -12
  38. package/dist/collection/components/item-sliding/item-sliding.js +12 -10
  39. package/dist/collection/components/loading/loading.js +7 -3
  40. package/dist/collection/components/modal/modal.js +75 -22
  41. package/dist/collection/components/popover/popover.js +13 -3
  42. package/dist/collection/components/segment-button/segment-button.js +7 -11
  43. package/dist/collection/utils/overlays.js +51 -29
  44. package/dist/docs.json +1 -1
  45. package/dist/esm/index.js +1 -1
  46. package/dist/esm/ion-action-sheet.entry.js +35 -20
  47. package/dist/esm/ion-alert.entry.js +20 -12
  48. package/dist/esm/ion-datetime.entry.js +1 -1
  49. package/dist/esm/ion-item-option_3.entry.js +12 -10
  50. package/dist/esm/ion-loading.entry.js +7 -3
  51. package/dist/esm/ion-menu_3.entry.js +1 -1
  52. package/dist/esm/ion-modal.entry.js +75 -22
  53. package/dist/esm/ion-popover.entry.js +13 -3
  54. package/dist/esm/ion-segment_2.entry.js +7 -11
  55. package/dist/esm/ion-select-modal.entry.js +1 -1
  56. package/dist/esm/ion-select_3.entry.js +1 -1
  57. package/dist/esm/ion-toast.entry.js +1 -1
  58. package/dist/esm/{overlays-BpnIFlXI.js → overlays-CefdMZgF.js} +52 -30
  59. package/dist/ionic/index.esm.js +1 -1
  60. package/dist/ionic/ionic.esm.js +1 -1
  61. package/dist/ionic/p-36abc1ee.entry.js +4 -0
  62. package/dist/ionic/{p-873a315a.entry.js → p-408973f4.entry.js} +1 -1
  63. package/dist/ionic/{p-4437015c.entry.js → p-46a938a9.entry.js} +1 -1
  64. package/dist/ionic/p-47626333.entry.js +4 -0
  65. package/dist/ionic/p-8f464a8f.entry.js +4 -0
  66. package/dist/ionic/p-9455207b.entry.js +4 -0
  67. package/dist/ionic/p-DLLCmV-y.js +4 -0
  68. package/dist/ionic/{p-05800a02.entry.js → p-a2fa2de2.entry.js} +1 -1
  69. package/dist/ionic/p-a53b0908.entry.js +4 -0
  70. package/dist/ionic/{p-75887ee0.entry.js → p-b875a59e.entry.js} +1 -1
  71. package/dist/ionic/p-f3b671aa.entry.js +4 -0
  72. package/dist/ionic/p-f521b13c.entry.js +4 -0
  73. package/dist/ionic/{p-49b9d405.entry.js → p-f8713b2c.entry.js} +1 -1
  74. package/dist/types/components/action-sheet/action-sheet.d.ts +10 -0
  75. package/dist/types/components/alert/alert.d.ts +7 -0
  76. package/dist/types/components/modal/modal.d.ts +8 -0
  77. package/dist/types/utils/overlays.d.ts +9 -0
  78. package/hydrate/index.js +214 -104
  79. package/hydrate/index.mjs +214 -104
  80. package/package.json +1 -1
  81. package/components/p-Bg4OwDwb.js +0 -4
  82. package/components/p-CQAjyETU.js +0 -4
  83. package/components/p-DqAI6tg7.js +0 -4
  84. package/components/p-DrehWDfv.js +0 -4
  85. package/components/p-eFI3mtEX.js +0 -4
  86. package/dist/collection/utils/test/late-props/late-props.js +0 -69
  87. package/dist/ionic/p-34b9379b.entry.js +0 -4
  88. package/dist/ionic/p-48c859fe.entry.js +0 -4
  89. package/dist/ionic/p-5b906fd6.entry.js +0 -4
  90. package/dist/ionic/p-68507e70.entry.js +0 -4
  91. package/dist/ionic/p-886d9e66.entry.js +0 -4
  92. package/dist/ionic/p-DdhHqKj-.js +0 -4
  93. package/dist/ionic/p-b7a11b58.entry.js +0 -4
  94. package/dist/ionic/p-f7dd1ed9.entry.js +0 -4
@@ -21,6 +21,15 @@ export const activeAnimations = new WeakMap();
21
21
  const isBackdropAlwaysBlocking = (el) => {
22
22
  return el.showBackdrop !== false && !((el.backdropBreakpoint ?? 0) > 0);
23
23
  };
24
+ /**
25
+ * Whether the overlay takes the app root out of the accessibility tree and
26
+ * blocks body scroll while presented. Toasts never do, modal and popover can
27
+ * opt out with `focusTrap={false}`, and a backdrop that does not block
28
+ * (`showBackdrop={false}`, or a `backdropBreakpoint` above 0) is excluded.
29
+ */
30
+ const locksAppRoot = (el) => {
31
+ return el.tagName !== 'ION-TOAST' && el.focusTrap !== false && isBackdropAlwaysBlocking(el);
32
+ };
24
33
  const createController = (tagName) => {
25
34
  return {
26
35
  create(options) {
@@ -391,6 +400,13 @@ export const getPresentedOverlay = (doc, overlayTag, id) => {
391
400
  // Otherwise, return the last overlay with the given id
392
401
  return (id === undefined ? overlays : overlays.filter((o) => o.id === id)).slice(-1)[0];
393
402
  };
403
+ /**
404
+ * The element an app nests its views under. Overlays hide this rather than the
405
+ * whole root, so the overlay itself (a sibling) stays reachable.
406
+ */
407
+ const getViewContainer = () => {
408
+ return getAppRoot(document).querySelector('ion-router-outlet, #ion-view-container-root');
409
+ };
394
410
  /**
395
411
  * When an overlay is presented, the main
396
412
  * focus is the overlay not the page content.
@@ -414,8 +430,7 @@ export const getPresentedOverlay = (doc, overlayTag, id) => {
414
430
  * for main content.
415
431
  */
416
432
  export const setRootAriaHidden = (hidden = false) => {
417
- const root = getAppRoot(document);
418
- const viewContainer = root.querySelector('ion-router-outlet, #ion-view-container-root');
433
+ const viewContainer = getViewContainer();
419
434
  if (!viewContainer) {
420
435
  return;
421
436
  }
@@ -440,15 +455,40 @@ export const cleanupRootFocusTrapAccessibility = () => {
440
455
  return;
441
456
  }
442
457
  const remainingOverlays = getPresentedOverlays(document);
443
- const hasRemainingLocking = remainingOverlays.some((o) => {
444
- const el = o;
445
- return el.tagName !== 'ION-TOAST' && el.focusTrap !== false && isBackdropAlwaysBlocking(el);
446
- });
458
+ const hasRemainingLocking = remainingOverlays.some((o) => locksAppRoot(o));
447
459
  if (!hasRemainingLocking) {
448
460
  setRootAriaHidden(false);
449
461
  document.body.classList.remove(BACKDROP_NO_SCROLL);
450
462
  }
451
463
  };
464
+ /**
465
+ * Shared by `present()` and the restore below, which have to stay in lockstep.
466
+ */
467
+ const applyRootLock = (el) => {
468
+ // Hiding the container the overlay now sits in would hide the overlay too.
469
+ if (!getViewContainer()?.contains(el)) {
470
+ setRootAriaHidden(true);
471
+ }
472
+ document.body.classList.add(BACKDROP_NO_SCROLL);
473
+ };
474
+ /**
475
+ * Re-applies the root lock that `cleanupRootFocusTrapAccessibility()` released.
476
+ * Call from `connectedCallback` when the overlay is still presented.
477
+ *
478
+ * A synchronous move keeps the overlay connected, so the lock survives. A
479
+ * detach with a re-insert in a later task releases it, which is the shape a
480
+ * framework produces when it takes a subtree out and puts it back.
481
+ */
482
+ export const restoreRootFocusTrapAccessibility = (overlayEl) => {
483
+ if (typeof document === 'undefined') {
484
+ return;
485
+ }
486
+ const el = overlayEl;
487
+ if (!locksAppRoot(el)) {
488
+ return;
489
+ }
490
+ applyRootLock(el);
491
+ };
452
492
  export const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts) => {
453
493
  if (overlay.presented) {
454
494
  return;
@@ -465,15 +505,7 @@ export const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation
465
505
  restoreElementFocus(overlay.el);
466
506
  }
467
507
  /**
468
- * Due to accessibility guidelines, toasts do not have
469
- * focus traps.
470
- *
471
- * All other overlays should have focus traps to prevent
472
- * the keyboard focus from leaving the overlay unless
473
- * developers explicitly opt out (for example, sheet
474
- * modals that should permit background interaction).
475
- *
476
- * Note: Some apps move inline overlays to a specific container
508
+ * Some apps move inline overlays to a specific container
477
509
  * during the willPresent lifecycle (e.g., React portals via
478
510
  * onWillPresent). Defer applying aria-hidden/inert to the app
479
511
  * root until after willPresent so we can detect where the
@@ -482,18 +514,11 @@ export const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation
482
514
  * to avoid disabling the overlay.
483
515
  */
484
516
  const overlayEl = overlay.el;
485
- const shouldTrapFocus = overlayEl.tagName !== 'ION-TOAST' && overlayEl.focusTrap !== false;
486
- const shouldLockRoot = shouldTrapFocus && isBackdropAlwaysBlocking(overlayEl);
517
+ const shouldLockRoot = locksAppRoot(overlayEl);
487
518
  overlay.presented = true;
488
519
  overlay.willPresent.emit();
489
520
  if (shouldLockRoot) {
490
- const root = getAppRoot(document);
491
- const viewContainer = root.querySelector('ion-router-outlet, #ion-view-container-root');
492
- const overlayInsideViewContainer = viewContainer ? viewContainer.contains(overlayEl) : false;
493
- if (!overlayInsideViewContainer) {
494
- setRootAriaHidden(true);
495
- }
496
- document.body.classList.add(BACKDROP_NO_SCROLL);
521
+ applyRootLock(overlayEl);
497
522
  }
498
523
  overlay.willPresentShorthand?.emit();
499
524
  const mode = getIonMode(overlay);
@@ -619,12 +644,9 @@ export const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLe
619
644
  * from the root element when the last focus-trapping overlay
620
645
  * is dismissed.
621
646
  */
622
- const overlaysLockingRoot = presentedOverlays.filter((o) => {
623
- const el = o;
624
- return el.tagName !== 'ION-TOAST' && el.focusTrap !== false && isBackdropAlwaysBlocking(el);
625
- });
647
+ const overlaysLockingRoot = presentedOverlays.filter((o) => locksAppRoot(o));
626
648
  const overlayEl = overlay.el;
627
- const locksRoot = overlayEl.tagName !== 'ION-TOAST' && overlayEl.focusTrap !== false && isBackdropAlwaysBlocking(overlayEl);
649
+ const locksRoot = locksAppRoot(overlayEl);
628
650
  /**
629
651
  * If this is the last visible overlay that is trapping focus
630
652
  * then we want to re-add the root to the accessibility tree.
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-08-20T18:04:41",
2
+ "timestamp": "2026-08-24T16:35:09",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.43.5",
package/dist/esm/index.js CHANGED
@@ -14,7 +14,7 @@ export { I as IonicSafeString } from './index-elneMH8y.js';
14
14
  export { g as getMode, s as setupConfig } from './config-DWCzVL3Y.js';
15
15
  export { o as openURL } from './theme-byZM6qHV.js';
16
16
  export { m as menuController } from './index-C5ZdL0qp.js';
17
- export { b as actionSheetController, a as alertController, l as loadingController, m as modalController, p as popoverController, t as toastController } from './overlays-BpnIFlXI.js';
17
+ export { b as actionSheetController, a as alertController, l as loadingController, m as modalController, p as popoverController, t as toastController } from './overlays-CefdMZgF.js';
18
18
  import './index-ZjP4CjeZ.js';
19
19
  import './gesture-controller-B_gJaBk0.js';
20
20
  import './dir-Dojwmvde.js';
@@ -5,7 +5,7 @@ import { r as registerInstance, c as createEvent, a as readTask, h, d as Host, g
5
5
  import { c as createButtonActiveGesture } from './button-active-ChA4D-ml.js';
6
6
  import { r as raf } from './helpers-BIgoInJU.js';
7
7
  import { c as createLockController } from './lock-controller-B-hirT0v.js';
8
- import { c as createDelegateController, d as createTriggerController, B as BACKDROP, i as isCancel, e as present, f as dismiss, g as eventMethod, s as safeCall, h as prepareOverlay, j as cleanupRootFocusTrapAccessibility, k as setOverlayId } from './overlays-BpnIFlXI.js';
8
+ import { c as createDelegateController, d as createTriggerController, B as BACKDROP, i as isCancel, e as present, f as dismiss, g as eventMethod, s as safeCall, h as prepareOverlay, r as restoreRootFocusTrapAccessibility, j as cleanupRootFocusTrapAccessibility, k as setOverlayId } from './overlays-CefdMZgF.js';
9
9
  import { r as renderOptionLabel } from './select-option-render-lIuu64EV.js';
10
10
  import { g as getClassMap } from './theme-byZM6qHV.js';
11
11
  import { b as getIonMode } from './ionic-global-lrowsHfi.js';
@@ -378,6 +378,13 @@ const ActionSheet = class {
378
378
  connectedCallback() {
379
379
  prepareOverlay(this.el);
380
380
  this.triggerChanged();
381
+ // `componentDidLoad` only fires once per instance, so a reconnect has to
382
+ // rebuild the gesture its disconnect destroyed.
383
+ this.setupButtonActiveGesture();
384
+ // Re-apply the root lock if moved without dismiss() being called
385
+ if (this.presented) {
386
+ restoreRootFocusTrapAccessibility(this.el);
387
+ }
381
388
  }
382
389
  disconnectedCallback() {
383
390
  if (this.gesture) {
@@ -397,24 +404,32 @@ const ActionSheet = class {
397
404
  // Initialize activeRadioId for radio buttons
398
405
  this.buttonsChanged();
399
406
  }
400
- componentDidLoad() {
401
- /**
402
- * Only create gesture if:
403
- * 1. A gesture does not already exist
404
- * 2. App is running in iOS mode
405
- * 3. A wrapper ref exists
406
- * 4. A group ref exists
407
- */
407
+ /**
408
+ * Only create gesture if:
409
+ * 1. A gesture does not already exist
410
+ * 2. App is running in iOS mode
411
+ * 3. A wrapper ref exists
412
+ * 4. A group ref exists
413
+ * 5. The host is still connected, since a reconnect can schedule this and
414
+ * disconnect again before the task runs
415
+ */
416
+ setupButtonActiveGesture() {
408
417
  const { groupEl, wrapperEl } = this;
409
- if (!this.gesture && getIonMode(this) === 'ios' && wrapperEl && groupEl) {
410
- readTask(() => {
411
- const isScrollable = groupEl.scrollHeight > groupEl.clientHeight;
412
- if (!isScrollable) {
413
- this.gesture = createButtonActiveGesture(wrapperEl, (refEl) => refEl.classList.contains('action-sheet-button'));
414
- this.gesture.enable(true);
415
- }
416
- });
418
+ if (getIonMode(this) !== 'ios' || !wrapperEl || !groupEl) {
419
+ return;
417
420
  }
421
+ readTask(() => {
422
+ // Two calls before the first flushes would otherwise both create a
423
+ // gesture, orphaning the first with its listeners still bound.
424
+ if (this.gesture || !this.el.isConnected || groupEl.scrollHeight > groupEl.clientHeight) {
425
+ return;
426
+ }
427
+ this.gesture = createButtonActiveGesture(wrapperEl, (refEl) => refEl.classList.contains('action-sheet-button'));
428
+ this.gesture.enable(true);
429
+ });
430
+ }
431
+ componentDidLoad() {
432
+ this.setupButtonActiveGesture();
418
433
  /**
419
434
  * If action sheet was rendered with isOpen="true"
420
435
  * then we should open action sheet immediately.
@@ -507,17 +522,17 @@ const ActionSheet = class {
507
522
  const cancelButton = allButtons.find((b) => b.role === 'cancel');
508
523
  const buttons = allButtons.filter((b) => b.role !== 'cancel');
509
524
  const headerID = `action-sheet-${overlayIndex}-header`;
510
- return (h(Host, { key: '7685831da9a78b73473246a2cea95cefa79a53c3', role: "dialog", "aria-modal": "true", "aria-labelledby": header !== undefined ? headerID : null, tabindex: "-1", ...htmlAttributes, style: {
525
+ return (h(Host, { key: '326d4af08e832e10e1882fbbf67dba3221095865', role: "dialog", "aria-modal": "true", "aria-labelledby": header !== undefined ? headerID : null, tabindex: "-1", ...htmlAttributes, style: {
511
526
  zIndex: `${20000 + this.overlayIndex}`,
512
527
  }, class: {
513
528
  [mode]: true,
514
529
  ...getClassMap(this.cssClass),
515
530
  'overlay-hidden': true,
516
531
  'action-sheet-translucent': this.translucent,
517
- }, onIonActionSheetWillDismiss: this.dispatchCancelHandler, onIonBackdropTap: this.onBackdropTap }, h("ion-backdrop", { key: 'c70f00e401cac99b89412d1adb867f35bc855d57', tappable: this.backdropDismiss }), h("div", { key: '3332893ce3098f1435875480b1269b2821d41660', tabindex: "0", "aria-hidden": "true" }), h("div", { key: 'eb406b0a9e303d6f94c5c7aa99c6f4c089bfbd41', class: "action-sheet-wrapper ion-overlay-wrapper", ref: (el) => (this.wrapperEl = el) }, h("div", { key: '92ec855379f10e1e0bfce6ff68b45d3cda0c137c', class: "action-sheet-container" }, h("div", { key: 'bc88a396d75396f574961471bf7e6c4edb513353', class: "action-sheet-group", ref: (el) => (this.groupEl = el), role: hasRadioButtons ? 'radiogroup' : undefined }, header !== undefined && (h("div", { key: '33329e0193818888bdcaa443ff5ea301802e0787', id: headerID, class: {
532
+ }, onIonActionSheetWillDismiss: this.dispatchCancelHandler, onIonBackdropTap: this.onBackdropTap }, h("ion-backdrop", { key: '8cb6a0d763a60f61f563a1b7d572ad5e9afd6e40', tappable: this.backdropDismiss }), h("div", { key: 'f8b8da0f52ae674a5e313632ee3d049bed3f813f', tabindex: "0", "aria-hidden": "true" }), h("div", { key: '53cf0d1b01a2cda23c27fc8b96edaccf892e61b3', class: "action-sheet-wrapper ion-overlay-wrapper", ref: (el) => (this.wrapperEl = el) }, h("div", { key: '6df261ff946c3b4496535df04cc70e2cfa3cc2da', class: "action-sheet-container" }, h("div", { key: '6f6f2846d19baa738651b990d8613aa0ecac9479', class: "action-sheet-group", ref: (el) => (this.groupEl = el), role: hasRadioButtons ? 'radiogroup' : undefined }, header !== undefined && (h("div", { key: '3f36df8eaaedb5e61a41bbf44134f25f263d1e7e', id: headerID, class: {
518
533
  'action-sheet-title': true,
519
534
  'action-sheet-has-sub-title': this.subHeader !== undefined,
520
- } }, header, this.subHeader && h("div", { key: '92ac5a9217a12b7417f7aca9c4fdb7bf6b051364', class: "action-sheet-sub-title" }, this.subHeader))), this.renderActionSheetButtons(buttons)), cancelButton && (h("div", { key: '020463b830fa48fc3ae647ea64f2aaa4d0969305', class: "action-sheet-group action-sheet-group-cancel" }, h("button", { key: 'cefa9c70a2233f6652a81b1a2eae6e717712144d', ...cancelButton.htmlAttributes, type: "button", class: buttonClass(cancelButton), onClick: () => this.buttonClick(cancelButton) }, h("span", { key: '56d7e2f8bfb3644e4476895164d334445fda9b2f', class: "action-sheet-button-inner" }, cancelButton.icon && (h("ion-icon", { key: '6a4a49254ec5cd96f4e0dce9447f90d8cac81913', icon: cancelButton.icon, "aria-hidden": "true", lazy: false, class: "action-sheet-icon" })), cancelButton.text), mode === 'md' && h("ion-ripple-effect", { key: '7d3c6e8d70b0922ea0f75520856285ce1005c891' })))))), h("div", { key: '958fc43e603c6a7f5d1e649d3326fce0f163b5d0', tabindex: "0", "aria-hidden": "true" })));
535
+ } }, header, this.subHeader && h("div", { key: 'a6b2bf51123eaae4ed873e65c00c426e9c511ac0', class: "action-sheet-sub-title" }, this.subHeader))), this.renderActionSheetButtons(buttons)), cancelButton && (h("div", { key: '4dd96553327003b899bc03a815a06a7cce35db29', class: "action-sheet-group action-sheet-group-cancel" }, h("button", { key: 'a1928040a3d20f2e50230b7d6003467d2916f5b4', ...cancelButton.htmlAttributes, type: "button", class: buttonClass(cancelButton), onClick: () => this.buttonClick(cancelButton) }, h("span", { key: '2fa9d0e4072f1fd55f08048966495a627a14ef8f', class: "action-sheet-button-inner" }, cancelButton.icon && (h("ion-icon", { key: 'c2eec9967cb9f0b75d4428bb548674199089203c', icon: cancelButton.icon, "aria-hidden": "true", lazy: false, class: "action-sheet-icon" })), cancelButton.text), mode === 'md' && h("ion-ripple-effect", { key: '09e71f28d77ae16481b832863f49b3f7d7dd76f9' })))))), h("div", { key: '386fbe5ca2a88e9b52bd3b9d8f3daddbc630e6f6', tabindex: "0", "aria-hidden": "true" })));
521
536
  }
522
537
  get el() { return getElement(this); }
523
538
  static get watchers() { return {
@@ -7,7 +7,7 @@ import { c as createButtonActiveGesture } from './button-active-ChA4D-ml.js';
7
7
  import { r as raf } from './helpers-BIgoInJU.js';
8
8
  import { c as createLockController } from './lock-controller-B-hirT0v.js';
9
9
  import { g as getOverlayLabelJustify, a as getOverlayLabelPlacement } from './overlay-control-label-BSQPZ79H.js';
10
- import { c as createDelegateController, d as createTriggerController, B as BACKDROP, i as isCancel, h as prepareOverlay, k as setOverlayId, j as cleanupRootFocusTrapAccessibility, e as present, f as dismiss, g as eventMethod, s as safeCall } from './overlays-BpnIFlXI.js';
10
+ import { c as createDelegateController, d as createTriggerController, B as BACKDROP, i as isCancel, h as prepareOverlay, r as restoreRootFocusTrapAccessibility, k as setOverlayId, j as cleanupRootFocusTrapAccessibility, e as present, f as dismiss, g as eventMethod, s as safeCall } from './overlays-CefdMZgF.js';
11
11
  import { s as sanitizeDOMString } from './index-elneMH8y.js';
12
12
  import { r as renderOptionLabel } from './select-option-render-lIuu64EV.js';
13
13
  import { g as getClassMap } from './theme-byZM6qHV.js';
@@ -296,10 +296,15 @@ const Alert = class {
296
296
  this.triggerChanged();
297
297
  /**
298
298
  * If the alert was previously connected and is being reattached, the
299
- * ResizeObserver was disconnected. componentDidLoad only fires once per
300
- * instance, so re-establish the observer here on reconnect.
299
+ * `ResizeObserver` and the button gesture were torn down. `componentDidLoad`
300
+ * only fires once per instance, so re-establish both here on reconnect.
301
301
  */
302
302
  this.setupButtonGroupResizeObserver();
303
+ this.setupButtonActiveGesture();
304
+ // Re-apply the root lock if moved without dismiss() being called
305
+ if (this.presented) {
306
+ restoreRootFocusTrapAccessibility(this.el);
307
+ }
303
308
  }
304
309
  componentWillLoad() {
305
310
  if (!this.htmlAttributes?.id) {
@@ -321,17 +326,20 @@ const Alert = class {
321
326
  this.buttonGroupResizeObserver?.disconnect();
322
327
  this.buttonGroupResizeObserver = undefined;
323
328
  }
324
- componentDidLoad() {
325
- /**
326
- * Only create gesture if:
327
- * 1. A gesture does not already exist
328
- * 2. App is running in iOS mode
329
- * 3. A wrapper ref exists
330
- */
329
+ /**
330
+ * Only create gesture if:
331
+ * 1. A gesture does not already exist
332
+ * 2. App is running in iOS mode
333
+ * 3. A wrapper ref exists
334
+ */
335
+ setupButtonActiveGesture() {
331
336
  if (!this.gesture && getIonMode(this) === 'ios' && this.wrapperEl) {
332
337
  this.gesture = createButtonActiveGesture(this.wrapperEl, (refEl) => refEl.classList.contains('alert-button'));
333
338
  this.gesture.enable(true);
334
339
  }
340
+ }
341
+ componentDidLoad() {
342
+ this.setupButtonActiveGesture();
335
343
  this.setupButtonGroupResizeObserver();
336
344
  /**
337
345
  * If alert was rendered with isOpen="true"
@@ -654,14 +662,14 @@ const Alert = class {
654
662
  * If neither are defined, do not set aria-labelledby.
655
663
  */
656
664
  const ariaLabelledBy = header && subHeader ? `${hdrId} ${subHdrId}` : header ? hdrId : subHeader ? subHdrId : null;
657
- return (h(Host, { key: '022f3463b8e6c52064b90ec304c524847c3d5ad3', tabindex: "-1", style: {
665
+ return (h(Host, { key: '083b5250dc4c76e85240e0225abcb7ca2b66de2f', tabindex: "-1", style: {
658
666
  zIndex: `${20000 + overlayIndex}`,
659
667
  }, class: {
660
668
  ...getClassMap(this.cssClass),
661
669
  [mode]: true,
662
670
  'overlay-hidden': true,
663
671
  'alert-translucent': this.translucent,
664
- }, onIonAlertWillDismiss: this.dispatchCancelHandler, onIonBackdropTap: this.onBackdropTap }, h("ion-backdrop", { key: 'c3cd05738bc2834f54707edeb2fae06ec10d6fd2', tappable: this.backdropDismiss }), h("div", { key: 'b44fadd9ba7ddf073854c5035538d11ae8e66bc2', tabindex: "0", "aria-hidden": "true" }), h("div", { key: 'fafea048141a6c7957e62aef31faa8041dd610c1', class: "alert-wrapper ion-overlay-wrapper", role: role, "aria-modal": "true", "aria-labelledby": ariaLabelledBy, "aria-describedby": message !== undefined ? msgId : null, tabindex: "0", ref: (el) => (this.wrapperEl = el), ...htmlAttributes }, h("div", { key: '3ad9d2d4b7cf425eab8293ddc12eff0fe8df1517', class: "alert-head" }, header && (h("h2", { key: '7d9154f5ee595b7e4da6ecf3a20871f104c1256e', id: hdrId, class: "alert-title" }, header)), subHeader && !header && (h("h2", { key: '1f891f38004be6964e9406b84dd580145c42516a', id: subHdrId, class: "alert-sub-title" }, subHeader)), subHeader && header && (h("h3", { key: '2ab4d344ecb7e384e8f6d3d3e59ee5a1bbcc832c', id: subHdrId, class: "alert-sub-title" }, subHeader))), this.renderAlertMessage(msgId), this.renderAlertInputs(), this.renderAlertButtons()), h("div", { key: '78a4ff09aa3aaafcd0dc2a42d036767d83b3cfa2', tabindex: "0", "aria-hidden": "true" })));
672
+ }, onIonAlertWillDismiss: this.dispatchCancelHandler, onIonBackdropTap: this.onBackdropTap }, h("ion-backdrop", { key: '65c92a956d998ae9016396dd2a29c42ab7376d0e', tappable: this.backdropDismiss }), h("div", { key: 'f2288fa0b7ef9d0bf031c168fe78c48422cf91c8', tabindex: "0", "aria-hidden": "true" }), h("div", { key: 'dbb109435c378f77c6b0231e58756f8a0467732d', class: "alert-wrapper ion-overlay-wrapper", role: role, "aria-modal": "true", "aria-labelledby": ariaLabelledBy, "aria-describedby": message !== undefined ? msgId : null, tabindex: "0", ref: (el) => (this.wrapperEl = el), ...htmlAttributes }, h("div", { key: '075597f94719673cf1f894a8566e1036849afa75', class: "alert-head" }, header && (h("h2", { key: 'f96f4b1db8473c62040beed6e96108c733978d73', id: hdrId, class: "alert-title" }, header)), subHeader && !header && (h("h2", { key: 'dbd824ef19a07bddde4eb928f11de7c7cadf98b8', id: subHdrId, class: "alert-sub-title" }, subHeader)), subHeader && header && (h("h3", { key: '4774fa13700dd23aec7930492acae80de3bdf5d1', id: subHdrId, class: "alert-sub-title" }, subHeader))), this.renderAlertMessage(msgId), this.renderAlertInputs(), this.renderAlertButtons()), h("div", { key: '5c728b7457e231f64294bbec821bdb547c6437dd', tabindex: "0", "aria-hidden": "true" })));
665
673
  }
666
674
  get el() { return getElement(this); }
667
675
  static get watchers() { return {
@@ -4,7 +4,7 @@
4
4
  import { j as printIonError, f as printIonWarning, r as registerInstance, c as createEvent, w as writeTask, e as config, h, d as Host, g as getElement } from './index-CKYcsw8f.js';
5
5
  import { startFocusVisible } from './focus-visible-BmVRXR1y.js';
6
6
  import { r as raf, g as getElementRoot, a as renderHiddenInput } from './helpers-BIgoInJU.js';
7
- import { F as FOCUS_TRAP_DISABLE_CLASS } from './overlays-BpnIFlXI.js';
7
+ import { F as FOCUS_TRAP_DISABLE_CLASS } from './overlays-CefdMZgF.js';
8
8
  import { i as isRTL } from './dir-Dojwmvde.js';
9
9
  import { c as createColorClasses } from './theme-byZM6qHV.js';
10
10
  import { b as chevronDown, d as caretUpSharp, e as chevronForward, f as caretDownSharp, c as chevronBack } from './index-BvabGprD.js';
@@ -4,7 +4,7 @@
4
4
  import { r as registerInstance, h, d as Host, g as getElement, c as createEvent, f as printIonWarning } from './index-CKYcsw8f.js';
5
5
  import { c as createColorClasses } from './theme-byZM6qHV.js';
6
6
  import { b as getIonMode } from './ionic-global-lrowsHfi.js';
7
- import { o as isEndSide, c as componentOnReady } from './helpers-BIgoInJU.js';
7
+ import { o as isEndSide } from './helpers-BIgoInJU.js';
8
8
  import { a as findClosestIonContent, d as disableContentScrollY, r as resetContentScrollY } from './index-BmOR8tCv.js';
9
9
  import { w as watchForOptions } from './watch-options-Dtdm8lKC.js';
10
10
  import './dir-Dojwmvde.js';
@@ -281,17 +281,19 @@ const ItemSliding = class {
281
281
  }
282
282
  }
283
283
  async updateOptions() {
284
- const options = Array.from(this.el.querySelectorAll('ion-item-options'));
285
- /**
286
- * Frameworks that assign element props after inserting the element haven't set
287
- * `side` while `connectedCallback` runs, so reading it any earlier reports every
288
- * option as `end`.
289
- */
290
- await Promise.all(options.map((option) => new Promise((resolve) => componentOnReady(option, resolve))));
284
+ const options = this.el.querySelectorAll('ion-item-options');
291
285
  let sides = 0;
292
286
  // Reset left and right options in case they were removed
293
287
  this.leftOptions = this.rightOptions = undefined;
294
- for (const option of options) {
288
+ for (let i = 0; i < options.length; i++) {
289
+ const item = options.item(i);
290
+ /**
291
+ * We cannot use the componentOnReady helper
292
+ * util here since we need to wait for all of these items
293
+ * to be ready before we set `this.sides` and `this.optsDirty`.
294
+ */
295
+ // eslint-disable-next-line custom-rules/no-component-on-ready-method
296
+ const option = item.componentOnReady !== undefined ? await item.componentOnReady() : item;
295
297
  const side = isEndSide(option.side ?? option.getAttribute('side')) ? 'end' : 'start';
296
298
  if (side === 'start') {
297
299
  this.leftOptions = option;
@@ -490,7 +492,7 @@ const ItemSliding = class {
490
492
  }
491
493
  render() {
492
494
  const mode = getIonMode(this);
493
- return (h(Host, { key: '02174ca963753d3a51a4249068f3d436f8acb03d', class: {
495
+ return (h(Host, { key: '15f6a98f8c888e86c29827cdf55d98ace08699dd', class: {
494
496
  [mode]: true,
495
497
  'item-sliding-active-slide': this.state !== 2 /* SlidingState.Disabled */,
496
498
  'item-sliding-active-options-end': (this.state & 8 /* SlidingState.End */) !== 0,
@@ -5,7 +5,7 @@ import { r as registerInstance, c as createEvent, e as config, h, d as Host, g a
5
5
  import { E as ENABLE_HTML_CONTENT_DEFAULT } from './config-DWCzVL3Y.js';
6
6
  import { r as raf } from './helpers-BIgoInJU.js';
7
7
  import { c as createLockController } from './lock-controller-B-hirT0v.js';
8
- import { c as createDelegateController, d as createTriggerController, B as BACKDROP, h as prepareOverlay, k as setOverlayId, j as cleanupRootFocusTrapAccessibility, e as present, f as dismiss, g as eventMethod } from './overlays-BpnIFlXI.js';
8
+ import { c as createDelegateController, d as createTriggerController, B as BACKDROP, h as prepareOverlay, r as restoreRootFocusTrapAccessibility, k as setOverlayId, j as cleanupRootFocusTrapAccessibility, e as present, f as dismiss, g as eventMethod } from './overlays-CefdMZgF.js';
9
9
  import { s as sanitizeDOMString } from './index-elneMH8y.js';
10
10
  import { g as getClassMap } from './theme-byZM6qHV.js';
11
11
  import { b as getIonMode } from './ionic-global-lrowsHfi.js';
@@ -181,6 +181,10 @@ const Loading = class {
181
181
  connectedCallback() {
182
182
  prepareOverlay(this.el);
183
183
  this.triggerChanged();
184
+ // Re-apply the root lock if moved without dismiss() being called
185
+ if (this.presented) {
186
+ restoreRootFocusTrapAccessibility(this.el);
187
+ }
184
188
  }
185
189
  componentWillLoad() {
186
190
  if (this.spinner === undefined) {
@@ -281,14 +285,14 @@ const Loading = class {
281
285
  * Otherwise, don't set aria-labelledby.
282
286
  */
283
287
  const ariaLabelledBy = message !== undefined ? msgId : null;
284
- return (h(Host, { key: '2d14122ff3081de73631a7fdd4affdd5c73b8618', role: "dialog", "aria-modal": "true", "aria-labelledby": ariaLabelledBy, tabindex: "-1", ...htmlAttributes, style: {
288
+ return (h(Host, { key: 'b4430bc66aedeca19d5645667cba73c169c4bd76', role: "dialog", "aria-modal": "true", "aria-labelledby": ariaLabelledBy, tabindex: "-1", ...htmlAttributes, style: {
285
289
  zIndex: `${40000 + this.overlayIndex}`,
286
290
  }, onIonBackdropTap: this.onBackdropTap, class: {
287
291
  ...getClassMap(this.cssClass),
288
292
  [mode]: true,
289
293
  'overlay-hidden': true,
290
294
  'loading-translucent': this.translucent,
291
- } }, h("ion-backdrop", { key: 'b7d5bb0d670a20c159d7f67327bf3b1489449188', visible: this.showBackdrop, tappable: this.backdropDismiss }), h("div", { key: '085ce92bd2004d323ab47eb472b83826e48dc619', tabindex: "0", "aria-hidden": "true" }), h("div", { key: '4ecd5bfc0bbd3da434d32f0f319f867a44c5e1f1', class: "loading-wrapper ion-overlay-wrapper" }, spinner && (h("div", { key: '5a4498e1421e09d01c0ee4312eae5272e95c3127', class: "loading-spinner" }, h("ion-spinner", { key: '1b3bc7d45d775195657ead3535f65e6b79f37e84', name: spinner, "aria-hidden": "true" }))), message !== undefined && this.renderLoadingMessage(msgId)), h("div", { key: 'bc7c5467b9f1c6ab957f79934e97acc713bdec37', tabindex: "0", "aria-hidden": "true" })));
295
+ } }, h("ion-backdrop", { key: 'dec0df942ae778c99ebd4dbf08d6c2a0a992639d', visible: this.showBackdrop, tappable: this.backdropDismiss }), h("div", { key: '71b2d5fc259666225047fc901648ada1efcd5d4b', tabindex: "0", "aria-hidden": "true" }), h("div", { key: '1d83dc3b57ee70c9e8c0f006c6fa576bd96ecded', class: "loading-wrapper ion-overlay-wrapper" }, spinner && (h("div", { key: 'd1cd127e044b8831e396b53122322c1db7e89904', class: "loading-spinner" }, h("ion-spinner", { key: '38c2580cf5659da612872f01801a5fbdc2c023ba', name: spinner, "aria-hidden": "true" }))), message !== undefined && this.renderLoadingMessage(msgId)), h("div", { key: '90e5e32ffe0df2c691f364149f43374e676bfaa3', tabindex: "0", "aria-hidden": "true" })));
292
296
  }
293
297
  get el() { return getElement(this); }
294
298
  static get watchers() { return {
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { r as registerInstance, c as createEvent, e as config, j as printIonError, h, d as Host, g as getElement } from './index-CKYcsw8f.js';
5
5
  import { g as getTimeGivenProgression } from './cubic-bezier-hHmYLOfE.js';
6
- import { o as getPresentedOverlay, B as BACKDROP, n as focusFirstDescendant, q as focusLastDescendant, G as GESTURE } from './overlays-BpnIFlXI.js';
6
+ import { o as getPresentedOverlay, B as BACKDROP, n as focusFirstDescendant, q as focusLastDescendant, G as GESTURE } from './overlays-CefdMZgF.js';
7
7
  import { G as GESTURE_CONTROLLER } from './gesture-controller-B_gJaBk0.js';
8
8
  import { shouldUseCloseWatcher } from './hardware-back-button-D8W4L0JP.js';
9
9
  import { o as isEndSide, i as inheritAriaAttributes, l as assert, e as clamp } from './helpers-BIgoInJU.js';
@@ -7,7 +7,7 @@ import { C as CoreDelegate, a as attachComponent, d as detachComponent } from '.
7
7
  import { g as getElementRoot, e as clamp, r as raf, b as inheritAttributes, h as hasLazyBuild } from './helpers-BIgoInJU.js';
8
8
  import { c as createLockController } from './lock-controller-B-hirT0v.js';
9
9
  import { g as getCapacitor } from './capacitor-CFERIeaU.js';
10
- import { G as GESTURE, O as OVERLAY_GESTURE_PRIORITY, F as FOCUS_TRAP_DISABLE_CLASS, d as createTriggerController, B as BACKDROP, h as prepareOverlay, j as cleanupRootFocusTrapAccessibility, k as setOverlayId, e as present, f as dismiss, g as eventMethod } from './overlays-BpnIFlXI.js';
10
+ import { G as GESTURE, O as OVERLAY_GESTURE_PRIORITY, F as FOCUS_TRAP_DISABLE_CLASS, d as createTriggerController, B as BACKDROP, h as prepareOverlay, r as restoreRootFocusTrapAccessibility, j as cleanupRootFocusTrapAccessibility, k as setOverlayId, e as present, f as dismiss, g as eventMethod } from './overlays-CefdMZgF.js';
11
11
  import { g as getClassMap } from './theme-byZM6qHV.js';
12
12
  import { e as deepReady, w as waitForMount } from './index-C8Dsa6li.js';
13
13
  import { b as getIonMode } from './ionic-global-lrowsHfi.js';
@@ -1902,6 +1902,9 @@ const Modal = class {
1902
1902
  this.inline = false;
1903
1903
  // Whether or not modal is being dismissed via gesture
1904
1904
  this.gestureAnimationDismissing = false;
1905
+ // True from the first safe-area write in `present()` until the enter
1906
+ // animation settles. A position-based read in that window is not the rest position.
1907
+ this.isPresenting = false;
1905
1908
  this.presented = false;
1906
1909
  /** @internal */
1907
1910
  this.hasController = false;
@@ -2138,6 +2141,17 @@ const Modal = class {
2138
2141
  const { el } = this;
2139
2142
  prepareOverlay(el);
2140
2143
  this.triggerChanged();
2144
+ // A disconnect tears down state this presentation still needs and cannot
2145
+ // tell a re-insert from a removal, so put it back.
2146
+ if (this.presented || this.isPresenting) {
2147
+ this.restoreSafeAreaOverrides();
2148
+ }
2149
+ // A relocation from `willPresent` reaches these before `present()` has
2150
+ // applied the lock, so they apply it instead. Both are idempotent.
2151
+ if (this.presented) {
2152
+ restoreRootFocusTrapAccessibility(el);
2153
+ this.initParentRemovalObserver();
2154
+ }
2141
2155
  }
2142
2156
  disconnectedCallback() {
2143
2157
  this.triggerController.removeClickListener();
@@ -2315,25 +2329,33 @@ const Modal = class {
2315
2329
  // Recalculate isSheetModal before safe-area setup because framework
2316
2330
  // bindings (e.g., Angular) may not have been applied when componentWillLoad ran.
2317
2331
  this.isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined;
2318
- // Set initial safe-area overrides before animation
2319
- this.setInitialSafeAreaOverrides();
2332
+ this.isPresenting = true;
2320
2333
  const hasCardModal = presentingElement !== undefined;
2321
- /**
2322
- * We need to change the status bar at the
2323
- * start of the animation so that it completes
2324
- * by the time the card animation is done.
2325
- */
2326
- if (hasCardModal && getIonMode(this) === 'ios') {
2327
- // Cache the original status bar color before the modal is presented
2328
- this.statusBarStyle = await StatusBar.getStyle();
2329
- setCardStatusBarDark();
2334
+ // Wrapped so a throw cannot strand `isPresenting`, which would suppress
2335
+ // the position-based correction for the life of this instance.
2336
+ try {
2337
+ // Set initial safe-area overrides before animation
2338
+ this.setInitialSafeAreaOverrides();
2339
+ /**
2340
+ * We need to change the status bar at the
2341
+ * start of the animation so that it completes
2342
+ * by the time the card animation is done.
2343
+ */
2344
+ if (hasCardModal && getIonMode(this) === 'ios') {
2345
+ // Cache the original status bar color before the modal is presented
2346
+ this.statusBarStyle = await StatusBar.getStyle();
2347
+ setCardStatusBarDark();
2348
+ }
2349
+ await present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation, {
2350
+ presentingEl: presentingElement,
2351
+ currentBreakpoint: this.initialBreakpoint,
2352
+ backdropBreakpoint: this.backdropBreakpoint,
2353
+ expandToScroll: this.expandToScroll,
2354
+ });
2355
+ }
2356
+ finally {
2357
+ this.isPresenting = false;
2330
2358
  }
2331
- await present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation, {
2332
- presentingEl: presentingElement,
2333
- currentBreakpoint: this.initialBreakpoint,
2334
- backdropBreakpoint: this.backdropBreakpoint,
2335
- expandToScroll: this.expandToScroll,
2336
- });
2337
2359
  // Update safe-area based on actual position after animation
2338
2360
  this.updateSafeAreaOverrides();
2339
2361
  // Apply fullscreen safe-area padding if needed
@@ -2835,6 +2857,9 @@ const Modal = class {
2835
2857
  this.cachedOriginalParent.tagName === 'ION-APP') {
2836
2858
  return;
2837
2859
  }
2860
+ // Both `present()` and a reconnect call this, so drop any existing
2861
+ // observer. Below the guards, so a call that bails cannot leave none.
2862
+ this.cleanupParentRemovalObserver();
2838
2863
  this.parentRemovalObserver = new MutationObserver((mutations) => {
2839
2864
  mutations.forEach((mutation) => {
2840
2865
  if (mutation.type === 'childList' && mutation.removedNodes.length > 0) {
@@ -2913,6 +2938,9 @@ const Modal = class {
2913
2938
  // Set the internal offset property with the resolved root safe-area-top value
2914
2939
  if (context.isSheetModal) {
2915
2940
  this.updateSheetOffsetTop();
2941
+ // A restore after a DOM move runs this a second time for the same
2942
+ // modal, so drop the previous subscription rather than stacking one.
2943
+ this.unsubscribeRootSafeAreaTop?.();
2916
2944
  this.unsubscribeRootSafeAreaTop = onRootSafeAreaTopChange((safeAreaTop) => this.updateSheetOffsetTop(safeAreaTop));
2917
2945
  }
2918
2946
  }
@@ -3031,6 +3059,31 @@ const Modal = class {
3031
3059
  const { contentEl } = this.findContentAndFooter();
3032
3060
  this.clearContentSafeAreaPadding(contentEl);
3033
3061
  }
3062
+ /**
3063
+ * Re-applies what `cleanupSafeAreaOverrides()` removed for a modal moved
3064
+ * while presented. Anything needing no measurement goes on synchronously so
3065
+ * the modal is never painted without safe-area. The position-based
3066
+ * correction waits a frame for the layout pass it reads.
3067
+ */
3068
+ restoreSafeAreaOverrides() {
3069
+ this.setInitialSafeAreaOverrides();
3070
+ this.applyFullscreenSafeArea();
3071
+ raf(() => {
3072
+ // A dismiss or another move can land first, and a read before the enter
3073
+ // animation settles is not the rest position. `present()` redoes it.
3074
+ if (!this.presented || !this.el.isConnected || this.isPresenting) {
3075
+ return;
3076
+ }
3077
+ // A hidden subtree carries `display: none`, so there is no box and the
3078
+ // read would write the safe-area for a modal touching no edge. The
3079
+ // prediction applied above holds until the modal is shown again.
3080
+ const { width, height } = this.el.getBoundingClientRect();
3081
+ if (width === 0 && height === 0) {
3082
+ return;
3083
+ }
3084
+ this.updateSafeAreaOverrides();
3085
+ });
3086
+ }
3034
3087
  render() {
3035
3088
  const { handle, isSheetModal, presentingElement, htmlAttributes, handleBehavior, inheritedAttributes, focusTrap, expandToScroll, } = this;
3036
3089
  const showHandle = handle !== false && isSheetModal;
@@ -3038,7 +3091,7 @@ const Modal = class {
3038
3091
  const isCardModal = presentingElement !== undefined && mode === 'ios';
3039
3092
  const isHandleCycle = handleBehavior === 'cycle';
3040
3093
  const isSheetModalWithHandle = isSheetModal && showHandle;
3041
- return (h(Host, { key: 'a471c293319cb6ee5ffb7ffafec0b8413e4289de', "no-router": true,
3094
+ return (h(Host, { key: '7c9c736052c5a788cf31040b6b2386dd9ea7454b', "no-router": true,
3042
3095
  // Allow the modal to be navigable when the handle is focusable
3043
3096
  tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1, ...htmlAttributes, style: {
3044
3097
  zIndex: `${20000 + this.overlayIndex}`,
@@ -3051,7 +3104,7 @@ const Modal = class {
3051
3104
  'overlay-hidden': true,
3052
3105
  [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false,
3053
3106
  ...getClassMap(this.cssClass),
3054
- }, onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }, h("ion-backdrop", { key: 'f67934afd4ddad64623856fb641cb6db846df428', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { key: 'a23f5cb6cf60c8f717c1dd556bce375829c80a43', class: "modal-shadow" }), h("div", { key: '51eb6cd1070e4b7e49840a78dc7437238c867a01',
3107
+ }, onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }, h("ion-backdrop", { key: '01b5b5765fb3a32393c736065c824bf760728823', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { key: '40fa7727a0923f7d7461dd027f1511a6a148d84a', class: "modal-shadow" }), h("div", { key: '9af934b607f60795bd5bff7bee6eacfc9b14fa35',
3055
3108
  /*
3056
3109
  role and aria-modal must be used on the
3057
3110
  same element. They must also be set inside the
@@ -3064,9 +3117,9 @@ const Modal = class {
3064
3117
  without the tabindex focus() would be a no-op and screen readers
3065
3118
  may not properly announce the dialog and its content when it opens.
3066
3119
  */
3067
- role: "dialog", ...inheritedAttributes, "aria-modal": "true", tabIndex: -1, class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }, showHandle && (h("button", { key: 'f49a144642b5c227c0c2b00b33f4c7e37a2bf088', class: "modal-handle",
3120
+ role: "dialog", ...inheritedAttributes, "aria-modal": "true", tabIndex: -1, class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }, showHandle && (h("button", { key: 'df84a6806413b13efc5b03c862edde83151579a7', class: "modal-handle",
3068
3121
  // Prevents the handle from receiving keyboard focus when it does not cycle
3069
- tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: 'e781c0d5881762c6b61aa432721a38b49580ff64', onSlotchange: this.onSlotChange }))));
3122
+ tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: '072d3929ec6f25481946b184d8ac24219011e783', onSlotchange: this.onSlotChange }))));
3070
3123
  }
3071
3124
  get el() { return getElement(this); }
3072
3125
  static get watchers() { return {