@ionic/core 7.7.2-nightly.20240208 → 7.7.2-nightly.20240212

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 (88) hide show
  1. package/components/action-sheet.js +7 -3
  2. package/components/alert.js +6 -2
  3. package/components/ion-loading.js +6 -2
  4. package/components/ion-modal.js +7 -3
  5. package/components/ion-picker.js +6 -2
  6. package/components/ion-toast.js +6 -2
  7. package/components/overlays.js +25 -1
  8. package/components/popover.js +6 -2
  9. package/dist/cjs/index.cjs.js +1 -1
  10. package/dist/cjs/ion-action-sheet.cjs.entry.js +8 -4
  11. package/dist/cjs/ion-alert.cjs.entry.js +7 -3
  12. package/dist/cjs/ion-datetime_3.cjs.entry.js +7 -3
  13. package/dist/cjs/ion-loading.cjs.entry.js +7 -3
  14. package/dist/cjs/ion-menu_3.cjs.entry.js +1 -1
  15. package/dist/cjs/ion-modal.cjs.entry.js +8 -4
  16. package/dist/cjs/ion-popover.cjs.entry.js +7 -3
  17. package/dist/cjs/ion-select_3.cjs.entry.js +1 -1
  18. package/dist/cjs/ion-toast.cjs.entry.js +7 -3
  19. package/dist/cjs/{overlays-c0b199e9.js → overlays-853fbc2a.js} +25 -1
  20. package/dist/collection/components/action-sheet/action-sheet.js +9 -5
  21. package/dist/collection/components/alert/alert.js +8 -4
  22. package/dist/collection/components/loading/loading.js +8 -4
  23. package/dist/collection/components/modal/modal.js +9 -5
  24. package/dist/collection/components/picker/picker.js +8 -4
  25. package/dist/collection/components/popover/popover.js +8 -4
  26. package/dist/collection/components/toast/test/toast.spec.js +12 -0
  27. package/dist/collection/components/toast/toast.js +8 -4
  28. package/dist/collection/utils/overlays.js +25 -1
  29. package/dist/collection/utils/test/overlays/overlays.spec.js +51 -0
  30. package/dist/docs.json +22 -22
  31. package/dist/esm/index.js +1 -1
  32. package/dist/esm/ion-action-sheet.entry.js +8 -4
  33. package/dist/esm/ion-alert.entry.js +7 -3
  34. package/dist/esm/ion-datetime_3.entry.js +7 -3
  35. package/dist/esm/ion-loading.entry.js +7 -3
  36. package/dist/esm/ion-menu_3.entry.js +1 -1
  37. package/dist/esm/ion-modal.entry.js +8 -4
  38. package/dist/esm/ion-popover.entry.js +7 -3
  39. package/dist/esm/ion-select_3.entry.js +1 -1
  40. package/dist/esm/ion-toast.entry.js +7 -3
  41. package/dist/esm/{overlays-141e4a0f.js → overlays-f628ea0d.js} +25 -1
  42. package/dist/esm-es5/index.js +1 -1
  43. package/dist/esm-es5/ion-action-sheet.entry.js +1 -1
  44. package/dist/esm-es5/ion-alert.entry.js +1 -1
  45. package/dist/esm-es5/ion-datetime_3.entry.js +1 -1
  46. package/dist/esm-es5/ion-loading.entry.js +1 -1
  47. package/dist/esm-es5/ion-menu_3.entry.js +1 -1
  48. package/dist/esm-es5/ion-modal.entry.js +1 -1
  49. package/dist/esm-es5/ion-popover.entry.js +1 -1
  50. package/dist/esm-es5/ion-select_3.entry.js +1 -1
  51. package/dist/esm-es5/ion-toast.entry.js +1 -1
  52. package/dist/esm-es5/overlays-f628ea0d.js +4 -0
  53. package/dist/ionic/index.esm.js +1 -1
  54. package/dist/ionic/ionic.esm.js +1 -1
  55. package/dist/ionic/{p-09104e40.system.entry.js → p-02228941.system.entry.js} +1 -1
  56. package/dist/ionic/{p-77b5178b.system.entry.js → p-03ef11fd.system.entry.js} +1 -1
  57. package/dist/ionic/p-33c1d796.system.js +1 -1
  58. package/dist/ionic/{p-84074821.entry.js → p-36129d85.entry.js} +1 -1
  59. package/dist/ionic/{p-1e516e45.entry.js → p-379dc0d8.entry.js} +1 -1
  60. package/dist/ionic/{p-f3d6ac85.system.entry.js → p-3996f9d5.system.entry.js} +1 -1
  61. package/dist/ionic/p-554cdfa6.js +4 -0
  62. package/dist/ionic/{p-1c425012.system.entry.js → p-6b5ddd6f.system.entry.js} +2 -2
  63. package/dist/ionic/{p-34c60592.system.entry.js → p-6c03fe3f.system.entry.js} +1 -1
  64. package/dist/ionic/{p-bbfd2cd0.system.entry.js → p-779fb2ab.system.entry.js} +1 -1
  65. package/dist/ionic/{p-6869d193.system.entry.js → p-7b71daed.system.entry.js} +1 -1
  66. package/dist/ionic/{p-c5ae804f.entry.js → p-80c7dd10.entry.js} +1 -1
  67. package/dist/ionic/{p-59b06910.entry.js → p-9e986623.entry.js} +1 -1
  68. package/dist/ionic/{p-7d9f8991.entry.js → p-a06dd73e.entry.js} +1 -1
  69. package/dist/ionic/{p-8942c4f0.entry.js → p-a726c887.entry.js} +1 -1
  70. package/dist/ionic/{p-389a681c.entry.js → p-a9de90a5.entry.js} +1 -1
  71. package/dist/ionic/{p-0c2363a9.system.js → p-b964aaa3.system.js} +1 -1
  72. package/dist/ionic/{p-79ff281e.entry.js → p-c05246a7.entry.js} +1 -1
  73. package/dist/ionic/{p-62ea79fb.system.js → p-c2895673.system.js} +1 -1
  74. package/dist/ionic/{p-10f54620.entry.js → p-c98011a7.entry.js} +1 -1
  75. package/dist/ionic/{p-a29e7420.system.entry.js → p-d51bf7d0.system.entry.js} +1 -1
  76. package/dist/ionic/{p-223b1692.system.entry.js → p-e49bc381.system.entry.js} +1 -1
  77. package/dist/types/components/action-sheet/action-sheet.d.ts +4 -0
  78. package/dist/types/components/alert/alert.d.ts +4 -0
  79. package/dist/types/components/loading/loading.d.ts +4 -0
  80. package/dist/types/components/modal/modal.d.ts +4 -0
  81. package/dist/types/components/picker/picker.d.ts +4 -0
  82. package/dist/types/components/popover/popover.d.ts +4 -0
  83. package/dist/types/components/toast/toast.d.ts +4 -0
  84. package/dist/types/components.d.ts +7 -7
  85. package/hydrate/index.js +69 -17
  86. package/package.json +2 -2
  87. package/dist/esm-es5/overlays-141e4a0f.js +0 -4
  88. package/dist/ionic/p-7888a87b.js +0 -4
@@ -410,6 +410,15 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
410
410
  return;
411
411
  }
412
412
  setRootAriaHidden(true);
413
+ /**
414
+ * Hide all other overlays from screen readers so only this one
415
+ * can be read. Note that presenting an overlay always makes
416
+ * it the topmost one.
417
+ */
418
+ if (index.doc !== undefined) {
419
+ const presentedOverlays = getPresentedOverlays(index.doc);
420
+ presentedOverlays.forEach((o) => o.setAttribute('aria-hidden', 'true'));
421
+ }
413
422
  overlay.presented = true;
414
423
  overlay.willPresent.emit();
415
424
  (_a = overlay.willPresentShorthand) === null || _a === void 0 ? void 0 : _a.emit();
@@ -443,6 +452,14 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
443
452
  if (overlay.keyboardClose && (document.activeElement === null || !overlay.el.contains(document.activeElement))) {
444
453
  overlay.el.focus();
445
454
  }
455
+ /**
456
+ * If this overlay was previously dismissed without being
457
+ * the topmost one (such as by manually calling dismiss()),
458
+ * it would still have aria-hidden on being presented again.
459
+ * Removing it here ensures the overlay is visible to screen
460
+ * readers.
461
+ */
462
+ overlay.el.removeAttribute('aria-hidden');
446
463
  };
447
464
  /**
448
465
  * When an overlay component is dismissed,
@@ -468,7 +485,7 @@ const focusPreviousElementOnDismiss = async (overlayEl) => {
468
485
  previousElement.focus();
469
486
  };
470
487
  const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnimation, opts) => {
471
- var _a, _b;
488
+ var _a, _b, _c;
472
489
  if (!overlay.presented) {
473
490
  return false;
474
491
  }
@@ -519,6 +536,13 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
519
536
  console.error(err);
520
537
  }
521
538
  overlay.el.remove();
539
+ /**
540
+ * If there are other overlays presented, unhide the new
541
+ * topmost one from screen readers.
542
+ */
543
+ if (index.doc !== undefined) {
544
+ (_c = getPresentedOverlay(index.doc)) === null || _c === void 0 ? void 0 : _c.removeAttribute('aria-hidden');
545
+ }
522
546
  return true;
523
547
  };
524
548
  const getAppRoot = (doc) => {
@@ -79,6 +79,10 @@ export class ActionSheet {
79
79
  * This can be useful in a button handler for determining which button was
80
80
  * clicked to dismiss the action sheet.
81
81
  * Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
82
+ *
83
+ * This is a no-op if the overlay has not been presented yet. If you want
84
+ * to remove an overlay from the DOM that was never presented, use the
85
+ * [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
82
86
  */
83
87
  async dismiss(data, role) {
84
88
  const unlock = await this.lockController.lock();
@@ -187,12 +191,12 @@ export class ActionSheet {
187
191
  const cancelButton = allButtons.find((b) => b.role === 'cancel');
188
192
  const buttons = allButtons.filter((b) => b.role !== 'cancel');
189
193
  const headerID = `action-sheet-${overlayIndex}-header`;
190
- return (h(Host, Object.assign({ key: '98851ef73ef85bb1e364111f090480102929a197', role: "dialog", "aria-modal": "true", "aria-labelledby": header !== undefined ? headerID : null, tabindex: "-1" }, htmlAttributes, { style: {
194
+ return (h(Host, Object.assign({ key: 'cd141d12d7d86d3402fd220c4afb61cdbf064c04', role: "dialog", "aria-modal": "true", "aria-labelledby": header !== undefined ? headerID : null, tabindex: "-1" }, htmlAttributes, { style: {
191
195
  zIndex: `${20000 + this.overlayIndex}`,
192
- }, class: Object.assign(Object.assign({ [mode]: true }, getClassMap(this.cssClass)), { 'overlay-hidden': true, 'action-sheet-translucent': this.translucent }), onIonActionSheetWillDismiss: this.dispatchCancelHandler, onIonBackdropTap: this.onBackdropTap }), h("ion-backdrop", { key: 'e2520342ca16aae4dac0bd7bff59b2150aeb2171', tappable: this.backdropDismiss }), h("div", { key: 'c95f2ec4edde1dc3a8860e68b4a86b82f6797aee', tabindex: "0" }), h("div", { key: '7af9edad368e308508801c8ef2225928ced63159', class: "action-sheet-wrapper ion-overlay-wrapper", ref: (el) => (this.wrapperEl = el) }, h("div", { key: 'd1d92b4d1814d34eb7d8134ff77ee260ca521a6d', class: "action-sheet-container" }, h("div", { key: 'cc774b45a9992e95bfee788cb484d99364b76d22', class: "action-sheet-group", ref: (el) => (this.groupEl = el) }, header !== undefined && (h("div", { id: headerID, class: {
196
+ }, class: Object.assign(Object.assign({ [mode]: true }, getClassMap(this.cssClass)), { 'overlay-hidden': true, 'action-sheet-translucent': this.translucent }), onIonActionSheetWillDismiss: this.dispatchCancelHandler, onIonBackdropTap: this.onBackdropTap }), h("ion-backdrop", { key: 'b6a051e2cf5e101edbf59c8a40a04d8f7107fb3c', tappable: this.backdropDismiss }), h("div", { key: '5bfa2b37a417aaff3776f06d92a8544dfcbf714f', tabindex: "0" }), h("div", { key: '77d5a217803fd7be8f8dbedcd0ef5e59f0fd9800', class: "action-sheet-wrapper ion-overlay-wrapper", ref: (el) => (this.wrapperEl = el) }, h("div", { key: '3901d56215f05cdab074e2ec321391281a165097', class: "action-sheet-container" }, h("div", { key: '275f5c7981b2ee44fb632b3d137c7209cbfcf45c', class: "action-sheet-group", ref: (el) => (this.groupEl = el) }, header !== undefined && (h("div", { id: headerID, class: {
193
197
  'action-sheet-title': true,
194
198
  'action-sheet-has-sub-title': this.subHeader !== undefined,
195
- } }, header, this.subHeader && h("div", { class: "action-sheet-sub-title" }, this.subHeader))), buttons.map((b) => (h("button", Object.assign({}, b.htmlAttributes, { type: "button", id: b.id, class: buttonClass(b), onClick: () => this.buttonClick(b) }), h("span", { class: "action-sheet-button-inner" }, b.icon && h("ion-icon", { icon: b.icon, "aria-hidden": "true", lazy: false, class: "action-sheet-icon" }), b.text), mode === 'md' && h("ion-ripple-effect", null))))), cancelButton && (h("div", { class: "action-sheet-group action-sheet-group-cancel" }, h("button", Object.assign({}, cancelButton.htmlAttributes, { type: "button", class: buttonClass(cancelButton), onClick: () => this.buttonClick(cancelButton) }), h("span", { class: "action-sheet-button-inner" }, cancelButton.icon && (h("ion-icon", { icon: cancelButton.icon, "aria-hidden": "true", lazy: false, class: "action-sheet-icon" })), cancelButton.text), mode === 'md' && h("ion-ripple-effect", null)))))), h("div", { key: '9a013adda7dec101cf0c90feb02f5b7f5582a0b3', tabindex: "0" })));
199
+ } }, header, this.subHeader && h("div", { class: "action-sheet-sub-title" }, this.subHeader))), buttons.map((b) => (h("button", Object.assign({}, b.htmlAttributes, { type: "button", id: b.id, class: buttonClass(b), onClick: () => this.buttonClick(b) }), h("span", { class: "action-sheet-button-inner" }, b.icon && h("ion-icon", { icon: b.icon, "aria-hidden": "true", lazy: false, class: "action-sheet-icon" }), b.text), mode === 'md' && h("ion-ripple-effect", null))))), cancelButton && (h("div", { class: "action-sheet-group action-sheet-group-cancel" }, h("button", Object.assign({}, cancelButton.htmlAttributes, { type: "button", class: buttonClass(cancelButton), onClick: () => this.buttonClick(cancelButton) }), h("span", { class: "action-sheet-button-inner" }, cancelButton.icon && (h("ion-icon", { icon: cancelButton.icon, "aria-hidden": "true", lazy: false, class: "action-sheet-icon" })), cancelButton.text), mode === 'md' && h("ion-ripple-effect", null)))))), h("div", { key: '4285893438675be9b40838a93c2ff382a1074cd3', tabindex: "0" })));
196
200
  }
197
201
  static get is() { return "ion-action-sheet"; }
198
202
  static get encapsulation() { return "scoped"; }
@@ -690,7 +694,7 @@ export class ActionSheet {
690
694
  }, {
691
695
  "name": "role",
692
696
  "type": "string | undefined",
693
- "docs": "The role of the element that is dismissing the action sheet.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the action sheet.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`."
697
+ "docs": "The role of the element that is dismissing the action sheet.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the action sheet.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
694
698
  }],
695
699
  "references": {
696
700
  "Promise": {
@@ -707,7 +711,7 @@ export class ActionSheet {
707
711
  "text": "data Any data to emit in the dismiss events."
708
712
  }, {
709
713
  "name": "param",
710
- "text": "role The role of the element that is dismissing the action sheet.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the action sheet.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`."
714
+ "text": "role The role of the element that is dismissing the action sheet.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the action sheet.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
711
715
  }]
712
716
  }
713
717
  },
@@ -220,6 +220,10 @@ export class Alert {
220
220
  * This can be useful in a button handler for determining which button was
221
221
  * clicked to dismiss the alert.
222
222
  * Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
223
+ *
224
+ * This is a no-op if the overlay has not been presented yet. If you want
225
+ * to remove an overlay from the DOM that was never presented, use the
226
+ * [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
223
227
  */
224
228
  async dismiss(data, role) {
225
229
  const unlock = await this.lockController.lock();
@@ -387,9 +391,9 @@ export class Alert {
387
391
  * If neither is defined, don't set aria-labelledby.
388
392
  */
389
393
  const ariaLabelledBy = header ? hdrId : subHeader ? subHdrId : null;
390
- return (h(Host, Object.assign({ key: '8327e1aef6c404c2021d43aaa542d86e839817f5', role: role, "aria-modal": "true", "aria-labelledby": ariaLabelledBy, "aria-describedby": message !== undefined ? msgId : null, tabindex: "-1" }, htmlAttributes, { style: {
394
+ return (h(Host, Object.assign({ key: '4b7f7880dc5f39aa9b61981af0a821ac0350af7f', role: role, "aria-modal": "true", "aria-labelledby": ariaLabelledBy, "aria-describedby": message !== undefined ? msgId : null, tabindex: "-1" }, htmlAttributes, { style: {
391
395
  zIndex: `${20000 + overlayIndex}`,
392
- }, class: Object.assign(Object.assign({}, getClassMap(this.cssClass)), { [mode]: true, 'overlay-hidden': true, 'alert-translucent': this.translucent }), onIonAlertWillDismiss: this.dispatchCancelHandler, onIonBackdropTap: this.onBackdropTap }), h("ion-backdrop", { key: '814a4e1b4f7560026b089b762c68401b6277355e', tappable: this.backdropDismiss }), h("div", { key: 'b31ce08019e7223a098d18cb857f72eddc245e98', tabindex: "0" }), h("div", { key: '77efa4b9f7062f55ba0998a09a24550ec0b9b4f5', class: "alert-wrapper ion-overlay-wrapper", ref: (el) => (this.wrapperEl = el) }, h("div", { key: '648e0768610ee57f9e5c84b8955da497ec9b0b82', class: "alert-head" }, header && (h("h2", { id: hdrId, class: "alert-title" }, header)), subHeader && (h("h2", { id: subHdrId, class: "alert-sub-title" }, subHeader))), this.renderAlertMessage(msgId), this.renderAlertInputs(), this.renderAlertButtons()), h("div", { key: 'f3d752cce77ca021dc959611ad5078b94b7f3cec', tabindex: "0" })));
396
+ }, class: Object.assign(Object.assign({}, getClassMap(this.cssClass)), { [mode]: true, 'overlay-hidden': true, 'alert-translucent': this.translucent }), onIonAlertWillDismiss: this.dispatchCancelHandler, onIonBackdropTap: this.onBackdropTap }), h("ion-backdrop", { key: '961a2684013ac61d59882914fd8d759ddb542fe7', tappable: this.backdropDismiss }), h("div", { key: '2ec08c3719b3cd8a4cae09d2c6ac778ffad5f940', tabindex: "0" }), h("div", { key: 'ee543683d20693c9a9497aca4d41f032aa580c9c', class: "alert-wrapper ion-overlay-wrapper", ref: (el) => (this.wrapperEl = el) }, h("div", { key: '55015102b67d080249a8859fc8788f3a82d5ead9', class: "alert-head" }, header && (h("h2", { id: hdrId, class: "alert-title" }, header)), subHeader && (h("h2", { id: subHdrId, class: "alert-sub-title" }, subHeader))), this.renderAlertMessage(msgId), this.renderAlertInputs(), this.renderAlertButtons()), h("div", { key: 'df7bcfb0cb41965f169de05edd631a050d5ce648', tabindex: "0" })));
393
397
  }
394
398
  static get is() { return "ion-alert"; }
395
399
  static get encapsulation() { return "scoped"; }
@@ -932,7 +936,7 @@ export class Alert {
932
936
  }, {
933
937
  "name": "role",
934
938
  "type": "string | undefined",
935
- "docs": "The role of the element that is dismissing the alert.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the alert.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`."
939
+ "docs": "The role of the element that is dismissing the alert.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the alert.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
936
940
  }],
937
941
  "references": {
938
942
  "Promise": {
@@ -949,7 +953,7 @@ export class Alert {
949
953
  "text": "data Any data to emit in the dismiss events."
950
954
  }, {
951
955
  "name": "param",
952
- "text": "role The role of the element that is dismissing the alert.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the alert.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`."
956
+ "text": "role The role of the element that is dismissing the alert.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the alert.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
953
957
  }]
954
958
  }
955
959
  },
@@ -113,6 +113,10 @@ export class Loading {
113
113
  * This can be useful in a button handler for determining which button was
114
114
  * clicked to dismiss the loading.
115
115
  * Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
116
+ *
117
+ * This is a no-op if the overlay has not been presented yet. If you want
118
+ * to remove an overlay from the DOM that was never presented, use the
119
+ * [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
116
120
  */
117
121
  async dismiss(data, role) {
118
122
  const unlock = await this.lockController.lock();
@@ -154,9 +158,9 @@ export class Loading {
154
158
  * Otherwise, don't set aria-labelledby.
155
159
  */
156
160
  const ariaLabelledBy = message !== undefined ? msgId : null;
157
- return (h(Host, Object.assign({ key: '81295894ca6e047124918420f2483c092ebf91b9', role: "dialog", "aria-modal": "true", "aria-labelledby": ariaLabelledBy, tabindex: "-1" }, htmlAttributes, { style: {
161
+ return (h(Host, Object.assign({ key: '95123f54ba1db5e59563d79db075315b43ed20f7', role: "dialog", "aria-modal": "true", "aria-labelledby": ariaLabelledBy, tabindex: "-1" }, htmlAttributes, { style: {
158
162
  zIndex: `${40000 + this.overlayIndex}`,
159
- }, onIonBackdropTap: this.onBackdropTap, class: Object.assign(Object.assign({}, getClassMap(this.cssClass)), { [mode]: true, 'overlay-hidden': true, 'loading-translucent': this.translucent }) }), h("ion-backdrop", { key: 'db9fbd946cf3eb03c3a70f2e71c49ab233df1879', visible: this.showBackdrop, tappable: this.backdropDismiss }), h("div", { key: 'd27b03de0b450c0668d4b4077d76bc5b283f03cf', tabindex: "0" }), h("div", { key: '7112719ddd487365c1e36fc4dec32aac888dbb52', class: "loading-wrapper ion-overlay-wrapper" }, spinner && (h("div", { class: "loading-spinner" }, h("ion-spinner", { name: spinner, "aria-hidden": "true" }))), message !== undefined && this.renderLoadingMessage(msgId)), h("div", { key: '5715dd7dae209ae58e5557cb60f3ae514752b822', tabindex: "0" })));
163
+ }, onIonBackdropTap: this.onBackdropTap, class: Object.assign(Object.assign({}, getClassMap(this.cssClass)), { [mode]: true, 'overlay-hidden': true, 'loading-translucent': this.translucent }) }), h("ion-backdrop", { key: 'e113bf123eaad38f2dafce8ea5d2ebef409d0c0f', visible: this.showBackdrop, tappable: this.backdropDismiss }), h("div", { key: '1268c9480854383c7883a79d597350540ade93c2', tabindex: "0" }), h("div", { key: 'e86fc71504ebd578117dea2232d9740a087d1249', class: "loading-wrapper ion-overlay-wrapper" }, spinner && (h("div", { class: "loading-spinner" }, h("ion-spinner", { name: spinner, "aria-hidden": "true" }))), message !== undefined && this.renderLoadingMessage(msgId)), h("div", { key: '3b91e2492e06aa65ebe77ed2b6ffb9d2f84bdd9c', tabindex: "0" })));
160
164
  }
161
165
  static get is() { return "ion-loading"; }
162
166
  static get encapsulation() { return "scoped"; }
@@ -680,7 +684,7 @@ export class Loading {
680
684
  }, {
681
685
  "name": "role",
682
686
  "type": "string | undefined",
683
- "docs": "The role of the element that is dismissing the loading.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the loading.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`."
687
+ "docs": "The role of the element that is dismissing the loading.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the loading.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
684
688
  }],
685
689
  "references": {
686
690
  "Promise": {
@@ -697,7 +701,7 @@ export class Loading {
697
701
  "text": "data Any data to emit in the dismiss events."
698
702
  }, {
699
703
  "name": "param",
700
- "text": "role The role of the element that is dismissing the loading.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the loading.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`."
704
+ "text": "role The role of the element that is dismissing the loading.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the loading.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
701
705
  }]
702
706
  }
703
707
  },
@@ -396,6 +396,10 @@ export class Modal {
396
396
  *
397
397
  * @param data Any data to emit in the dismiss events.
398
398
  * @param role The role of the element that is dismissing the modal. For example, 'cancel' or 'backdrop'.
399
+ *
400
+ * This is a no-op if the overlay has not been presented yet. If you want
401
+ * to remove an overlay from the DOM that was never presented, use the
402
+ * [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
399
403
  */
400
404
  async dismiss(data, role) {
401
405
  var _a;
@@ -526,9 +530,9 @@ export class Modal {
526
530
  const mode = getIonMode(this);
527
531
  const isCardModal = presentingElement !== undefined && mode === 'ios';
528
532
  const isHandleCycle = handleBehavior === 'cycle';
529
- return (h(Host, Object.assign({ key: '9a305d82f123283b6200c42d67393b378bb309a8', "no-router": true, tabindex: "-1" }, htmlAttributes, { style: {
533
+ return (h(Host, Object.assign({ key: '0c2c4369ab2df4ef4660addea5e927c6a0232864', "no-router": true, tabindex: "-1" }, htmlAttributes, { style: {
530
534
  zIndex: `${20000 + this.overlayIndex}`,
531
- }, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, 'overlay-hidden': true }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle }), h("ion-backdrop", { key: '85e8dc6f19b30fd95db518445929fb0c1d5cdef0', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { class: "modal-shadow" }), h("div", Object.assign({ key: '893a0202d91828e60099311442c2677bee5464e2',
535
+ }, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, 'overlay-hidden': true }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle }), h("ion-backdrop", { key: 'd044383a776c2ee1703f996caedaedca47f2948f', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { class: "modal-shadow" }), h("div", Object.assign({ key: '8d23b6a3cc9069e4d46fa0645cde9db3e6f89507',
532
536
  /*
533
537
  role and aria-modal must be used on the
534
538
  same element. They must also be set inside the
@@ -537,7 +541,7 @@ export class Modal {
537
541
  */
538
542
  role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { class: "modal-handle",
539
543
  // Prevents the handle from receiving keyboard focus when it does not cycle
540
- tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle" })), h("slot", { key: '25187bf4c69d9022930227b8b8748a294176be5f' }))));
544
+ tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle" })), h("slot", { key: '3fbb689e4bf5575fbb26ad1000f6ac5993f3bf8f' }))));
541
545
  }
542
546
  static get is() { return "ion-modal"; }
543
547
  static get encapsulation() { return "shadow"; }
@@ -1232,7 +1236,7 @@ export class Modal {
1232
1236
  }, {
1233
1237
  "name": "role",
1234
1238
  "type": "string | undefined",
1235
- "docs": "The role of the element that is dismissing the modal. For example, 'cancel' or 'backdrop'."
1239
+ "docs": "The role of the element that is dismissing the modal. For example, 'cancel' or 'backdrop'.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
1236
1240
  }],
1237
1241
  "references": {
1238
1242
  "Promise": {
@@ -1253,7 +1257,7 @@ export class Modal {
1253
1257
  "text": "data Any data to emit in the dismiss events."
1254
1258
  }, {
1255
1259
  "name": "param",
1256
- "text": "role The role of the element that is dismissing the modal. For example, 'cancel' or 'backdrop'."
1260
+ "text": "role The role of the element that is dismissing the modal. For example, 'cancel' or 'backdrop'.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
1257
1261
  }]
1258
1262
  }
1259
1263
  },
@@ -109,6 +109,10 @@ export class Picker {
109
109
  * This can be useful in a button handler for determining which button was
110
110
  * clicked to dismiss the picker.
111
111
  * Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
112
+ *
113
+ * This is a no-op if the overlay has not been presented yet. If you want
114
+ * to remove an overlay from the DOM that was never presented, use the
115
+ * [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
112
116
  */
113
117
  async dismiss(data, role) {
114
118
  const unlock = await this.lockController.lock();
@@ -180,11 +184,11 @@ export class Picker {
180
184
  render() {
181
185
  const { htmlAttributes } = this;
182
186
  const mode = getIonMode(this);
183
- return (h(Host, Object.assign({ key: '8b9049c5315e701dff3f7457be646941bb3cc0df', "aria-modal": "true", tabindex: "-1" }, htmlAttributes, { style: {
187
+ return (h(Host, Object.assign({ key: 'c266cc072afaba2da22f70d8b62dc4bc6756d188', "aria-modal": "true", tabindex: "-1" }, htmlAttributes, { style: {
184
188
  zIndex: `${20000 + this.overlayIndex}`,
185
189
  }, class: Object.assign({ [mode]: true,
186
190
  // Used internally for styling
187
- [`picker-${mode}`]: true, 'overlay-hidden': true }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonPickerWillDismiss: this.dispatchCancelHandler }), h("ion-backdrop", { key: '4f62ae6c088108189bfab18b680f0ae50b4cc395', visible: this.showBackdrop, tappable: this.backdropDismiss }), h("div", { key: 'c5fd2584ca4470c69bf61582cef2ac72289addba', tabindex: "0" }), h("div", { key: '2e68572dd5ddc4911c1e6bca57a2157b47477348', class: "picker-wrapper ion-overlay-wrapper", role: "dialog" }, h("div", { key: '218526e531998a4d5a6377499acb42f99b347729', class: "picker-toolbar" }, this.buttons.map((b) => (h("div", { class: buttonWrapperClass(b) }, h("button", { type: "button", onClick: () => this.buttonClick(b), class: buttonClass(b) }, b.text))))), h("div", { key: '4dd711f1fa1f2a4bd24696ae1633da16bbf55879', class: "picker-columns" }, h("div", { key: '440ebd807ca3675b0055e67e0354ac4625ae375d', class: "picker-above-highlight" }), this.presented && this.columns.map((c) => h("ion-picker-column", { col: c })), h("div", { key: '5cdceda410904470e3742ab416ed3d3a661b6859', class: "picker-below-highlight" }))), h("div", { key: '0c96e8a43a6d4cd4b8b7c9e81c54414eb1d989bf', tabindex: "0" })));
191
+ [`picker-${mode}`]: true, 'overlay-hidden': true }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonPickerWillDismiss: this.dispatchCancelHandler }), h("ion-backdrop", { key: '35ee3e5028028835580e28ac2c8db65a924d5d6a', visible: this.showBackdrop, tappable: this.backdropDismiss }), h("div", { key: '8b454e6edbcfc45c57d3d8baf7c14b7905921a6e', tabindex: "0" }), h("div", { key: 'e0fee78ec6d097bf0963190f748e5daad602e0f7', class: "picker-wrapper ion-overlay-wrapper", role: "dialog" }, h("div", { key: 'ce66bca18fc3e982ad7d6660f27cb1a03fb8247b', class: "picker-toolbar" }, this.buttons.map((b) => (h("div", { class: buttonWrapperClass(b) }, h("button", { type: "button", onClick: () => this.buttonClick(b), class: buttonClass(b) }, b.text))))), h("div", { key: 'a58b9523fe16f109dd6de0610717c5077fed964b', class: "picker-columns" }, h("div", { key: 'acd54c0314cff51e8513a08dd9755c4b847c0617', class: "picker-above-highlight" }), this.presented && this.columns.map((c) => h("ion-picker-column", { col: c })), h("div", { key: '604730bd87582d048d850c6e0a0f29ba33258918', class: "picker-below-highlight" }))), h("div", { key: '93baf5e6e57aec5f084d7d5b24af14e7d8126b5a', tabindex: "0" })));
188
192
  }
189
193
  static get is() { return "ion-picker"; }
190
194
  static get encapsulation() { return "scoped"; }
@@ -693,7 +697,7 @@ export class Picker {
693
697
  }, {
694
698
  "name": "role",
695
699
  "type": "string | undefined",
696
- "docs": "The role of the element that is dismissing the picker.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the picker.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`."
700
+ "docs": "The role of the element that is dismissing the picker.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the picker.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
697
701
  }],
698
702
  "references": {
699
703
  "Promise": {
@@ -710,7 +714,7 @@ export class Picker {
710
714
  "text": "data Any data to emit in the dismiss events."
711
715
  }, {
712
716
  "name": "param",
713
- "text": "role The role of the element that is dismissing the picker.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the picker.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`."
717
+ "text": "role The role of the element that is dismissing the picker.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the picker.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
714
718
  }]
715
719
  }
716
720
  },
@@ -280,6 +280,10 @@ export class Popover {
280
280
  * @param role The role of the element that is dismissing the popover. For example, 'cancel' or 'backdrop'.
281
281
  * @param dismissParentPopover If `true`, dismissing this popover will also dismiss
282
282
  * a parent popover if this popover is nested. Defaults to `true`.
283
+ *
284
+ * This is a no-op if the overlay has not been presented yet. If you want
285
+ * to remove an overlay from the DOM that was never presented, use the
286
+ * [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
283
287
  */
284
288
  async dismiss(data, role, dismissParentPopover = true) {
285
289
  const unlock = await this.lockController.lock();
@@ -331,9 +335,9 @@ export class Popover {
331
335
  const { onLifecycle, parentPopover, dismissOnSelect, side, arrow, htmlAttributes } = this;
332
336
  const desktop = isPlatform('desktop');
333
337
  const enableArrow = arrow && !parentPopover;
334
- return (h(Host, Object.assign({ key: 'f335ae001173483e6a973b2084f8a7b6b895ae5d', "aria-modal": "true", "no-router": true, tabindex: "-1" }, htmlAttributes, { style: {
338
+ return (h(Host, Object.assign({ key: '104a5bf92a9bbd2efc71d499a8500e5d55f81711', "aria-modal": "true", "no-router": true, tabindex: "-1" }, htmlAttributes, { style: {
335
339
  zIndex: `${20000 + this.overlayIndex}`,
336
- }, class: Object.assign(Object.assign({}, getClassMap(this.cssClass)), { [mode]: true, 'popover-translucent': this.translucent, 'overlay-hidden': true, 'popover-desktop': desktop, [`popover-side-${side}`]: true, 'popover-nested': !!parentPopover }), onIonPopoverDidPresent: onLifecycle, onIonPopoverWillPresent: onLifecycle, onIonPopoverWillDismiss: onLifecycle, onIonPopoverDidDismiss: onLifecycle, onIonBackdropTap: this.onBackdropTap }), !parentPopover && h("ion-backdrop", { tappable: this.backdropDismiss, visible: this.showBackdrop, part: "backdrop" }), h("div", { key: '8468f39b0a0f30b42ae9cac51950e5f0b9be1069', class: "popover-wrapper ion-overlay-wrapper", onClick: dismissOnSelect ? () => this.dismiss() : undefined }, enableArrow && h("div", { class: "popover-arrow", part: "arrow" }), h("div", { key: 'cb4eeaef385187f3c8e566931844e30edd5451c4', class: "popover-content", part: "content" }, h("slot", { key: '80a5739a4beb6eba150503e426104701954c90b9' })))));
340
+ }, class: Object.assign(Object.assign({}, getClassMap(this.cssClass)), { [mode]: true, 'popover-translucent': this.translucent, 'overlay-hidden': true, 'popover-desktop': desktop, [`popover-side-${side}`]: true, 'popover-nested': !!parentPopover }), onIonPopoverDidPresent: onLifecycle, onIonPopoverWillPresent: onLifecycle, onIonPopoverWillDismiss: onLifecycle, onIonPopoverDidDismiss: onLifecycle, onIonBackdropTap: this.onBackdropTap }), !parentPopover && h("ion-backdrop", { tappable: this.backdropDismiss, visible: this.showBackdrop, part: "backdrop" }), h("div", { key: 'ef0baa04c22444d4bc705220235a892308d67586', class: "popover-wrapper ion-overlay-wrapper", onClick: dismissOnSelect ? () => this.dismiss() : undefined }, enableArrow && h("div", { class: "popover-arrow", part: "arrow" }), h("div", { key: '5cc5f5c353de614e484e9cfeacecfca9fbfde0e0', class: "popover-content", part: "content" }, h("slot", { key: '2d85c591cdc85efa98afbf40f676525f1402efcf' })))));
337
341
  }
338
342
  static get is() { return "ion-popover"; }
339
343
  static get encapsulation() { return "shadow"; }
@@ -1130,7 +1134,7 @@ export class Popover {
1130
1134
  }, {
1131
1135
  "name": "dismissParentPopover",
1132
1136
  "type": "boolean",
1133
- "docs": "If `true`, dismissing this popover will also dismiss\na parent popover if this popover is nested. Defaults to `true`."
1137
+ "docs": "If `true`, dismissing this popover will also dismiss\na parent popover if this popover is nested. Defaults to `true`.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
1134
1138
  }],
1135
1139
  "references": {
1136
1140
  "Promise": {
@@ -1154,7 +1158,7 @@ export class Popover {
1154
1158
  "text": "role The role of the element that is dismissing the popover. For example, 'cancel' or 'backdrop'."
1155
1159
  }, {
1156
1160
  "name": "param",
1157
- "text": "dismissParentPopover If `true`, dismissing this popover will also dismiss\na parent popover if this popover is nested. Defaults to `true`."
1161
+ "text": "dismissParentPopover If `true`, dismissing this popover will also dismiss\na parent popover if this popover is nested. Defaults to `true`.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
1158
1162
  }]
1159
1163
  }
1160
1164
  },
@@ -80,6 +80,18 @@ describe('toast: a11y smoke test', () => {
80
80
  });
81
81
  });
82
82
  describe('toast: duration config', () => {
83
+ afterEach(() => {
84
+ /**
85
+ * Important: Reset the config
86
+ * after each test as it is not
87
+ * automatically reset.
88
+ * Otherwise, toasts in other tests
89
+ * will take on any toastDuration value
90
+ * set and timeouts will potentially run
91
+ * after tests are finished.
92
+ */
93
+ config.reset({});
94
+ });
83
95
  it('should have duration set to 0', async () => {
84
96
  const page = await newSpecPage({
85
97
  components: [Toast],
@@ -217,6 +217,10 @@ export class Toast {
217
217
  * This can be useful in a button handler for determining which button was
218
218
  * clicked to dismiss the toast.
219
219
  * Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
220
+ *
221
+ * This is a no-op if the overlay has not been presented yet. If you want
222
+ * to remove an overlay from the DOM that was never presented, use the
223
+ * [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
220
224
  */
221
225
  async dismiss(data, role) {
222
226
  var _a, _b;
@@ -384,9 +388,9 @@ export class Toast {
384
388
  if (layout === 'stacked' && startButtons.length > 0 && endButtons.length > 0) {
385
389
  printIonWarning('This toast is using start and end buttons with the stacked toast layout. We recommend following the best practice of using either start or end buttons with the stacked toast layout.', el);
386
390
  }
387
- return (h(Host, Object.assign({ key: '15a5c3e8d475435c838b70c55ef2e7cc12d6abfb', tabindex: "-1" }, this.htmlAttributes, { style: {
391
+ return (h(Host, Object.assign({ key: 'c8d7e7d2baa01d3ed5d65a845bc61acf087c0b18', tabindex: "-1" }, this.htmlAttributes, { style: {
388
392
  zIndex: `${60000 + this.overlayIndex}`,
389
- }, class: createColorClasses(this.color, Object.assign(Object.assign({ [mode]: true }, getClassMap(this.cssClass)), { 'overlay-hidden': true, 'toast-translucent': this.translucent })), onIonToastWillDismiss: this.dispatchCancelHandler }), h("div", { key: 'a6ed7fb75ab098dc632d1a546b4d5298675c14c1', class: wrapperClass }, h("div", { key: '68ff7219e9abae0b7c2030369ebffd2fe0edf7de', class: "toast-container", part: "container" }, this.renderButtons(startButtons, 'start'), this.icon !== undefined && (h("ion-icon", { class: "toast-icon", part: "icon", icon: this.icon, lazy: false, "aria-hidden": "true" })), h("div", { key: '6b45ca5e283d3507c682cbe733e27a94460a7f69', class: "toast-content", role: "status", "aria-atomic": "true", "aria-live": "polite" }, !revealContentToScreenReader && header !== undefined && this.renderHeader('oldHeader', 'true'), !revealContentToScreenReader && message !== undefined && this.renderToastMessage('oldMessage', 'true'), revealContentToScreenReader && header !== undefined && this.renderHeader('header'), revealContentToScreenReader && message !== undefined && this.renderToastMessage('header')), this.renderButtons(endButtons, 'end')))));
393
+ }, class: createColorClasses(this.color, Object.assign(Object.assign({ [mode]: true }, getClassMap(this.cssClass)), { 'overlay-hidden': true, 'toast-translucent': this.translucent })), onIonToastWillDismiss: this.dispatchCancelHandler }), h("div", { key: '27c0feeb89c4efb47c42623a4b036ed84338ed10', class: wrapperClass }, h("div", { key: '41d5a3069f92e4a6acef2793fa4e236cdbdaae88', class: "toast-container", part: "container" }, this.renderButtons(startButtons, 'start'), this.icon !== undefined && (h("ion-icon", { class: "toast-icon", part: "icon", icon: this.icon, lazy: false, "aria-hidden": "true" })), h("div", { key: '176f497bc990ef2ecc14c7fa90dd3a54a912030a', class: "toast-content", role: "status", "aria-atomic": "true", "aria-live": "polite" }, !revealContentToScreenReader && header !== undefined && this.renderHeader('oldHeader', 'true'), !revealContentToScreenReader && message !== undefined && this.renderToastMessage('oldMessage', 'true'), revealContentToScreenReader && header !== undefined && this.renderHeader('header'), revealContentToScreenReader && message !== undefined && this.renderToastMessage('header')), this.renderButtons(endButtons, 'end')))));
390
394
  }
391
395
  static get is() { return "ion-toast"; }
392
396
  static get encapsulation() { return "shadow"; }
@@ -1032,7 +1036,7 @@ export class Toast {
1032
1036
  }, {
1033
1037
  "name": "role",
1034
1038
  "type": "string | undefined",
1035
- "docs": "The role of the element that is dismissing the toast.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the toast.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`."
1039
+ "docs": "The role of the element that is dismissing the toast.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the toast.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
1036
1040
  }],
1037
1041
  "references": {
1038
1042
  "Promise": {
@@ -1054,7 +1058,7 @@ export class Toast {
1054
1058
  "text": "data Any data to emit in the dismiss events."
1055
1059
  }, {
1056
1060
  "name": "param",
1057
- "text": "role The role of the element that is dismissing the toast.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the toast.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`."
1061
+ "text": "role The role of the element that is dismissing the toast.\nThis can be useful in a button handler for determining which button was\nclicked to dismiss the toast.\nSome examples include: ``\"cancel\"`, `\"destructive\"`, \"selected\"`, and `\"backdrop\"`.\n\nThis is a no-op if the overlay has not been presented yet. If you want\nto remove an overlay from the DOM that was never presented, use the\n[remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method."
1058
1062
  }]
1059
1063
  }
1060
1064
  },
@@ -409,6 +409,15 @@ export const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation
409
409
  return;
410
410
  }
411
411
  setRootAriaHidden(true);
412
+ /**
413
+ * Hide all other overlays from screen readers so only this one
414
+ * can be read. Note that presenting an overlay always makes
415
+ * it the topmost one.
416
+ */
417
+ if (doc !== undefined) {
418
+ const presentedOverlays = getPresentedOverlays(doc);
419
+ presentedOverlays.forEach((o) => o.setAttribute('aria-hidden', 'true'));
420
+ }
412
421
  overlay.presented = true;
413
422
  overlay.willPresent.emit();
414
423
  (_a = overlay.willPresentShorthand) === null || _a === void 0 ? void 0 : _a.emit();
@@ -442,6 +451,14 @@ export const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation
442
451
  if (overlay.keyboardClose && (document.activeElement === null || !overlay.el.contains(document.activeElement))) {
443
452
  overlay.el.focus();
444
453
  }
454
+ /**
455
+ * If this overlay was previously dismissed without being
456
+ * the topmost one (such as by manually calling dismiss()),
457
+ * it would still have aria-hidden on being presented again.
458
+ * Removing it here ensures the overlay is visible to screen
459
+ * readers.
460
+ */
461
+ overlay.el.removeAttribute('aria-hidden');
445
462
  };
446
463
  /**
447
464
  * When an overlay component is dismissed,
@@ -467,7 +484,7 @@ const focusPreviousElementOnDismiss = async (overlayEl) => {
467
484
  previousElement.focus();
468
485
  };
469
486
  export const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnimation, opts) => {
470
- var _a, _b;
487
+ var _a, _b, _c;
471
488
  if (!overlay.presented) {
472
489
  return false;
473
490
  }
@@ -518,6 +535,13 @@ export const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLe
518
535
  console.error(err);
519
536
  }
520
537
  overlay.el.remove();
538
+ /**
539
+ * If there are other overlays presented, unhide the new
540
+ * topmost one from screen readers.
541
+ */
542
+ if (doc !== undefined) {
543
+ (_c = getPresentedOverlay(doc)) === null || _c === void 0 ? void 0 : _c.removeAttribute('aria-hidden');
544
+ }
521
545
  return true;
522
546
  };
523
547
  const getAppRoot = (doc) => {
@@ -100,3 +100,54 @@ describe('setRootAriaHidden()', () => {
100
100
  expect(routerOutlet.hasAttribute('aria-hidden')).toEqual(false);
101
101
  });
102
102
  });
103
+ describe('aria-hidden on individual overlays', () => {
104
+ it('should hide non-topmost overlays from screen readers', async () => {
105
+ const page = await newSpecPage({
106
+ components: [Modal],
107
+ html: `
108
+ <ion-modal id="one"></ion-modal>
109
+ <ion-modal id="two"></ion-modal>
110
+ `,
111
+ });
112
+ const modalOne = page.body.querySelector('ion-modal#one');
113
+ const modalTwo = page.body.querySelector('ion-modal#two');
114
+ await modalOne.present();
115
+ await modalTwo.present();
116
+ expect(modalOne.hasAttribute('aria-hidden')).toEqual(true);
117
+ expect(modalTwo.hasAttribute('aria-hidden')).toEqual(false);
118
+ });
119
+ it('should unhide new topmost overlay from screen readers when topmost is dismissed', async () => {
120
+ const page = await newSpecPage({
121
+ components: [Modal],
122
+ html: `
123
+ <ion-modal id="one"></ion-modal>
124
+ <ion-modal id="two"></ion-modal>
125
+ `,
126
+ });
127
+ const modalOne = page.body.querySelector('ion-modal#one');
128
+ const modalTwo = page.body.querySelector('ion-modal#two');
129
+ await modalOne.present();
130
+ await modalTwo.present();
131
+ // dismiss modalTwo so that modalOne becomes the new topmost overlay
132
+ await modalTwo.dismiss();
133
+ expect(modalOne.hasAttribute('aria-hidden')).toEqual(false);
134
+ });
135
+ it('should not keep overlays hidden from screen readers if presented after being dismissed while non-topmost', async () => {
136
+ const page = await newSpecPage({
137
+ components: [Modal],
138
+ html: `
139
+ <ion-modal id="one"></ion-modal>
140
+ <ion-modal id="two"></ion-modal>
141
+ `,
142
+ });
143
+ const modalOne = page.body.querySelector('ion-modal#one');
144
+ const modalTwo = page.body.querySelector('ion-modal#two');
145
+ await modalOne.present();
146
+ await modalTwo.present();
147
+ // modalOne is not the topmost overlay at this point and is hidden from screen readers
148
+ await modalOne.dismiss();
149
+ // modalOne will become the topmost overlay; ensure it isn't still hidden from screen readers
150
+ await modalOne.present();
151
+ expect(modalOne.hasAttribute('aria-hidden')).toEqual(false);
152
+ });
153
+ });